xref: /titanic_50/usr/src/lib/libipsecutil/common/algs.c (revision 7c478bd95313f5f23a4c958a745db2134aa03244)
1*7c478bd9Sstevel@tonic-gate /*
2*7c478bd9Sstevel@tonic-gate  * CDDL HEADER START
3*7c478bd9Sstevel@tonic-gate  *
4*7c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*7c478bd9Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
6*7c478bd9Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
7*7c478bd9Sstevel@tonic-gate  * with the License.
8*7c478bd9Sstevel@tonic-gate  *
9*7c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*7c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
11*7c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
12*7c478bd9Sstevel@tonic-gate  * and limitations under the License.
13*7c478bd9Sstevel@tonic-gate  *
14*7c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
15*7c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*7c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
17*7c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
18*7c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
19*7c478bd9Sstevel@tonic-gate  *
20*7c478bd9Sstevel@tonic-gate  * CDDL HEADER END
21*7c478bd9Sstevel@tonic-gate  */
22*7c478bd9Sstevel@tonic-gate /*
23*7c478bd9Sstevel@tonic-gate  * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
24*7c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
25*7c478bd9Sstevel@tonic-gate  */
26*7c478bd9Sstevel@tonic-gate 
27*7c478bd9Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
28*7c478bd9Sstevel@tonic-gate 
29*7c478bd9Sstevel@tonic-gate #include <sys/types.h>
30*7c478bd9Sstevel@tonic-gate #include <sys/stat.h>
31*7c478bd9Sstevel@tonic-gate #include <ipsec_util.h>
32*7c478bd9Sstevel@tonic-gate #include <stdlib.h>
33*7c478bd9Sstevel@tonic-gate #include <strings.h>
34*7c478bd9Sstevel@tonic-gate #include <netdb.h>
35*7c478bd9Sstevel@tonic-gate #include <fcntl.h>
36*7c478bd9Sstevel@tonic-gate #include <unistd.h>
37*7c478bd9Sstevel@tonic-gate #include <libintl.h>
38*7c478bd9Sstevel@tonic-gate #include <errno.h>
39*7c478bd9Sstevel@tonic-gate 
40*7c478bd9Sstevel@tonic-gate static char *preamble =
41*7c478bd9Sstevel@tonic-gate "# /etc/inet/ipsecalgs output from ipsecalgs(1m)\n"
42*7c478bd9Sstevel@tonic-gate "#\n"
43*7c478bd9Sstevel@tonic-gate "# DO NOT EDIT OR PARSE THIS FILE!\n"
44*7c478bd9Sstevel@tonic-gate "#\n"
45*7c478bd9Sstevel@tonic-gate "# Use the ipsecalgs(1m) command to change the contents of this file.\n"
46*7c478bd9Sstevel@tonic-gate "\n";
47*7c478bd9Sstevel@tonic-gate 
48*7c478bd9Sstevel@tonic-gate #define	CFG_PERMS S_IRUSR | S_IRGRP | S_IROTH	/* Perms 0444. */
49*7c478bd9Sstevel@tonic-gate #define	CFG_OWNER 0	/* root */
50*7c478bd9Sstevel@tonic-gate #define	CFG_GROUP 1	/* "other" */
51*7c478bd9Sstevel@tonic-gate 
52*7c478bd9Sstevel@tonic-gate /*
53*7c478bd9Sstevel@tonic-gate  * write_new_algfile() helper macros to check for write errors.
54*7c478bd9Sstevel@tonic-gate  */
55*7c478bd9Sstevel@tonic-gate 
56*7c478bd9Sstevel@tonic-gate #define	FPRINTF_ERR(fcall) if ((fcall) < 0) {	\
57*7c478bd9Sstevel@tonic-gate 	rc = LIBIPSEC_ALGS_DIAG_ALGSFILEWRITE;	\
58*7c478bd9Sstevel@tonic-gate 	goto bail;				\
59*7c478bd9Sstevel@tonic-gate }
60*7c478bd9Sstevel@tonic-gate 
61*7c478bd9Sstevel@tonic-gate #define	FPUT_ERR(fcall) if ((fcall) == EOF) {	\
62*7c478bd9Sstevel@tonic-gate 	rc = LIBIPSEC_ALGS_DIAG_ALGSFILEWRITE;	\
63*7c478bd9Sstevel@tonic-gate 	goto bail;				\
64*7c478bd9Sstevel@tonic-gate }
65*7c478bd9Sstevel@tonic-gate 
66*7c478bd9Sstevel@tonic-gate /*
67*7c478bd9Sstevel@tonic-gate  * Helper macros to start and finish a list of entries that were added
68*7c478bd9Sstevel@tonic-gate  * as part of a package installation.
69*7c478bd9Sstevel@tonic-gate  */
70*7c478bd9Sstevel@tonic-gate 
71*7c478bd9Sstevel@tonic-gate #define	PKG_SEC_START(pkgname, doing_pkg, cur_pkg) {		\
72*7c478bd9Sstevel@tonic-gate 	(void) strcpy((cur_pkg), (pkgname));			\
73*7c478bd9Sstevel@tonic-gate 	FPRINTF_ERR(fprintf(f, "%s%s\n",			\
74*7c478bd9Sstevel@tonic-gate 	    LIBIPSEC_ALGS_LINE_PKGSTART, (cur_pkg)));		\
75*7c478bd9Sstevel@tonic-gate 	(doing_pkg) = B_TRUE;					\
76*7c478bd9Sstevel@tonic-gate }
77*7c478bd9Sstevel@tonic-gate 
78*7c478bd9Sstevel@tonic-gate #define	PKG_SEC_END(doing_pkg, cur_pkg) {			\
79*7c478bd9Sstevel@tonic-gate 	if (doing_pkg) {					\
80*7c478bd9Sstevel@tonic-gate 		FPRINTF_ERR(fprintf(f, "%s%s\n",		\
81*7c478bd9Sstevel@tonic-gate 		    LIBIPSEC_ALGS_LINE_PKGEND, (cur_pkg)));	\
82*7c478bd9Sstevel@tonic-gate 		(doing_pkg) = B_FALSE;				\
83*7c478bd9Sstevel@tonic-gate 	}							\
84*7c478bd9Sstevel@tonic-gate }
85*7c478bd9Sstevel@tonic-gate 
86*7c478bd9Sstevel@tonic-gate /*
87*7c478bd9Sstevel@tonic-gate  * Take a zero-terminated int array and print int1,int2...,intN.
88*7c478bd9Sstevel@tonic-gate  * If zero-only, then print a single '0'.
89*7c478bd9Sstevel@tonic-gate  * Returns 0 on success, -1 if an error occurred while writing to
90*7c478bd9Sstevel@tonic-gate  * the specified file.
91*7c478bd9Sstevel@tonic-gate  */
92*7c478bd9Sstevel@tonic-gate int
93*7c478bd9Sstevel@tonic-gate list_ints(FILE *f, int *floater)
94*7c478bd9Sstevel@tonic-gate {
95*7c478bd9Sstevel@tonic-gate 	boolean_t executed = B_FALSE;
96*7c478bd9Sstevel@tonic-gate 
97*7c478bd9Sstevel@tonic-gate 	while (*floater != 0) {
98*7c478bd9Sstevel@tonic-gate 		executed = B_TRUE;
99*7c478bd9Sstevel@tonic-gate 		if (fprintf(f, "%d", *floater) < 0)
100*7c478bd9Sstevel@tonic-gate 			return (-1);
101*7c478bd9Sstevel@tonic-gate 		if (*(++floater) != 0)
102*7c478bd9Sstevel@tonic-gate 			if (fputc(',', f) == EOF)
103*7c478bd9Sstevel@tonic-gate 				return (-1);
104*7c478bd9Sstevel@tonic-gate 	}
105*7c478bd9Sstevel@tonic-gate 
106*7c478bd9Sstevel@tonic-gate 	if (!executed)
107*7c478bd9Sstevel@tonic-gate 		if (fputc('0', f) == EOF)
108*7c478bd9Sstevel@tonic-gate 			return (-1);
109*7c478bd9Sstevel@tonic-gate 
110*7c478bd9Sstevel@tonic-gate 	return (0);
111*7c478bd9Sstevel@tonic-gate }
112*7c478bd9Sstevel@tonic-gate 
113*7c478bd9Sstevel@tonic-gate /*
114*7c478bd9Sstevel@tonic-gate  * If the specified algorithm was defined within a package section, i.e.
115*7c478bd9Sstevel@tonic-gate  * between the lines "# Start <pkgname>" and "# End <pkgname>", returns
116*7c478bd9Sstevel@tonic-gate  * the value of <pkgname>.
117*7c478bd9Sstevel@tonic-gate  */
118*7c478bd9Sstevel@tonic-gate static char *
119*7c478bd9Sstevel@tonic-gate alg_has_pkg(ipsec_proto_t *proto, struct ipsecalgent *alg)
120*7c478bd9Sstevel@tonic-gate {
121*7c478bd9Sstevel@tonic-gate 	int i;
122*7c478bd9Sstevel@tonic-gate 
123*7c478bd9Sstevel@tonic-gate 	if (proto->proto_algs_pkgs == NULL)
124*7c478bd9Sstevel@tonic-gate 		return (NULL);
125*7c478bd9Sstevel@tonic-gate 
126*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < proto->proto_algs_npkgs; i++)
127*7c478bd9Sstevel@tonic-gate 		if (proto->proto_algs_pkgs[i].alg_num == alg->a_alg_num)
128*7c478bd9Sstevel@tonic-gate 			return (proto->proto_algs_pkgs[i].pkg_name);
129*7c478bd9Sstevel@tonic-gate 
130*7c478bd9Sstevel@tonic-gate 	return (NULL);
131*7c478bd9Sstevel@tonic-gate }
132*7c478bd9Sstevel@tonic-gate 
133*7c478bd9Sstevel@tonic-gate /*
134*7c478bd9Sstevel@tonic-gate  * Writes the package start/end delimiters according to the package
135*7c478bd9Sstevel@tonic-gate  * name associated with the current protocol or algorithm, and
136*7c478bd9Sstevel@tonic-gate  * the state of the packaging information already written to the file.
137*7c478bd9Sstevel@tonic-gate  * Called by write_new_algfile(). Returns 0 on success, one of the
138*7c478bd9Sstevel@tonic-gate  * LIBIPSEC_DIAG codes on failure.
139*7c478bd9Sstevel@tonic-gate  */
140*7c478bd9Sstevel@tonic-gate static int
141*7c478bd9Sstevel@tonic-gate pkg_section(FILE *f, char *pkg_name, boolean_t *doing_pkg, char *cur_pkg)
142*7c478bd9Sstevel@tonic-gate {
143*7c478bd9Sstevel@tonic-gate 	int rc = 0;
144*7c478bd9Sstevel@tonic-gate 
145*7c478bd9Sstevel@tonic-gate 	if (pkg_name != NULL) {
146*7c478bd9Sstevel@tonic-gate 		/* protocol or algorithm is associated with a package */
147*7c478bd9Sstevel@tonic-gate 		if (!*doing_pkg) {
148*7c478bd9Sstevel@tonic-gate 			/* start of a new package section */
149*7c478bd9Sstevel@tonic-gate 			PKG_SEC_START(pkg_name, *doing_pkg, cur_pkg);
150*7c478bd9Sstevel@tonic-gate 		} else {
151*7c478bd9Sstevel@tonic-gate 			/* already in a package section */
152*7c478bd9Sstevel@tonic-gate 			if (strcmp(pkg_name, cur_pkg) != 0) {
153*7c478bd9Sstevel@tonic-gate 				/* different package name */
154*7c478bd9Sstevel@tonic-gate 				PKG_SEC_END(*doing_pkg, cur_pkg);
155*7c478bd9Sstevel@tonic-gate 				PKG_SEC_START(pkg_name, *doing_pkg, cur_pkg);
156*7c478bd9Sstevel@tonic-gate 			}
157*7c478bd9Sstevel@tonic-gate 		}
158*7c478bd9Sstevel@tonic-gate 	} else if (*doing_pkg) {
159*7c478bd9Sstevel@tonic-gate 		/* in a package section when the entry isn't */
160*7c478bd9Sstevel@tonic-gate 		PKG_SEC_END(*doing_pkg, cur_pkg);
161*7c478bd9Sstevel@tonic-gate 	}
162*7c478bd9Sstevel@tonic-gate bail:
163*7c478bd9Sstevel@tonic-gate 	return (rc);
164*7c478bd9Sstevel@tonic-gate }
165*7c478bd9Sstevel@tonic-gate 
166*7c478bd9Sstevel@tonic-gate /*
167*7c478bd9Sstevel@tonic-gate  * Given a list of protocols and number, write them to a new algorithm file.
168*7c478bd9Sstevel@tonic-gate  * This function takes num_protos + num_protos * dois-per-alg operations.
169*7c478bd9Sstevel@tonic-gate  * Also free the protocol structure.
170*7c478bd9Sstevel@tonic-gate  *
171*7c478bd9Sstevel@tonic-gate  * Note that no locking spans the read/update/write phases that can be
172*7c478bd9Sstevel@tonic-gate  * used by callers of this routine. This could cause this function to suffer
173*7c478bd9Sstevel@tonic-gate  * from the "lost update" problem. Since updates to the IPsec protocols
174*7c478bd9Sstevel@tonic-gate  * and algorithm tables are very infrequent, this should not be a issue in
175*7c478bd9Sstevel@tonic-gate  * practice.
176*7c478bd9Sstevel@tonic-gate  */
177*7c478bd9Sstevel@tonic-gate static int
178*7c478bd9Sstevel@tonic-gate write_new_algfile(ipsec_proto_t *protos, int num_protos)
179*7c478bd9Sstevel@tonic-gate {
180*7c478bd9Sstevel@tonic-gate 	FILE *f;
181*7c478bd9Sstevel@tonic-gate 	int fd, i, j, k;
182*7c478bd9Sstevel@tonic-gate 	int rc = 0;
183*7c478bd9Sstevel@tonic-gate 	struct ipsecalgent *alg;
184*7c478bd9Sstevel@tonic-gate 	char cur_pkg[1024];
185*7c478bd9Sstevel@tonic-gate 	boolean_t doing_pkg = B_FALSE;
186*7c478bd9Sstevel@tonic-gate 	char *alg_pkg;
187*7c478bd9Sstevel@tonic-gate 	char *tmp_name_template = INET_IPSECALGSPATH "ipsecalgsXXXXXX";
188*7c478bd9Sstevel@tonic-gate 	char *tmp_name;
189*7c478bd9Sstevel@tonic-gate 
190*7c478bd9Sstevel@tonic-gate 	/*
191*7c478bd9Sstevel@tonic-gate 	 * In order to avoid potentially corrupting the configuration
192*7c478bd9Sstevel@tonic-gate 	 * file on file system failure, write the new configuration info
193*7c478bd9Sstevel@tonic-gate 	 * to a temporary file which is then renamed to the configuration
194*7c478bd9Sstevel@tonic-gate 	 * file (INET_IPSECALGSFILE.)
195*7c478bd9Sstevel@tonic-gate 	 */
196*7c478bd9Sstevel@tonic-gate 	tmp_name = mktemp(tmp_name_template);
197*7c478bd9Sstevel@tonic-gate 
198*7c478bd9Sstevel@tonic-gate 	fd = open(tmp_name, O_WRONLY|O_CREAT|O_EXCL, CFG_PERMS);
199*7c478bd9Sstevel@tonic-gate 	if (fd == -1) {
200*7c478bd9Sstevel@tonic-gate 		rc = LIBIPSEC_ALGS_DIAG_ALGSFILEOPEN;
201*7c478bd9Sstevel@tonic-gate 		goto bail;
202*7c478bd9Sstevel@tonic-gate 	}
203*7c478bd9Sstevel@tonic-gate 
204*7c478bd9Sstevel@tonic-gate 	f = fdopen(fd, "w");
205*7c478bd9Sstevel@tonic-gate 	if (f == NULL) {
206*7c478bd9Sstevel@tonic-gate 		(void) close(fd);
207*7c478bd9Sstevel@tonic-gate 		rc = LIBIPSEC_ALGS_DIAG_ALGSFILEFDOPEN;
208*7c478bd9Sstevel@tonic-gate 		goto bail;
209*7c478bd9Sstevel@tonic-gate 	}
210*7c478bd9Sstevel@tonic-gate 
211*7c478bd9Sstevel@tonic-gate 	FPUT_ERR(fputs(preamble, f));
212*7c478bd9Sstevel@tonic-gate 
213*7c478bd9Sstevel@tonic-gate 	/* Write protocol entries. */
214*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < num_protos; i++) {
215*7c478bd9Sstevel@tonic-gate 
216*7c478bd9Sstevel@tonic-gate 		/* add package section delimiters if needed */
217*7c478bd9Sstevel@tonic-gate 		rc = pkg_section(f, protos[i].proto_pkg, &doing_pkg, cur_pkg);
218*7c478bd9Sstevel@tonic-gate 		if (rc != 0)
219*7c478bd9Sstevel@tonic-gate 			goto bail;
220*7c478bd9Sstevel@tonic-gate 
221*7c478bd9Sstevel@tonic-gate 		FPRINTF_ERR(fprintf(f, "%s%d|%s|",
222*7c478bd9Sstevel@tonic-gate 		    LIBIPSEC_ALGS_LINE_PROTO,
223*7c478bd9Sstevel@tonic-gate 		    protos[i].proto_num, protos[i].proto_name));
224*7c478bd9Sstevel@tonic-gate 		switch (protos[i].proto_exec_mode) {
225*7c478bd9Sstevel@tonic-gate 		case LIBIPSEC_ALGS_EXEC_SYNC:
226*7c478bd9Sstevel@tonic-gate 			FPRINTF_ERR(fprintf(f, "sync\n"));
227*7c478bd9Sstevel@tonic-gate 			break;
228*7c478bd9Sstevel@tonic-gate 		case LIBIPSEC_ALGS_EXEC_ASYNC:
229*7c478bd9Sstevel@tonic-gate 			FPRINTF_ERR(fprintf(f, "async\n"));
230*7c478bd9Sstevel@tonic-gate 			break;
231*7c478bd9Sstevel@tonic-gate 		}
232*7c478bd9Sstevel@tonic-gate 	}
233*7c478bd9Sstevel@tonic-gate 
234*7c478bd9Sstevel@tonic-gate 	/* terminate the package section for the protocols if needed */
235*7c478bd9Sstevel@tonic-gate 	PKG_SEC_END(doing_pkg, cur_pkg);
236*7c478bd9Sstevel@tonic-gate 
237*7c478bd9Sstevel@tonic-gate 	FPUT_ERR(fputs("\n", f));
238*7c478bd9Sstevel@tonic-gate 
239*7c478bd9Sstevel@tonic-gate 	/* Write algorithm entries. */
240*7c478bd9Sstevel@tonic-gate 
241*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < num_protos; i++) {
242*7c478bd9Sstevel@tonic-gate 		for (j = 0; j < protos[i].proto_numalgs; j++) {
243*7c478bd9Sstevel@tonic-gate 			alg = protos[i].proto_algs[j];
244*7c478bd9Sstevel@tonic-gate 
245*7c478bd9Sstevel@tonic-gate 			/* add package section delimiters if needed */
246*7c478bd9Sstevel@tonic-gate 			alg_pkg = alg_has_pkg(&protos[i], alg);
247*7c478bd9Sstevel@tonic-gate 			rc = pkg_section(f, alg_pkg, &doing_pkg, cur_pkg);
248*7c478bd9Sstevel@tonic-gate 			if (rc != 0)
249*7c478bd9Sstevel@tonic-gate 				goto bail;
250*7c478bd9Sstevel@tonic-gate 
251*7c478bd9Sstevel@tonic-gate 			/* protocol and algorithm numbers */
252*7c478bd9Sstevel@tonic-gate 			FPRINTF_ERR(fprintf(f, "%s%d|%d|",
253*7c478bd9Sstevel@tonic-gate 			    LIBIPSEC_ALGS_LINE_ALG,
254*7c478bd9Sstevel@tonic-gate 			    alg->a_proto_num, alg->a_alg_num));
255*7c478bd9Sstevel@tonic-gate 
256*7c478bd9Sstevel@tonic-gate 			/* algorithm names */
257*7c478bd9Sstevel@tonic-gate 			for (k = 0; alg->a_names[k] != NULL; k++) {
258*7c478bd9Sstevel@tonic-gate 				FPRINTF_ERR(fprintf(f, "%s", alg->a_names[k]));
259*7c478bd9Sstevel@tonic-gate 				if (alg->a_names[k+1] != NULL)
260*7c478bd9Sstevel@tonic-gate 					FPRINTF_ERR(fprintf(f, ","));
261*7c478bd9Sstevel@tonic-gate 			}
262*7c478bd9Sstevel@tonic-gate 
263*7c478bd9Sstevel@tonic-gate 			/* mechanism name */
264*7c478bd9Sstevel@tonic-gate 			FPRINTF_ERR(fprintf(f, "|%s|", alg->a_mech_name));
265*7c478bd9Sstevel@tonic-gate 
266*7c478bd9Sstevel@tonic-gate 			/* key sizes */
267*7c478bd9Sstevel@tonic-gate 			if (alg->a_key_increment == 0) {
268*7c478bd9Sstevel@tonic-gate 				/* key sizes defined by enumeration */
269*7c478bd9Sstevel@tonic-gate 				if (list_ints(f, alg->a_key_sizes) == -1) {
270*7c478bd9Sstevel@tonic-gate 					rc = LIBIPSEC_ALGS_DIAG_ALGSFILEWRITE;
271*7c478bd9Sstevel@tonic-gate 					goto bail;
272*7c478bd9Sstevel@tonic-gate 				}
273*7c478bd9Sstevel@tonic-gate 			} else {
274*7c478bd9Sstevel@tonic-gate 				/* key sizes defined by range */
275*7c478bd9Sstevel@tonic-gate 				FPRINTF_ERR(fprintf(f, "%d/%d-%d,%d",
276*7c478bd9Sstevel@tonic-gate 				    alg->a_key_sizes[0], alg->a_key_sizes[1],
277*7c478bd9Sstevel@tonic-gate 				    alg->a_key_sizes[2], alg->a_key_increment));
278*7c478bd9Sstevel@tonic-gate 			}
279*7c478bd9Sstevel@tonic-gate 			FPUT_ERR(fputc('|', f));
280*7c478bd9Sstevel@tonic-gate 
281*7c478bd9Sstevel@tonic-gate 			/* block sizes */
282*7c478bd9Sstevel@tonic-gate 			if (list_ints(f, alg->a_block_sizes) == -1) {
283*7c478bd9Sstevel@tonic-gate 				rc = LIBIPSEC_ALGS_DIAG_ALGSFILEWRITE;
284*7c478bd9Sstevel@tonic-gate 				goto bail;
285*7c478bd9Sstevel@tonic-gate 			}
286*7c478bd9Sstevel@tonic-gate 			FPUT_ERR(fputc('\n', f));
287*7c478bd9Sstevel@tonic-gate 		}
288*7c478bd9Sstevel@tonic-gate 	}
289*7c478bd9Sstevel@tonic-gate 
290*7c478bd9Sstevel@tonic-gate 	/* terminate the package section for the algorithms if needed */
291*7c478bd9Sstevel@tonic-gate 	PKG_SEC_END(doing_pkg, cur_pkg);
292*7c478bd9Sstevel@tonic-gate 
293*7c478bd9Sstevel@tonic-gate 	if (fchmod(fd, CFG_PERMS) == -1) {
294*7c478bd9Sstevel@tonic-gate 		rc = LIBIPSEC_ALGS_DIAG_ALGSFILECHMOD;
295*7c478bd9Sstevel@tonic-gate 		goto bail;
296*7c478bd9Sstevel@tonic-gate 	}
297*7c478bd9Sstevel@tonic-gate 	if (fchown(fd, CFG_OWNER, CFG_GROUP) == -1) {
298*7c478bd9Sstevel@tonic-gate 		rc = LIBIPSEC_ALGS_DIAG_ALGSFILECHOWN;
299*7c478bd9Sstevel@tonic-gate 		goto bail;
300*7c478bd9Sstevel@tonic-gate 	}
301*7c478bd9Sstevel@tonic-gate 	if (fclose(f) == EOF) {
302*7c478bd9Sstevel@tonic-gate 		rc = LIBIPSEC_ALGS_DIAG_ALGSFILECLOSE;
303*7c478bd9Sstevel@tonic-gate 		goto bail;
304*7c478bd9Sstevel@tonic-gate 	}
305*7c478bd9Sstevel@tonic-gate 
306*7c478bd9Sstevel@tonic-gate 	if (rename(tmp_name, INET_IPSECALGSFILE) == -1)
307*7c478bd9Sstevel@tonic-gate 		rc = LIBIPSEC_ALGS_DIAG_ALGSFILERENAME;
308*7c478bd9Sstevel@tonic-gate 
309*7c478bd9Sstevel@tonic-gate bail:
310*7c478bd9Sstevel@tonic-gate 	_clean_trash(protos, num_protos);
311*7c478bd9Sstevel@tonic-gate 	return (rc);
312*7c478bd9Sstevel@tonic-gate }
313*7c478bd9Sstevel@tonic-gate 
314*7c478bd9Sstevel@tonic-gate /*
315*7c478bd9Sstevel@tonic-gate  * Return a pointer to the protocol entry corresponding to the specified
316*7c478bd9Sstevel@tonic-gate  * protocol num proto_num. Also builds the list of currently defined
317*7c478bd9Sstevel@tonic-gate  * protocols.
318*7c478bd9Sstevel@tonic-gate  */
319*7c478bd9Sstevel@tonic-gate static ipsec_proto_t *
320*7c478bd9Sstevel@tonic-gate proto_setup(ipsec_proto_t **protos, int *num_protos, int proto_num,
321*7c478bd9Sstevel@tonic-gate     boolean_t cleanup)
322*7c478bd9Sstevel@tonic-gate {
323*7c478bd9Sstevel@tonic-gate 	int i;
324*7c478bd9Sstevel@tonic-gate 	ipsec_proto_t *current_proto, *ret_proto = NULL;
325*7c478bd9Sstevel@tonic-gate 
326*7c478bd9Sstevel@tonic-gate 	_build_internal_algs(protos, num_protos);
327*7c478bd9Sstevel@tonic-gate 
328*7c478bd9Sstevel@tonic-gate 	if (*protos == NULL)
329*7c478bd9Sstevel@tonic-gate 		return (NULL);
330*7c478bd9Sstevel@tonic-gate 
331*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < *num_protos; i++) {
332*7c478bd9Sstevel@tonic-gate 		current_proto = (*protos) + i;
333*7c478bd9Sstevel@tonic-gate 		if (current_proto->proto_num == proto_num) {
334*7c478bd9Sstevel@tonic-gate 			ret_proto = current_proto;
335*7c478bd9Sstevel@tonic-gate 			break;
336*7c478bd9Sstevel@tonic-gate 		}
337*7c478bd9Sstevel@tonic-gate 	}
338*7c478bd9Sstevel@tonic-gate 
339*7c478bd9Sstevel@tonic-gate 	if (ret_proto == NULL) {
340*7c478bd9Sstevel@tonic-gate 		if (cleanup)
341*7c478bd9Sstevel@tonic-gate 			_clean_trash(*protos, *num_protos);
342*7c478bd9Sstevel@tonic-gate 		/* else caller wants parsed /etc/inet/ipsecalgs anyway */
343*7c478bd9Sstevel@tonic-gate 	}
344*7c478bd9Sstevel@tonic-gate 
345*7c478bd9Sstevel@tonic-gate 	return (ret_proto);
346*7c478bd9Sstevel@tonic-gate }
347*7c478bd9Sstevel@tonic-gate 
348*7c478bd9Sstevel@tonic-gate /*
349*7c478bd9Sstevel@tonic-gate  * Delete the first found algorithm of the specified protocol which
350*7c478bd9Sstevel@tonic-gate  * has the same name as the one specified by alg_name. Deletion of
351*7c478bd9Sstevel@tonic-gate  * the entry takes place only if the delete_it flag is set. If an
352*7c478bd9Sstevel@tonic-gate  * entry was found, return B_TRUE, otherwise return B_FALSE.
353*7c478bd9Sstevel@tonic-gate  */
354*7c478bd9Sstevel@tonic-gate static boolean_t
355*7c478bd9Sstevel@tonic-gate delipsecalgbyname_common(const char *name, ipsec_proto_t *proto,
356*7c478bd9Sstevel@tonic-gate     boolean_t delete_it)
357*7c478bd9Sstevel@tonic-gate {
358*7c478bd9Sstevel@tonic-gate 	int i;
359*7c478bd9Sstevel@tonic-gate 	char **name_check;
360*7c478bd9Sstevel@tonic-gate 	boolean_t found_match = B_FALSE;
361*7c478bd9Sstevel@tonic-gate 
362*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < proto->proto_numalgs; i++) {
363*7c478bd9Sstevel@tonic-gate 		if (!found_match) {
364*7c478bd9Sstevel@tonic-gate 			for (name_check =
365*7c478bd9Sstevel@tonic-gate 			    proto->proto_algs[i]->a_names;
366*7c478bd9Sstevel@tonic-gate 			    *name_check != NULL; name_check++) {
367*7c478bd9Sstevel@tonic-gate 				/*
368*7c478bd9Sstevel@tonic-gate 				 * Can use strcmp because the algorithm names
369*7c478bd9Sstevel@tonic-gate 				 * are bound.
370*7c478bd9Sstevel@tonic-gate 				 */
371*7c478bd9Sstevel@tonic-gate 				if (strcmp(*name_check, name) == 0) {
372*7c478bd9Sstevel@tonic-gate 					found_match = B_TRUE;
373*7c478bd9Sstevel@tonic-gate 					if (!delete_it)
374*7c478bd9Sstevel@tonic-gate 						return (found_match);
375*7c478bd9Sstevel@tonic-gate 					freeipsecalgent(proto->proto_algs[i]);
376*7c478bd9Sstevel@tonic-gate 					break;
377*7c478bd9Sstevel@tonic-gate 				}
378*7c478bd9Sstevel@tonic-gate 			}
379*7c478bd9Sstevel@tonic-gate 		} else {
380*7c478bd9Sstevel@tonic-gate 			proto->proto_algs[i - 1] = proto->proto_algs[i];
381*7c478bd9Sstevel@tonic-gate 		}
382*7c478bd9Sstevel@tonic-gate 	}
383*7c478bd9Sstevel@tonic-gate 
384*7c478bd9Sstevel@tonic-gate 	if (found_match)
385*7c478bd9Sstevel@tonic-gate 		proto->proto_numalgs--;
386*7c478bd9Sstevel@tonic-gate 
387*7c478bd9Sstevel@tonic-gate 	return (found_match);
388*7c478bd9Sstevel@tonic-gate }
389*7c478bd9Sstevel@tonic-gate 
390*7c478bd9Sstevel@tonic-gate /*
391*7c478bd9Sstevel@tonic-gate  * Returns B_TRUE if the specified 0-terminated lists of key or
392*7c478bd9Sstevel@tonic-gate  * block sizes match, B_FALSE otherwise.
393*7c478bd9Sstevel@tonic-gate  */
394*7c478bd9Sstevel@tonic-gate static boolean_t
395*7c478bd9Sstevel@tonic-gate sizes_match(int *a1, int *a2)
396*7c478bd9Sstevel@tonic-gate {
397*7c478bd9Sstevel@tonic-gate 	int i;
398*7c478bd9Sstevel@tonic-gate 
399*7c478bd9Sstevel@tonic-gate 	for (i = 0; (a1[i] != 0) && (a2[i] != 0); i++) {
400*7c478bd9Sstevel@tonic-gate 		if (a1[i] != a2[i])
401*7c478bd9Sstevel@tonic-gate 			return (B_FALSE);
402*7c478bd9Sstevel@tonic-gate 	}
403*7c478bd9Sstevel@tonic-gate 	if ((a1[i] != 0) || (a2[i] != 0))
404*7c478bd9Sstevel@tonic-gate 		return (B_FALSE);
405*7c478bd9Sstevel@tonic-gate 
406*7c478bd9Sstevel@tonic-gate 	return (B_TRUE);
407*7c478bd9Sstevel@tonic-gate }
408*7c478bd9Sstevel@tonic-gate 
409*7c478bd9Sstevel@tonic-gate /*
410*7c478bd9Sstevel@tonic-gate  * Returns B_TRUE if an _exact_ equivalent of the specified algorithm
411*7c478bd9Sstevel@tonic-gate  * already exists, B_FALSE otherwise.
412*7c478bd9Sstevel@tonic-gate  */
413*7c478bd9Sstevel@tonic-gate static boolean_t
414*7c478bd9Sstevel@tonic-gate ipsecalg_exists(struct ipsecalgent *newbie, ipsec_proto_t *proto)
415*7c478bd9Sstevel@tonic-gate {
416*7c478bd9Sstevel@tonic-gate 	struct ipsecalgent *curalg;
417*7c478bd9Sstevel@tonic-gate 	char **curname, **newbiename;
418*7c478bd9Sstevel@tonic-gate 	int i;
419*7c478bd9Sstevel@tonic-gate 	boolean_t match;
420*7c478bd9Sstevel@tonic-gate 
421*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < proto->proto_numalgs; i++) {
422*7c478bd9Sstevel@tonic-gate 		curalg = proto->proto_algs[i];
423*7c478bd9Sstevel@tonic-gate 
424*7c478bd9Sstevel@tonic-gate 		if (curalg->a_alg_num != newbie->a_alg_num)
425*7c478bd9Sstevel@tonic-gate 			continue;
426*7c478bd9Sstevel@tonic-gate 
427*7c478bd9Sstevel@tonic-gate 		if (curalg->a_key_increment != newbie->a_key_increment)
428*7c478bd9Sstevel@tonic-gate 			continue;
429*7c478bd9Sstevel@tonic-gate 
430*7c478bd9Sstevel@tonic-gate 		if (strcmp(curalg->a_mech_name, newbie->a_mech_name) != 0)
431*7c478bd9Sstevel@tonic-gate 			continue;
432*7c478bd9Sstevel@tonic-gate 
433*7c478bd9Sstevel@tonic-gate 		curname = curalg->a_names;
434*7c478bd9Sstevel@tonic-gate 		newbiename = newbie->a_names;
435*7c478bd9Sstevel@tonic-gate 		match = B_TRUE;
436*7c478bd9Sstevel@tonic-gate 		while ((*curname != NULL) && (*newbiename != NULL) && match) {
437*7c478bd9Sstevel@tonic-gate 			match = (strcmp(*curname, *newbiename) == 0);
438*7c478bd9Sstevel@tonic-gate 			curname++;
439*7c478bd9Sstevel@tonic-gate 			newbiename++;
440*7c478bd9Sstevel@tonic-gate 		}
441*7c478bd9Sstevel@tonic-gate 		if (!match || (*curname != NULL) || (*newbiename != NULL))
442*7c478bd9Sstevel@tonic-gate 			continue;
443*7c478bd9Sstevel@tonic-gate 
444*7c478bd9Sstevel@tonic-gate 		if (!sizes_match(curalg->a_block_sizes, newbie->a_block_sizes))
445*7c478bd9Sstevel@tonic-gate 			continue;
446*7c478bd9Sstevel@tonic-gate 
447*7c478bd9Sstevel@tonic-gate 		if (!sizes_match(curalg->a_key_sizes, newbie->a_key_sizes))
448*7c478bd9Sstevel@tonic-gate 			continue;
449*7c478bd9Sstevel@tonic-gate 
450*7c478bd9Sstevel@tonic-gate 		/* we found an exact match */
451*7c478bd9Sstevel@tonic-gate 		return (B_TRUE);
452*7c478bd9Sstevel@tonic-gate 	}
453*7c478bd9Sstevel@tonic-gate 
454*7c478bd9Sstevel@tonic-gate 	return (B_FALSE);
455*7c478bd9Sstevel@tonic-gate }
456*7c478bd9Sstevel@tonic-gate 
457*7c478bd9Sstevel@tonic-gate /*
458*7c478bd9Sstevel@tonic-gate  * Add a new algorithm to the /etc/inet/ipsecalgs file.  Caller must free
459*7c478bd9Sstevel@tonic-gate  * or otherwise address "newbie".
460*7c478bd9Sstevel@tonic-gate  */
461*7c478bd9Sstevel@tonic-gate int
462*7c478bd9Sstevel@tonic-gate addipsecalg(struct ipsecalgent *newbie, uint_t flags)
463*7c478bd9Sstevel@tonic-gate {
464*7c478bd9Sstevel@tonic-gate 	ipsec_proto_t *protos, *current_proto;
465*7c478bd9Sstevel@tonic-gate 	struct ipsecalgent *clone, **holder;
466*7c478bd9Sstevel@tonic-gate 	int num_protos, i;
467*7c478bd9Sstevel@tonic-gate 	char **name_check;
468*7c478bd9Sstevel@tonic-gate 	boolean_t forced_add = (flags & LIBIPSEC_ALGS_ADD_FORCE) != 0;
469*7c478bd9Sstevel@tonic-gate 	boolean_t found_match;
470*7c478bd9Sstevel@tonic-gate 
471*7c478bd9Sstevel@tonic-gate 	if ((current_proto = proto_setup(&protos, &num_protos,
472*7c478bd9Sstevel@tonic-gate 	    newbie->a_proto_num, B_TRUE)) == NULL)
473*7c478bd9Sstevel@tonic-gate 		return (LIBIPSEC_ALGS_DIAG_UNKN_PROTO);
474*7c478bd9Sstevel@tonic-gate 
475*7c478bd9Sstevel@tonic-gate 	/*
476*7c478bd9Sstevel@tonic-gate 	 * If an algorithm that matches _exactly_ the new algorithm
477*7c478bd9Sstevel@tonic-gate 	 * already exists, we're done.
478*7c478bd9Sstevel@tonic-gate 	 */
479*7c478bd9Sstevel@tonic-gate 	if (ipsecalg_exists(newbie, current_proto))
480*7c478bd9Sstevel@tonic-gate 		return (0);
481*7c478bd9Sstevel@tonic-gate 
482*7c478bd9Sstevel@tonic-gate 	/*
483*7c478bd9Sstevel@tonic-gate 	 * We don't allow a new algorithm to be created if one of
484*7c478bd9Sstevel@tonic-gate 	 * its names is already defined for an existing algorithm,
485*7c478bd9Sstevel@tonic-gate 	 * unless the operation is forced, in which case existing
486*7c478bd9Sstevel@tonic-gate 	 * algorithm entries that conflict with the new one are
487*7c478bd9Sstevel@tonic-gate 	 * deleted.
488*7c478bd9Sstevel@tonic-gate 	 */
489*7c478bd9Sstevel@tonic-gate 	for (name_check = newbie->a_names; *name_check != NULL; name_check++) {
490*7c478bd9Sstevel@tonic-gate 		found_match = delipsecalgbyname_common(*name_check,
491*7c478bd9Sstevel@tonic-gate 		    current_proto, forced_add);
492*7c478bd9Sstevel@tonic-gate 		if (found_match && !forced_add) {
493*7c478bd9Sstevel@tonic-gate 			/*
494*7c478bd9Sstevel@tonic-gate 			 * Duplicate entry found, but the addition was
495*7c478bd9Sstevel@tonic-gate 			 * not forced.
496*7c478bd9Sstevel@tonic-gate 			 */
497*7c478bd9Sstevel@tonic-gate 			_clean_trash(protos, num_protos);
498*7c478bd9Sstevel@tonic-gate 			return (LIBIPSEC_ALGS_DIAG_ALG_EXISTS);
499*7c478bd9Sstevel@tonic-gate 		}
500*7c478bd9Sstevel@tonic-gate 	}
501*7c478bd9Sstevel@tonic-gate 
502*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < current_proto->proto_numalgs; i++) {
503*7c478bd9Sstevel@tonic-gate 		if (current_proto->proto_algs[i]->a_alg_num ==
504*7c478bd9Sstevel@tonic-gate 		    newbie->a_alg_num) {
505*7c478bd9Sstevel@tonic-gate 			/*
506*7c478bd9Sstevel@tonic-gate 			 * An algorithm with the same protocol number
507*7c478bd9Sstevel@tonic-gate 			 * and algorithm number already exists. Fail
508*7c478bd9Sstevel@tonic-gate 			 * addition unless the operation is forced.
509*7c478bd9Sstevel@tonic-gate 			 */
510*7c478bd9Sstevel@tonic-gate 			if (flags & LIBIPSEC_ALGS_ADD_FORCE) {
511*7c478bd9Sstevel@tonic-gate 				clone = _duplicate_alg(newbie);
512*7c478bd9Sstevel@tonic-gate 				if (clone != NULL) {
513*7c478bd9Sstevel@tonic-gate 					freeipsecalgent(
514*7c478bd9Sstevel@tonic-gate 					    current_proto->proto_algs[i]);
515*7c478bd9Sstevel@tonic-gate 					current_proto->proto_algs[i] = clone;
516*7c478bd9Sstevel@tonic-gate 					return (write_new_algfile(protos,
517*7c478bd9Sstevel@tonic-gate 						    num_protos));
518*7c478bd9Sstevel@tonic-gate 				} else {
519*7c478bd9Sstevel@tonic-gate 					_clean_trash(protos, num_protos);
520*7c478bd9Sstevel@tonic-gate 					return (LIBIPSEC_ALGS_DIAG_NOMEM);
521*7c478bd9Sstevel@tonic-gate 				}
522*7c478bd9Sstevel@tonic-gate 			} else {
523*7c478bd9Sstevel@tonic-gate 				_clean_trash(protos, num_protos);
524*7c478bd9Sstevel@tonic-gate 				return (LIBIPSEC_ALGS_DIAG_ALG_EXISTS);
525*7c478bd9Sstevel@tonic-gate 			}
526*7c478bd9Sstevel@tonic-gate 		}
527*7c478bd9Sstevel@tonic-gate 	}
528*7c478bd9Sstevel@tonic-gate 
529*7c478bd9Sstevel@tonic-gate 	/* append the new algorithm */
530*7c478bd9Sstevel@tonic-gate 	holder = realloc(current_proto->proto_algs,
531*7c478bd9Sstevel@tonic-gate 	    sizeof (struct ipsecalgent *) * (i + 1));
532*7c478bd9Sstevel@tonic-gate 	if (holder == NULL) {
533*7c478bd9Sstevel@tonic-gate 		_clean_trash(protos, num_protos);
534*7c478bd9Sstevel@tonic-gate 		return (LIBIPSEC_ALGS_DIAG_NOMEM);
535*7c478bd9Sstevel@tonic-gate 	}
536*7c478bd9Sstevel@tonic-gate 	clone = _duplicate_alg(newbie);
537*7c478bd9Sstevel@tonic-gate 	if (clone == NULL) {
538*7c478bd9Sstevel@tonic-gate 		free(holder);
539*7c478bd9Sstevel@tonic-gate 		_clean_trash(protos, num_protos);
540*7c478bd9Sstevel@tonic-gate 		return (LIBIPSEC_ALGS_DIAG_NOMEM);
541*7c478bd9Sstevel@tonic-gate 	}
542*7c478bd9Sstevel@tonic-gate 	current_proto->proto_numalgs++;
543*7c478bd9Sstevel@tonic-gate 	current_proto->proto_algs = holder;
544*7c478bd9Sstevel@tonic-gate 	current_proto->proto_algs[i] = clone;
545*7c478bd9Sstevel@tonic-gate 	return (write_new_algfile(protos, num_protos));
546*7c478bd9Sstevel@tonic-gate }
547*7c478bd9Sstevel@tonic-gate 
548*7c478bd9Sstevel@tonic-gate /*
549*7c478bd9Sstevel@tonic-gate  * Delete an algorithm by name & protocol number from /etc/inet/ipsecalgs.
550*7c478bd9Sstevel@tonic-gate  * Only deletes the first encountered instance.
551*7c478bd9Sstevel@tonic-gate  */
552*7c478bd9Sstevel@tonic-gate int
553*7c478bd9Sstevel@tonic-gate delipsecalgbyname(const char *name, int proto_num)
554*7c478bd9Sstevel@tonic-gate {
555*7c478bd9Sstevel@tonic-gate 	ipsec_proto_t *protos, *current_proto;
556*7c478bd9Sstevel@tonic-gate 	int num_protos;
557*7c478bd9Sstevel@tonic-gate 
558*7c478bd9Sstevel@tonic-gate 	if ((current_proto = proto_setup(&protos, &num_protos, proto_num,
559*7c478bd9Sstevel@tonic-gate 	    B_TRUE)) == NULL)
560*7c478bd9Sstevel@tonic-gate 		return (LIBIPSEC_ALGS_DIAG_UNKN_PROTO);
561*7c478bd9Sstevel@tonic-gate 
562*7c478bd9Sstevel@tonic-gate 	if (delipsecalgbyname_common(name, current_proto, B_TRUE))
563*7c478bd9Sstevel@tonic-gate 		return (write_new_algfile(protos, num_protos));
564*7c478bd9Sstevel@tonic-gate 
565*7c478bd9Sstevel@tonic-gate 	_clean_trash(protos, num_protos);
566*7c478bd9Sstevel@tonic-gate 	return (LIBIPSEC_ALGS_DIAG_UNKN_ALG);
567*7c478bd9Sstevel@tonic-gate }
568*7c478bd9Sstevel@tonic-gate 
569*7c478bd9Sstevel@tonic-gate /*
570*7c478bd9Sstevel@tonic-gate  * Delete an algorithm by num + protocol num from /etc/inet/ipsecalgs.
571*7c478bd9Sstevel@tonic-gate  */
572*7c478bd9Sstevel@tonic-gate int
573*7c478bd9Sstevel@tonic-gate delipsecalgbynum(int alg_num, int proto_num)
574*7c478bd9Sstevel@tonic-gate {
575*7c478bd9Sstevel@tonic-gate 	ipsec_proto_t *protos, *current_proto;
576*7c478bd9Sstevel@tonic-gate 	int i, num_protos;
577*7c478bd9Sstevel@tonic-gate 	boolean_t found_match = B_FALSE;
578*7c478bd9Sstevel@tonic-gate 
579*7c478bd9Sstevel@tonic-gate 	if ((current_proto = proto_setup(&protos, &num_protos, proto_num,
580*7c478bd9Sstevel@tonic-gate 	    B_TRUE)) == NULL)
581*7c478bd9Sstevel@tonic-gate 		return (LIBIPSEC_ALGS_DIAG_UNKN_PROTO);
582*7c478bd9Sstevel@tonic-gate 
583*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < current_proto->proto_numalgs; i++) {
584*7c478bd9Sstevel@tonic-gate 		if (!found_match) {
585*7c478bd9Sstevel@tonic-gate 			if (current_proto->proto_algs[i]->a_alg_num ==
586*7c478bd9Sstevel@tonic-gate 			    alg_num) {
587*7c478bd9Sstevel@tonic-gate 				found_match = B_TRUE;
588*7c478bd9Sstevel@tonic-gate 				freeipsecalgent(current_proto->proto_algs[i]);
589*7c478bd9Sstevel@tonic-gate 			}
590*7c478bd9Sstevel@tonic-gate 		} else {
591*7c478bd9Sstevel@tonic-gate 			current_proto->proto_algs[i - 1] =
592*7c478bd9Sstevel@tonic-gate 			    current_proto->proto_algs[i];
593*7c478bd9Sstevel@tonic-gate 		}
594*7c478bd9Sstevel@tonic-gate 	}
595*7c478bd9Sstevel@tonic-gate 
596*7c478bd9Sstevel@tonic-gate 	if (found_match) {
597*7c478bd9Sstevel@tonic-gate 		current_proto->proto_numalgs--;
598*7c478bd9Sstevel@tonic-gate 		return (write_new_algfile(protos, num_protos));
599*7c478bd9Sstevel@tonic-gate 	}
600*7c478bd9Sstevel@tonic-gate 
601*7c478bd9Sstevel@tonic-gate 	_clean_trash(protos, num_protos);
602*7c478bd9Sstevel@tonic-gate 	return (LIBIPSEC_ALGS_DIAG_UNKN_ALG);
603*7c478bd9Sstevel@tonic-gate }
604*7c478bd9Sstevel@tonic-gate 
605*7c478bd9Sstevel@tonic-gate /*
606*7c478bd9Sstevel@tonic-gate  * Remove the specified protocol entry from the list of protocols.
607*7c478bd9Sstevel@tonic-gate  */
608*7c478bd9Sstevel@tonic-gate static void
609*7c478bd9Sstevel@tonic-gate delipsecproto_common(ipsec_proto_t *protos, int num_protos,
610*7c478bd9Sstevel@tonic-gate     ipsec_proto_t *proto)
611*7c478bd9Sstevel@tonic-gate {
612*7c478bd9Sstevel@tonic-gate 	int i;
613*7c478bd9Sstevel@tonic-gate 
614*7c478bd9Sstevel@tonic-gate 	/* free protocol storage */
615*7c478bd9Sstevel@tonic-gate 	free(proto->proto_name);
616*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < proto->proto_numalgs; i++)
617*7c478bd9Sstevel@tonic-gate 		freeipsecalgent(proto->proto_algs[i]);
618*7c478bd9Sstevel@tonic-gate 
619*7c478bd9Sstevel@tonic-gate 	/* remove from list of prototocols */
620*7c478bd9Sstevel@tonic-gate 	for (i = (proto - protos + 1); i < num_protos; i++)
621*7c478bd9Sstevel@tonic-gate 		protos[i - 1] = protos[i];
622*7c478bd9Sstevel@tonic-gate }
623*7c478bd9Sstevel@tonic-gate 
624*7c478bd9Sstevel@tonic-gate /*
625*7c478bd9Sstevel@tonic-gate  * Add an IPsec protocol to /etc/inet/ipsecalgs.
626*7c478bd9Sstevel@tonic-gate  */
627*7c478bd9Sstevel@tonic-gate int
628*7c478bd9Sstevel@tonic-gate addipsecproto(const char *proto_name, int proto_num,
629*7c478bd9Sstevel@tonic-gate     ipsecalgs_exec_mode_t proto_exec_mode, uint_t flags)
630*7c478bd9Sstevel@tonic-gate {
631*7c478bd9Sstevel@tonic-gate 	ipsec_proto_t *protos, *current_proto, *new_proto;
632*7c478bd9Sstevel@tonic-gate 	int i, num_protos;
633*7c478bd9Sstevel@tonic-gate 
634*7c478bd9Sstevel@tonic-gate 	/*
635*7c478bd9Sstevel@tonic-gate 	 * NOTE:If build_internal_algs returns NULL for any
636*7c478bd9Sstevel@tonic-gate 	 *	reason, we will end up clobbering /etc/inet/ipsecalgs!
637*7c478bd9Sstevel@tonic-gate 	 */
638*7c478bd9Sstevel@tonic-gate 
639*7c478bd9Sstevel@tonic-gate 	current_proto = proto_setup(&protos, &num_protos, proto_num, B_FALSE);
640*7c478bd9Sstevel@tonic-gate 
641*7c478bd9Sstevel@tonic-gate 	/* check for protocol with duplicate id */
642*7c478bd9Sstevel@tonic-gate 	if (current_proto != NULL) {
643*7c478bd9Sstevel@tonic-gate 		if ((strcmp(proto_name, current_proto->proto_name) == 0) &&
644*7c478bd9Sstevel@tonic-gate 		    (proto_exec_mode == current_proto->proto_exec_mode)) {
645*7c478bd9Sstevel@tonic-gate 			/*
646*7c478bd9Sstevel@tonic-gate 			 * The current protocol being added matches
647*7c478bd9Sstevel@tonic-gate 			 * exactly an existing protocol, we're done.
648*7c478bd9Sstevel@tonic-gate 			 */
649*7c478bd9Sstevel@tonic-gate 			return (0);
650*7c478bd9Sstevel@tonic-gate 		}
651*7c478bd9Sstevel@tonic-gate 		if (!(flags & LIBIPSEC_ALGS_ADD_FORCE))
652*7c478bd9Sstevel@tonic-gate 			return (LIBIPSEC_ALGS_DIAG_PROTO_EXISTS);
653*7c478bd9Sstevel@tonic-gate 		delipsecproto_common(protos, num_protos--, current_proto);
654*7c478bd9Sstevel@tonic-gate 	}
655*7c478bd9Sstevel@tonic-gate 
656*7c478bd9Sstevel@tonic-gate 	/* check for protocol with duplicate name */
657*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < num_protos; i++) {
658*7c478bd9Sstevel@tonic-gate 		if (strcmp(protos[i].proto_name, proto_name) == 0) {
659*7c478bd9Sstevel@tonic-gate 			if (!(flags & LIBIPSEC_ALGS_ADD_FORCE))
660*7c478bd9Sstevel@tonic-gate 				return (LIBIPSEC_ALGS_DIAG_PROTO_EXISTS);
661*7c478bd9Sstevel@tonic-gate 			delipsecproto_common(protos, num_protos--, &protos[i]);
662*7c478bd9Sstevel@tonic-gate 			break;
663*7c478bd9Sstevel@tonic-gate 		}
664*7c478bd9Sstevel@tonic-gate 	}
665*7c478bd9Sstevel@tonic-gate 
666*7c478bd9Sstevel@tonic-gate 	/* add new protocol */
667*7c478bd9Sstevel@tonic-gate 	num_protos++;
668*7c478bd9Sstevel@tonic-gate 	new_proto = realloc(protos, num_protos *
669*7c478bd9Sstevel@tonic-gate 	    sizeof (ipsec_proto_t));
670*7c478bd9Sstevel@tonic-gate 	if (new_proto == NULL) {
671*7c478bd9Sstevel@tonic-gate 		_clean_trash(protos, num_protos - 1);
672*7c478bd9Sstevel@tonic-gate 		return (LIBIPSEC_ALGS_DIAG_NOMEM);
673*7c478bd9Sstevel@tonic-gate 	}
674*7c478bd9Sstevel@tonic-gate 	protos = new_proto;
675*7c478bd9Sstevel@tonic-gate 	new_proto += (num_protos - 1);
676*7c478bd9Sstevel@tonic-gate 
677*7c478bd9Sstevel@tonic-gate 	/* initialize protocol entry */
678*7c478bd9Sstevel@tonic-gate 	new_proto->proto_num = proto_num;
679*7c478bd9Sstevel@tonic-gate 	new_proto->proto_numalgs = 0;
680*7c478bd9Sstevel@tonic-gate 	new_proto->proto_algs = NULL;
681*7c478bd9Sstevel@tonic-gate 	new_proto->proto_name = strdup(proto_name);
682*7c478bd9Sstevel@tonic-gate 	if (new_proto->proto_name == NULL) {
683*7c478bd9Sstevel@tonic-gate 		_clean_trash(protos, num_protos);
684*7c478bd9Sstevel@tonic-gate 		return (LIBIPSEC_ALGS_DIAG_NOMEM);
685*7c478bd9Sstevel@tonic-gate 	}
686*7c478bd9Sstevel@tonic-gate 	new_proto->proto_pkg = NULL;
687*7c478bd9Sstevel@tonic-gate 	new_proto->proto_algs_pkgs = NULL;
688*7c478bd9Sstevel@tonic-gate 	new_proto->proto_algs_npkgs = 0;
689*7c478bd9Sstevel@tonic-gate 	new_proto->proto_exec_mode = proto_exec_mode;
690*7c478bd9Sstevel@tonic-gate 
691*7c478bd9Sstevel@tonic-gate 	return (write_new_algfile(protos, num_protos));
692*7c478bd9Sstevel@tonic-gate }
693*7c478bd9Sstevel@tonic-gate 
694*7c478bd9Sstevel@tonic-gate /*
695*7c478bd9Sstevel@tonic-gate  * Delete an IPsec protocol entry from /etc/inet/ipsecalgs.  This also
696*7c478bd9Sstevel@tonic-gate  * nukes the associated algorithms.
697*7c478bd9Sstevel@tonic-gate  */
698*7c478bd9Sstevel@tonic-gate int
699*7c478bd9Sstevel@tonic-gate delipsecprotobynum(int proto_num)
700*7c478bd9Sstevel@tonic-gate {
701*7c478bd9Sstevel@tonic-gate 	ipsec_proto_t *protos, *current_proto;
702*7c478bd9Sstevel@tonic-gate 	int num_protos;
703*7c478bd9Sstevel@tonic-gate 
704*7c478bd9Sstevel@tonic-gate 	if ((current_proto = proto_setup(&protos, &num_protos, proto_num,
705*7c478bd9Sstevel@tonic-gate 	    B_TRUE)) == NULL)
706*7c478bd9Sstevel@tonic-gate 		return (LIBIPSEC_ALGS_DIAG_UNKN_PROTO);
707*7c478bd9Sstevel@tonic-gate 
708*7c478bd9Sstevel@tonic-gate 	delipsecproto_common(protos, num_protos--, current_proto);
709*7c478bd9Sstevel@tonic-gate 
710*7c478bd9Sstevel@tonic-gate 	return (write_new_algfile(protos, num_protos));
711*7c478bd9Sstevel@tonic-gate }
712*7c478bd9Sstevel@tonic-gate 
713*7c478bd9Sstevel@tonic-gate int
714*7c478bd9Sstevel@tonic-gate delipsecprotobyname(const char *proto_name)
715*7c478bd9Sstevel@tonic-gate {
716*7c478bd9Sstevel@tonic-gate 	int proto_num;
717*7c478bd9Sstevel@tonic-gate 
718*7c478bd9Sstevel@tonic-gate 	proto_num = getipsecprotobyname(proto_name);
719*7c478bd9Sstevel@tonic-gate 	if (proto_num == -1)
720*7c478bd9Sstevel@tonic-gate 		return (LIBIPSEC_ALGS_DIAG_UNKN_PROTO);
721*7c478bd9Sstevel@tonic-gate 
722*7c478bd9Sstevel@tonic-gate 	return (delipsecprotobynum(proto_num));
723*7c478bd9Sstevel@tonic-gate }
724*7c478bd9Sstevel@tonic-gate 
725*7c478bd9Sstevel@tonic-gate /*
726*7c478bd9Sstevel@tonic-gate  * Implement these in libnsl since these are read-only operations.
727*7c478bd9Sstevel@tonic-gate  */
728*7c478bd9Sstevel@tonic-gate int *
729*7c478bd9Sstevel@tonic-gate getipsecprotos(int *nentries)
730*7c478bd9Sstevel@tonic-gate {
731*7c478bd9Sstevel@tonic-gate 	return (_real_getipsecprotos(nentries));
732*7c478bd9Sstevel@tonic-gate }
733*7c478bd9Sstevel@tonic-gate 
734*7c478bd9Sstevel@tonic-gate int *
735*7c478bd9Sstevel@tonic-gate getipsecalgs(int *nentries, int proto_num)
736*7c478bd9Sstevel@tonic-gate {
737*7c478bd9Sstevel@tonic-gate 	return (_real_getipsecalgs(nentries, proto_num));
738*7c478bd9Sstevel@tonic-gate }
739*7c478bd9Sstevel@tonic-gate 
740*7c478bd9Sstevel@tonic-gate const char *
741*7c478bd9Sstevel@tonic-gate ipsecalgs_diag(int diag)
742*7c478bd9Sstevel@tonic-gate {
743*7c478bd9Sstevel@tonic-gate 	switch (diag) {
744*7c478bd9Sstevel@tonic-gate 	case LIBIPSEC_ALGS_DIAG_ALG_EXISTS:
745*7c478bd9Sstevel@tonic-gate 		return (gettext("Algorithm already exists"));
746*7c478bd9Sstevel@tonic-gate 	case LIBIPSEC_ALGS_DIAG_PROTO_EXISTS:
747*7c478bd9Sstevel@tonic-gate 		return (gettext("Protocol already exists"));
748*7c478bd9Sstevel@tonic-gate 	case LIBIPSEC_ALGS_DIAG_UNKN_PROTO:
749*7c478bd9Sstevel@tonic-gate 		return (gettext("Unknown protocol"));
750*7c478bd9Sstevel@tonic-gate 	case LIBIPSEC_ALGS_DIAG_UNKN_ALG:
751*7c478bd9Sstevel@tonic-gate 		return (gettext("Unknown algorithm"));
752*7c478bd9Sstevel@tonic-gate 	case LIBIPSEC_ALGS_DIAG_NOMEM:
753*7c478bd9Sstevel@tonic-gate 		return (gettext("Out of memory"));
754*7c478bd9Sstevel@tonic-gate 	case LIBIPSEC_ALGS_DIAG_ALGSFILEOPEN:
755*7c478bd9Sstevel@tonic-gate 		return (gettext("open() failed"));
756*7c478bd9Sstevel@tonic-gate 	case LIBIPSEC_ALGS_DIAG_ALGSFILEFDOPEN:
757*7c478bd9Sstevel@tonic-gate 		return (gettext("fdopen() failed"));
758*7c478bd9Sstevel@tonic-gate 	case LIBIPSEC_ALGS_DIAG_ALGSFILELOCK:
759*7c478bd9Sstevel@tonic-gate 		return (gettext("lockf() failed"));
760*7c478bd9Sstevel@tonic-gate 	case LIBIPSEC_ALGS_DIAG_ALGSFILERENAME:
761*7c478bd9Sstevel@tonic-gate 		return (gettext("rename() failed"));
762*7c478bd9Sstevel@tonic-gate 	case LIBIPSEC_ALGS_DIAG_ALGSFILEWRITE:
763*7c478bd9Sstevel@tonic-gate 		return (gettext("write to file failed"));
764*7c478bd9Sstevel@tonic-gate 	case LIBIPSEC_ALGS_DIAG_ALGSFILECHMOD:
765*7c478bd9Sstevel@tonic-gate 		return (gettext("chmod() failed"));
766*7c478bd9Sstevel@tonic-gate 	case LIBIPSEC_ALGS_DIAG_ALGSFILECHOWN:
767*7c478bd9Sstevel@tonic-gate 		return (gettext("chown() failed"));
768*7c478bd9Sstevel@tonic-gate 	case LIBIPSEC_ALGS_DIAG_ALGSFILECLOSE:
769*7c478bd9Sstevel@tonic-gate 		return (gettext("close() failed"));
770*7c478bd9Sstevel@tonic-gate 	default:
771*7c478bd9Sstevel@tonic-gate 		return (gettext("failed"));
772*7c478bd9Sstevel@tonic-gate 	}
773*7c478bd9Sstevel@tonic-gate }
774*7c478bd9Sstevel@tonic-gate 
775*7c478bd9Sstevel@tonic-gate /*
776*7c478bd9Sstevel@tonic-gate  * Get the execution mode corresponding to the specified protocol.
777*7c478bd9Sstevel@tonic-gate  * Returns 0 on success, one of the LIBIPSEC_ALGS_DIAG_* values on
778*7c478bd9Sstevel@tonic-gate  * failure.
779*7c478bd9Sstevel@tonic-gate  */
780*7c478bd9Sstevel@tonic-gate int
781*7c478bd9Sstevel@tonic-gate ipsecproto_get_exec_mode(int proto_num, ipsecalgs_exec_mode_t *exec_mode)
782*7c478bd9Sstevel@tonic-gate {
783*7c478bd9Sstevel@tonic-gate 	ipsec_proto_t *protos, *current_proto;
784*7c478bd9Sstevel@tonic-gate 	int num_protos;
785*7c478bd9Sstevel@tonic-gate 
786*7c478bd9Sstevel@tonic-gate 	if ((current_proto = proto_setup(&protos, &num_protos, proto_num,
787*7c478bd9Sstevel@tonic-gate 	    B_TRUE)) == NULL)
788*7c478bd9Sstevel@tonic-gate 		return (LIBIPSEC_ALGS_DIAG_UNKN_PROTO);
789*7c478bd9Sstevel@tonic-gate 
790*7c478bd9Sstevel@tonic-gate 	*exec_mode = current_proto->proto_exec_mode;
791*7c478bd9Sstevel@tonic-gate 
792*7c478bd9Sstevel@tonic-gate 	_clean_trash(protos, num_protos);
793*7c478bd9Sstevel@tonic-gate 	return (0);
794*7c478bd9Sstevel@tonic-gate }
795*7c478bd9Sstevel@tonic-gate 
796*7c478bd9Sstevel@tonic-gate /*
797*7c478bd9Sstevel@tonic-gate  * Set the execution mode of the specified protocol. Returns 0 on success,
798*7c478bd9Sstevel@tonic-gate  * or one of the LIBIPSEC_ALGS_DIAG_* values on failure.
799*7c478bd9Sstevel@tonic-gate  */
800*7c478bd9Sstevel@tonic-gate int
801*7c478bd9Sstevel@tonic-gate ipsecproto_set_exec_mode(int proto_num, ipsecalgs_exec_mode_t exec_mode)
802*7c478bd9Sstevel@tonic-gate {
803*7c478bd9Sstevel@tonic-gate 	ipsec_proto_t *protos, *current_proto;
804*7c478bd9Sstevel@tonic-gate 	int num_protos;
805*7c478bd9Sstevel@tonic-gate 
806*7c478bd9Sstevel@tonic-gate 	if ((current_proto = proto_setup(&protos, &num_protos, proto_num,
807*7c478bd9Sstevel@tonic-gate 	    B_TRUE)) == NULL)
808*7c478bd9Sstevel@tonic-gate 		return (LIBIPSEC_ALGS_DIAG_UNKN_PROTO);
809*7c478bd9Sstevel@tonic-gate 
810*7c478bd9Sstevel@tonic-gate 	current_proto->proto_exec_mode = exec_mode;
811*7c478bd9Sstevel@tonic-gate 
812*7c478bd9Sstevel@tonic-gate 	return (write_new_algfile(protos, num_protos));
813*7c478bd9Sstevel@tonic-gate }
814