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