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 2003 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/errno.h>
31*0Sstevel@tonic-gate #include <sys/stat.h>
32*0Sstevel@tonic-gate #include <ipsec_util.h>
33*0Sstevel@tonic-gate #include <netdb.h>
34*0Sstevel@tonic-gate #include <fcntl.h>
35*0Sstevel@tonic-gate #include <unistd.h>
36*0Sstevel@tonic-gate #include <synch.h>
37*0Sstevel@tonic-gate #include <string.h>
38*0Sstevel@tonic-gate #include <strings.h>
39*0Sstevel@tonic-gate #include <stdlib.h>
40*0Sstevel@tonic-gate #include <unistd.h>
41*0Sstevel@tonic-gate #include <syslog.h>
42*0Sstevel@tonic-gate 
43*0Sstevel@tonic-gate /* Globals... */
44*0Sstevel@tonic-gate static rwlock_t proto_rw = DEFAULTRWLOCK; /* Protects cached algorithm list. */
45*0Sstevel@tonic-gate static time_t proto_last_update;
46*0Sstevel@tonic-gate static ipsec_proto_t *protos;
47*0Sstevel@tonic-gate static int num_protos;
48*0Sstevel@tonic-gate 
49*0Sstevel@tonic-gate void
50*0Sstevel@tonic-gate _clean_trash(ipsec_proto_t *proto, int num)
51*0Sstevel@tonic-gate {
52*0Sstevel@tonic-gate 	int alg_offset;
53*0Sstevel@tonic-gate 
54*0Sstevel@tonic-gate 	if (proto == NULL)
55*0Sstevel@tonic-gate 		return;
56*0Sstevel@tonic-gate 
57*0Sstevel@tonic-gate 	while (num-- != 0) {
58*0Sstevel@tonic-gate 		free(proto[num].proto_name);
59*0Sstevel@tonic-gate 		free(proto[num].proto_pkg);
60*0Sstevel@tonic-gate 		for (alg_offset = 0; alg_offset < proto[num].proto_numalgs;
61*0Sstevel@tonic-gate 		    alg_offset++)
62*0Sstevel@tonic-gate 			freeipsecalgent(proto[num].proto_algs[alg_offset]);
63*0Sstevel@tonic-gate 		free(proto[num].proto_algs);
64*0Sstevel@tonic-gate 		for (alg_offset = 0; alg_offset < proto[num].proto_algs_npkgs;
65*0Sstevel@tonic-gate 		    alg_offset++)
66*0Sstevel@tonic-gate 			free(proto[num].proto_algs_pkgs[alg_offset].pkg_name);
67*0Sstevel@tonic-gate 		free(proto[num].proto_algs_pkgs);
68*0Sstevel@tonic-gate 	}
69*0Sstevel@tonic-gate 
70*0Sstevel@tonic-gate 	free(proto);
71*0Sstevel@tonic-gate }
72*0Sstevel@tonic-gate 
73*0Sstevel@tonic-gate static const char *pipechar = "|";
74*0Sstevel@tonic-gate static const char *comma = ",";
75*0Sstevel@tonic-gate static const char *dash = "-";
76*0Sstevel@tonic-gate static const char *slash = "/";
77*0Sstevel@tonic-gate 
78*0Sstevel@tonic-gate /*
79*0Sstevel@tonic-gate  * Returns >= 0 if success (and > 0 means "increment").
80*0Sstevel@tonic-gate  * Returns -1 if failure.
81*0Sstevel@tonic-gate  */
82*0Sstevel@tonic-gate static int
83*0Sstevel@tonic-gate build_keysizes(int **sizep, char *input_string)
84*0Sstevel@tonic-gate {
85*0Sstevel@tonic-gate 	char *lasts, *token;
86*0Sstevel@tonic-gate 	int *key_sizes = NULL, num_sizes, key_low, key_high, key_default;
87*0Sstevel@tonic-gate 	int key_increment = 0;
88*0Sstevel@tonic-gate 
89*0Sstevel@tonic-gate 	/*
90*0Sstevel@tonic-gate 	 * Okay, let's check the format of the key string.  It'll be either:
91*0Sstevel@tonic-gate 	 *
92*0Sstevel@tonic-gate 	 * enumeration: size1,size2...,sizeN
93*0Sstevel@tonic-gate 	 * range: defaultSize/sizeLow-sizeHi,increment
94*0Sstevel@tonic-gate 	 *
95*0Sstevel@tonic-gate 	 * In the case of an enumeration, the default key size is the
96*0Sstevel@tonic-gate 	 * first one in the list.
97*0Sstevel@tonic-gate 	 */
98*0Sstevel@tonic-gate 
99*0Sstevel@tonic-gate 	if (strchr(input_string, '/') != NULL) {
100*0Sstevel@tonic-gate 		/* key sizes specified by range */
101*0Sstevel@tonic-gate 
102*0Sstevel@tonic-gate 		/* default */
103*0Sstevel@tonic-gate 		token = strtok_r(input_string, slash, &lasts);
104*0Sstevel@tonic-gate 		if (token == NULL || (key_default = atoi(token)) == 0)
105*0Sstevel@tonic-gate 			return (-1);
106*0Sstevel@tonic-gate 
107*0Sstevel@tonic-gate 		/* low */
108*0Sstevel@tonic-gate 		token = strtok_r(NULL, dash, &lasts);
109*0Sstevel@tonic-gate 		if (token == NULL || (key_low = atoi(token)) == 0)
110*0Sstevel@tonic-gate 			return (-1);
111*0Sstevel@tonic-gate 
112*0Sstevel@tonic-gate 		/* high */
113*0Sstevel@tonic-gate 		token = strtok_r(NULL, comma, &lasts);
114*0Sstevel@tonic-gate 		if (token == NULL || (key_high = atoi(token)) == 0 ||
115*0Sstevel@tonic-gate 		    key_high <= key_low)
116*0Sstevel@tonic-gate 			return (-1);
117*0Sstevel@tonic-gate 
118*0Sstevel@tonic-gate 		/* increment */
119*0Sstevel@tonic-gate 		token = strtok_r(NULL, "", &lasts);
120*0Sstevel@tonic-gate 		if (token == NULL || (key_increment = atoi(token)) == 0)
121*0Sstevel@tonic-gate 			return (-1);
122*0Sstevel@tonic-gate 
123*0Sstevel@tonic-gate 		key_sizes = (int *)malloc(LIBIPSEC_ALGS_KEY_NUM_VAL *
124*0Sstevel@tonic-gate 		    sizeof (int));
125*0Sstevel@tonic-gate 		if (key_sizes == NULL)
126*0Sstevel@tonic-gate 			return (-1);
127*0Sstevel@tonic-gate 
128*0Sstevel@tonic-gate 		key_sizes[LIBIPSEC_ALGS_KEY_DEF_IDX] = key_default;
129*0Sstevel@tonic-gate 		key_sizes[LIBIPSEC_ALGS_KEY_MIN_IDX] = key_low;
130*0Sstevel@tonic-gate 		key_sizes[LIBIPSEC_ALGS_KEY_MAX_IDX] = key_high;
131*0Sstevel@tonic-gate 		key_sizes[LIBIPSEC_ALGS_KEY_MAX_IDX + 1] = 0;
132*0Sstevel@tonic-gate 	} else {
133*0Sstevel@tonic-gate 		/* key sizes specified by enumeration */
134*0Sstevel@tonic-gate 
135*0Sstevel@tonic-gate 		key_sizes = (int *)malloc(sizeof (int));
136*0Sstevel@tonic-gate 		if (key_sizes == NULL)
137*0Sstevel@tonic-gate 			return (-1);
138*0Sstevel@tonic-gate 		num_sizes = 0;
139*0Sstevel@tonic-gate 
140*0Sstevel@tonic-gate 		token = strtok_r(input_string, comma, &lasts);
141*0Sstevel@tonic-gate 		if (token == NULL || key_sizes == NULL)
142*0Sstevel@tonic-gate 			return (-1);
143*0Sstevel@tonic-gate 		*key_sizes = 0;
144*0Sstevel@tonic-gate 		do {
145*0Sstevel@tonic-gate 			int *nks;
146*0Sstevel@tonic-gate 
147*0Sstevel@tonic-gate 			nks = (int *)realloc(key_sizes,
148*0Sstevel@tonic-gate 			    sizeof (int) * ((++num_sizes) + 1));
149*0Sstevel@tonic-gate 			if (nks == NULL) {
150*0Sstevel@tonic-gate 				free(key_sizes);
151*0Sstevel@tonic-gate 				return (-1);
152*0Sstevel@tonic-gate 			}
153*0Sstevel@tonic-gate 			key_sizes = nks;
154*0Sstevel@tonic-gate 			/* Can't check for atoi() == 0 here... */
155*0Sstevel@tonic-gate 			key_sizes[num_sizes - 1] = atoi(token);
156*0Sstevel@tonic-gate 			key_sizes[num_sizes] = 0;
157*0Sstevel@tonic-gate 		} while ((token = strtok_r(NULL, comma, &lasts)) != NULL);
158*0Sstevel@tonic-gate 	}
159*0Sstevel@tonic-gate 
160*0Sstevel@tonic-gate 	*sizep = key_sizes;
161*0Sstevel@tonic-gate 
162*0Sstevel@tonic-gate 	return (key_increment);
163*0Sstevel@tonic-gate }
164*0Sstevel@tonic-gate 
165*0Sstevel@tonic-gate /*
166*0Sstevel@tonic-gate  * Find the execution mode corresponding to the given string.
167*0Sstevel@tonic-gate  * Returns 0 on success, -1 on failure.
168*0Sstevel@tonic-gate  */
169*0Sstevel@tonic-gate int
170*0Sstevel@tonic-gate _str_to_ipsec_exec_mode(char *str, ipsecalgs_exec_mode_t *exec_mode)
171*0Sstevel@tonic-gate {
172*0Sstevel@tonic-gate 	if (strcmp(str, "sync") == 0) {
173*0Sstevel@tonic-gate 		*exec_mode = LIBIPSEC_ALGS_EXEC_SYNC;
174*0Sstevel@tonic-gate 		return (0);
175*0Sstevel@tonic-gate 	} else if (strcmp(str, "async") == 0) {
176*0Sstevel@tonic-gate 		*exec_mode = LIBIPSEC_ALGS_EXEC_ASYNC;
177*0Sstevel@tonic-gate 		return (0);
178*0Sstevel@tonic-gate 	}
179*0Sstevel@tonic-gate 
180*0Sstevel@tonic-gate 	return (-1);
181*0Sstevel@tonic-gate }
182*0Sstevel@tonic-gate 
183*0Sstevel@tonic-gate /*
184*0Sstevel@tonic-gate  * Given a file pointer, read all the text from the file and convert it into
185*0Sstevel@tonic-gate  * a bunch of ipsec_proto_t's, each with an array of struct ipsecalgent
186*0Sstevel@tonic-gate  * pointers - one for each algorithm.
187*0Sstevel@tonic-gate  */
188*0Sstevel@tonic-gate static ipsec_proto_t *
189*0Sstevel@tonic-gate build_list(FILE *f, int *num)
190*0Sstevel@tonic-gate {
191*0Sstevel@tonic-gate 	char line[1024];
192*0Sstevel@tonic-gate 	char *token, *lasts, *alg_names, *ef_name, *key_string, *block_string;
193*0Sstevel@tonic-gate 	char *proto_name;
194*0Sstevel@tonic-gate 	ipsec_proto_t *rc = NULL, *new_proto = NULL;
195*0Sstevel@tonic-gate 	int *block_sizes, *key_sizes;
196*0Sstevel@tonic-gate 	int rc_num = 0, key_increment;
197*0Sstevel@tonic-gate 	int new_num, alg_num, num_sizes;
198*0Sstevel@tonic-gate 	struct ipsecalgent *curalg, **newalglist;
199*0Sstevel@tonic-gate 	char cur_pkg[1024];
200*0Sstevel@tonic-gate 	boolean_t doing_pkg = B_FALSE;
201*0Sstevel@tonic-gate 	ipsecalgs_exec_mode_t exec_mode;
202*0Sstevel@tonic-gate 	char diag_buf[128];
203*0Sstevel@tonic-gate 
204*0Sstevel@tonic-gate 	diag_buf[0] = '\0';
205*0Sstevel@tonic-gate 
206*0Sstevel@tonic-gate 	while (fgets(line, sizeof (line), f) != NULL) {
207*0Sstevel@tonic-gate 		if (strncasecmp(line, LIBIPSEC_ALGS_LINE_PROTO,
208*0Sstevel@tonic-gate 		    sizeof (LIBIPSEC_ALGS_LINE_PROTO) - 1) != 0 &&
209*0Sstevel@tonic-gate 		    strncasecmp(line, LIBIPSEC_ALGS_LINE_ALG,
210*0Sstevel@tonic-gate 		    sizeof (LIBIPSEC_ALGS_LINE_ALG) - 1) != 0 &&
211*0Sstevel@tonic-gate 		    strncasecmp(line, LIBIPSEC_ALGS_LINE_PKGSTART,
212*0Sstevel@tonic-gate 		    sizeof (LIBIPSEC_ALGS_LINE_PKGSTART) - 1) != 0 &&
213*0Sstevel@tonic-gate 		    strncasecmp(line, LIBIPSEC_ALGS_LINE_PKGEND,
214*0Sstevel@tonic-gate 		    sizeof (LIBIPSEC_ALGS_LINE_PKGEND) - 1) != 0) {
215*0Sstevel@tonic-gate 			if ((token = strtok_r(line, " \t\n", &lasts)) == NULL ||
216*0Sstevel@tonic-gate 			    token[0] == '#') {
217*0Sstevel@tonic-gate 				continue;
218*0Sstevel@tonic-gate 			} else {
219*0Sstevel@tonic-gate 				snprintf(diag_buf, sizeof (diag_buf),
220*0Sstevel@tonic-gate 					"non-recognized start of line");
221*0Sstevel@tonic-gate 				goto bail;
222*0Sstevel@tonic-gate 			}
223*0Sstevel@tonic-gate 		}
224*0Sstevel@tonic-gate 
225*0Sstevel@tonic-gate 		if (strncasecmp(line, LIBIPSEC_ALGS_LINE_PROTO,
226*0Sstevel@tonic-gate 		    sizeof (LIBIPSEC_ALGS_LINE_PROTO) - 1) == 0) {
227*0Sstevel@tonic-gate 			/* current line defines a new protocol */
228*0Sstevel@tonic-gate 
229*0Sstevel@tonic-gate 			/* skip the protocol token */
230*0Sstevel@tonic-gate 			token = strtok_r(line, pipechar, &lasts);
231*0Sstevel@tonic-gate 
232*0Sstevel@tonic-gate 			/* protocol number */
233*0Sstevel@tonic-gate 			token = strtok_r(NULL, pipechar, &lasts);
234*0Sstevel@tonic-gate 			if (token == NULL || (new_num = atoi(token)) == 0) {
235*0Sstevel@tonic-gate 				snprintf(diag_buf, sizeof (diag_buf),
236*0Sstevel@tonic-gate 				    "invalid protocol number");
237*0Sstevel@tonic-gate 				goto bail;
238*0Sstevel@tonic-gate 			}
239*0Sstevel@tonic-gate 
240*0Sstevel@tonic-gate 			/* protocol name */
241*0Sstevel@tonic-gate 			token = strtok_r(NULL, pipechar, &lasts);
242*0Sstevel@tonic-gate 			if (token == NULL) {
243*0Sstevel@tonic-gate 				snprintf(diag_buf, sizeof (diag_buf),
244*0Sstevel@tonic-gate 				    "cannot read protocol name");
245*0Sstevel@tonic-gate 				goto bail;
246*0Sstevel@tonic-gate 			}
247*0Sstevel@tonic-gate 			proto_name = token;
248*0Sstevel@tonic-gate 
249*0Sstevel@tonic-gate 			/* execution mode */
250*0Sstevel@tonic-gate 			token = strtok_r(NULL, pipechar, &lasts);
251*0Sstevel@tonic-gate 			if (token == NULL) {
252*0Sstevel@tonic-gate 				snprintf(diag_buf, sizeof (diag_buf),
253*0Sstevel@tonic-gate 				    "cannot read execution mode");
254*0Sstevel@tonic-gate 				goto bail;
255*0Sstevel@tonic-gate 			}
256*0Sstevel@tonic-gate 			/* remove trailing '\n' */
257*0Sstevel@tonic-gate 			token[strlen(token) - 1] = '\0';
258*0Sstevel@tonic-gate 			if (_str_to_ipsec_exec_mode(token, &exec_mode) != 0) {
259*0Sstevel@tonic-gate 				snprintf(diag_buf, sizeof (diag_buf),
260*0Sstevel@tonic-gate 				    "invalid execution mode: \"%s\"", token);
261*0Sstevel@tonic-gate 				goto bail;
262*0Sstevel@tonic-gate 			}
263*0Sstevel@tonic-gate 
264*0Sstevel@tonic-gate 			/* initialize protocol structure */
265*0Sstevel@tonic-gate 			rc_num++;
266*0Sstevel@tonic-gate 			new_proto = (ipsec_proto_t *)realloc(rc,
267*0Sstevel@tonic-gate 			    sizeof (ipsec_proto_t) * rc_num);
268*0Sstevel@tonic-gate 			rc = new_proto;
269*0Sstevel@tonic-gate 			if (new_proto == NULL)
270*0Sstevel@tonic-gate 				goto bail;
271*0Sstevel@tonic-gate 			new_proto += (rc_num - 1);
272*0Sstevel@tonic-gate 			new_proto->proto_num = new_num;
273*0Sstevel@tonic-gate 			new_proto->proto_algs = NULL;
274*0Sstevel@tonic-gate 			new_proto->proto_numalgs = 0;
275*0Sstevel@tonic-gate 			new_proto->proto_name = strdup(proto_name);
276*0Sstevel@tonic-gate 			if (new_proto->proto_name == NULL)
277*0Sstevel@tonic-gate 				goto bail;
278*0Sstevel@tonic-gate 			new_proto->proto_exec_mode = exec_mode;
279*0Sstevel@tonic-gate 
280*0Sstevel@tonic-gate 			if (doing_pkg) {
281*0Sstevel@tonic-gate 				/* record proto as being part of current pkg */
282*0Sstevel@tonic-gate 				new_proto->proto_pkg = strdup(cur_pkg);
283*0Sstevel@tonic-gate 				if (new_proto->proto_pkg == NULL)
284*0Sstevel@tonic-gate 					goto bail;
285*0Sstevel@tonic-gate 			} else {
286*0Sstevel@tonic-gate 				new_proto->proto_pkg = NULL;
287*0Sstevel@tonic-gate 			}
288*0Sstevel@tonic-gate 
289*0Sstevel@tonic-gate 			new_proto->proto_algs_pkgs = NULL;
290*0Sstevel@tonic-gate 			new_proto->proto_algs_npkgs = 0;
291*0Sstevel@tonic-gate 
292*0Sstevel@tonic-gate 		} else if (strncasecmp(line, LIBIPSEC_ALGS_LINE_ALG,
293*0Sstevel@tonic-gate 		    sizeof (LIBIPSEC_ALGS_LINE_ALG) - 1) == 0) {
294*0Sstevel@tonic-gate 			/* current line defines a new algorithm */
295*0Sstevel@tonic-gate 
296*0Sstevel@tonic-gate 			/* skip the algorithm token */
297*0Sstevel@tonic-gate 			token = strtok_r(line, pipechar, &lasts);
298*0Sstevel@tonic-gate 
299*0Sstevel@tonic-gate 			/* protocol number */
300*0Sstevel@tonic-gate 			token = strtok_r(NULL, pipechar, &lasts);
301*0Sstevel@tonic-gate 			if (token == NULL || (new_num = atoi(token)) == 0) {
302*0Sstevel@tonic-gate 				snprintf(diag_buf, sizeof (diag_buf),
303*0Sstevel@tonic-gate 				    "invalid algorithm number");
304*0Sstevel@tonic-gate 				goto bail;
305*0Sstevel@tonic-gate 			}
306*0Sstevel@tonic-gate 
307*0Sstevel@tonic-gate 			/* We can be O(N) for now.  There aren't that many. */
308*0Sstevel@tonic-gate 			for (new_proto = rc; new_proto < (rc + new_num);
309*0Sstevel@tonic-gate 			    new_proto++)
310*0Sstevel@tonic-gate 				if (new_proto->proto_num == new_num)
311*0Sstevel@tonic-gate 					break;
312*0Sstevel@tonic-gate 			if (new_proto == (rc + new_num)) {
313*0Sstevel@tonic-gate 				snprintf(diag_buf, sizeof (diag_buf),
314*0Sstevel@tonic-gate 				    "invalid protocol number %d for algorithm",
315*0Sstevel@tonic-gate 				    new_num);
316*0Sstevel@tonic-gate 				goto bail;
317*0Sstevel@tonic-gate 			}
318*0Sstevel@tonic-gate 
319*0Sstevel@tonic-gate 			/* algorithm number */
320*0Sstevel@tonic-gate 			token = strtok_r(NULL, pipechar, &lasts);
321*0Sstevel@tonic-gate 			if (token == NULL) {
322*0Sstevel@tonic-gate 				snprintf(diag_buf, sizeof (diag_buf),
323*0Sstevel@tonic-gate 				    "cannot read algorithm number");
324*0Sstevel@tonic-gate 				goto bail;
325*0Sstevel@tonic-gate 			}
326*0Sstevel@tonic-gate 			/* Can't check for 0 here. */
327*0Sstevel@tonic-gate 			alg_num = atoi(token);
328*0Sstevel@tonic-gate 
329*0Sstevel@tonic-gate 			/* algorithm names */
330*0Sstevel@tonic-gate 			token = strtok_r(NULL, pipechar, &lasts);
331*0Sstevel@tonic-gate 			if (token == NULL) {
332*0Sstevel@tonic-gate 				snprintf(diag_buf, sizeof (diag_buf),
333*0Sstevel@tonic-gate 				    "cannot read algorithm number");
334*0Sstevel@tonic-gate 				goto bail;
335*0Sstevel@tonic-gate 			}
336*0Sstevel@tonic-gate 			alg_names = token;
337*0Sstevel@tonic-gate 
338*0Sstevel@tonic-gate 			/* mechanism name */
339*0Sstevel@tonic-gate 			token = strtok_r(NULL, pipechar, &lasts);
340*0Sstevel@tonic-gate 			if (token == NULL) {
341*0Sstevel@tonic-gate 				snprintf(diag_buf, sizeof (diag_buf),
342*0Sstevel@tonic-gate 				    "cannot read mechanism name for alg %d "
343*0Sstevel@tonic-gate 				    "(proto %d)", alg_num,
344*0Sstevel@tonic-gate 				    new_proto->proto_num);
345*0Sstevel@tonic-gate 				goto bail;
346*0Sstevel@tonic-gate 			}
347*0Sstevel@tonic-gate 			ef_name = token;
348*0Sstevel@tonic-gate 
349*0Sstevel@tonic-gate 			/* key sizes */
350*0Sstevel@tonic-gate 			token = strtok_r(NULL, pipechar, &lasts);
351*0Sstevel@tonic-gate 			if (token == NULL) {
352*0Sstevel@tonic-gate 				snprintf(diag_buf, sizeof (diag_buf),
353*0Sstevel@tonic-gate 				    "cannot read key sizes for alg %d "
354*0Sstevel@tonic-gate 				    "(proto %d)", alg_num,
355*0Sstevel@tonic-gate 				    new_proto->proto_num);
356*0Sstevel@tonic-gate 				goto bail;
357*0Sstevel@tonic-gate 			}
358*0Sstevel@tonic-gate 			key_string = token;
359*0Sstevel@tonic-gate 
360*0Sstevel@tonic-gate 			/* block sizes */
361*0Sstevel@tonic-gate 			token = strtok_r(NULL, pipechar, &lasts);
362*0Sstevel@tonic-gate 			if (token == NULL) {
363*0Sstevel@tonic-gate 				snprintf(diag_buf, sizeof (diag_buf),
364*0Sstevel@tonic-gate 				    "cannot read mechanism name for alg %d "
365*0Sstevel@tonic-gate 				    "(proto %d)", alg_num,
366*0Sstevel@tonic-gate 				    new_proto->proto_num);
367*0Sstevel@tonic-gate 				goto bail;
368*0Sstevel@tonic-gate 			}
369*0Sstevel@tonic-gate 			block_string = token;
370*0Sstevel@tonic-gate 
371*0Sstevel@tonic-gate 			/* extract key sizes */
372*0Sstevel@tonic-gate 			key_increment = build_keysizes(&key_sizes, key_string);
373*0Sstevel@tonic-gate 			if (key_increment == -1) {
374*0Sstevel@tonic-gate 				snprintf(diag_buf, sizeof (diag_buf),
375*0Sstevel@tonic-gate 				    "invalid key sizes for alg %d (proto %d)",
376*0Sstevel@tonic-gate 				    alg_num, new_proto->proto_num);
377*0Sstevel@tonic-gate 				goto bail;
378*0Sstevel@tonic-gate 			}
379*0Sstevel@tonic-gate 
380*0Sstevel@tonic-gate 			/* extract block sizes */
381*0Sstevel@tonic-gate 			block_sizes = (int *)malloc(sizeof (int));
382*0Sstevel@tonic-gate 			if (block_sizes == NULL) {
383*0Sstevel@tonic-gate 				free(key_sizes);
384*0Sstevel@tonic-gate 				goto bail;
385*0Sstevel@tonic-gate 			}
386*0Sstevel@tonic-gate 			num_sizes = 0;
387*0Sstevel@tonic-gate 			token = strtok_r(block_string, comma, &lasts);
388*0Sstevel@tonic-gate 			if (token == NULL) {
389*0Sstevel@tonic-gate 				snprintf(diag_buf, sizeof (diag_buf),
390*0Sstevel@tonic-gate 				    "invalid block sizes for alg %d (proto %d)",
391*0Sstevel@tonic-gate 				    alg_num, new_proto->proto_num);
392*0Sstevel@tonic-gate 				free(key_sizes);
393*0Sstevel@tonic-gate 				goto bail;
394*0Sstevel@tonic-gate 			}
395*0Sstevel@tonic-gate 			*block_sizes = 0;
396*0Sstevel@tonic-gate 			do {
397*0Sstevel@tonic-gate 				int *nbk;
398*0Sstevel@tonic-gate 
399*0Sstevel@tonic-gate 				nbk = (int *)realloc(block_sizes,
400*0Sstevel@tonic-gate 				    sizeof (int) * ((++num_sizes) + 1));
401*0Sstevel@tonic-gate 				if (nbk == NULL) {
402*0Sstevel@tonic-gate 					free(key_sizes);
403*0Sstevel@tonic-gate 					free(block_sizes);
404*0Sstevel@tonic-gate 					goto bail;
405*0Sstevel@tonic-gate 				}
406*0Sstevel@tonic-gate 				block_sizes = nbk;
407*0Sstevel@tonic-gate 				/* Can't check for 0 here... */
408*0Sstevel@tonic-gate 				block_sizes[num_sizes - 1] = atoi(token);
409*0Sstevel@tonic-gate 				block_sizes[num_sizes] = 0;
410*0Sstevel@tonic-gate 			} while ((token = strtok_r(NULL, comma, &lasts)) !=
411*0Sstevel@tonic-gate 			    NULL);
412*0Sstevel@tonic-gate 
413*0Sstevel@tonic-gate 			/* Allocate a new struct ipsecalgent. */
414*0Sstevel@tonic-gate 			curalg = (struct ipsecalgent *)calloc(
415*0Sstevel@tonic-gate 			    sizeof (struct ipsecalgent), 1);
416*0Sstevel@tonic-gate 			if (curalg == NULL) {
417*0Sstevel@tonic-gate 				free(key_sizes);
418*0Sstevel@tonic-gate 				free(block_sizes);
419*0Sstevel@tonic-gate 				goto bail;
420*0Sstevel@tonic-gate 			}
421*0Sstevel@tonic-gate 			curalg->a_proto_num = new_num;
422*0Sstevel@tonic-gate 			curalg->a_alg_num = alg_num;
423*0Sstevel@tonic-gate 			curalg->a_block_sizes = block_sizes;
424*0Sstevel@tonic-gate 			curalg->a_key_sizes = key_sizes;
425*0Sstevel@tonic-gate 			curalg->a_key_increment = key_increment;
426*0Sstevel@tonic-gate 			if ((curalg->a_mech_name = strdup(ef_name)) == NULL) {
427*0Sstevel@tonic-gate 				freeipsecalgent(curalg);
428*0Sstevel@tonic-gate 				goto bail;
429*0Sstevel@tonic-gate 			}
430*0Sstevel@tonic-gate 			/* Set names. */
431*0Sstevel@tonic-gate 			curalg->a_names = (char **)malloc(sizeof (char *));
432*0Sstevel@tonic-gate 			num_sizes = 0;	/* Recycle "sizes" */
433*0Sstevel@tonic-gate 			token = strtok_r(alg_names, comma, &lasts);
434*0Sstevel@tonic-gate 			if (curalg->a_names == NULL || token == NULL) {
435*0Sstevel@tonic-gate 				freeipsecalgent(curalg);
436*0Sstevel@tonic-gate 				goto bail;
437*0Sstevel@tonic-gate 			}
438*0Sstevel@tonic-gate 			do {
439*0Sstevel@tonic-gate 				char **nnames;
440*0Sstevel@tonic-gate 
441*0Sstevel@tonic-gate 				nnames = (char **)realloc(curalg->a_names,
442*0Sstevel@tonic-gate 				    sizeof (char *) * ((++num_sizes) + 1));
443*0Sstevel@tonic-gate 				if (nnames == NULL) {
444*0Sstevel@tonic-gate 					freeipsecalgent(curalg);
445*0Sstevel@tonic-gate 					goto bail;
446*0Sstevel@tonic-gate 				}
447*0Sstevel@tonic-gate 				curalg->a_names = nnames;
448*0Sstevel@tonic-gate 				curalg->a_names[num_sizes] = NULL;
449*0Sstevel@tonic-gate 				curalg->a_names[num_sizes - 1] =
450*0Sstevel@tonic-gate 				    strdup(token);
451*0Sstevel@tonic-gate 				if (curalg->a_names[num_sizes - 1] == NULL) {
452*0Sstevel@tonic-gate 					freeipsecalgent(curalg);
453*0Sstevel@tonic-gate 					goto bail;
454*0Sstevel@tonic-gate 				}
455*0Sstevel@tonic-gate 			} while ((token = strtok_r(NULL, comma, &lasts)) !=
456*0Sstevel@tonic-gate 			    NULL);
457*0Sstevel@tonic-gate 
458*0Sstevel@tonic-gate 			if (doing_pkg) {
459*0Sstevel@tonic-gate 				/* record alg as being part of current pkg */
460*0Sstevel@tonic-gate 				int npkgs = new_proto->proto_algs_npkgs;
461*0Sstevel@tonic-gate 
462*0Sstevel@tonic-gate 				new_proto->proto_algs_pkgs = realloc(
463*0Sstevel@tonic-gate 				    new_proto->proto_algs_pkgs,
464*0Sstevel@tonic-gate 				    (npkgs + 1) * sizeof (ipsecalgs_pkg_t));
465*0Sstevel@tonic-gate 				if (new_proto->proto_algs_pkgs == NULL)
466*0Sstevel@tonic-gate 					goto bail;
467*0Sstevel@tonic-gate 
468*0Sstevel@tonic-gate 				new_proto->proto_algs_pkgs[npkgs].alg_num =
469*0Sstevel@tonic-gate 					curalg->a_alg_num;
470*0Sstevel@tonic-gate 				new_proto->proto_algs_pkgs[npkgs].pkg_name =
471*0Sstevel@tonic-gate 					strdup(cur_pkg);
472*0Sstevel@tonic-gate 				if (new_proto->proto_algs_pkgs[npkgs].pkg_name
473*0Sstevel@tonic-gate 				    == NULL)
474*0Sstevel@tonic-gate 					goto bail;
475*0Sstevel@tonic-gate 
476*0Sstevel@tonic-gate 				new_proto->proto_algs_npkgs = npkgs + 1;
477*0Sstevel@tonic-gate 			}
478*0Sstevel@tonic-gate 
479*0Sstevel@tonic-gate 			/* add new alg to protocol */
480*0Sstevel@tonic-gate 			newalglist = realloc(new_proto->proto_algs,
481*0Sstevel@tonic-gate 			    (new_proto->proto_numalgs + 1) *
482*0Sstevel@tonic-gate 			    sizeof (struct ipsecalgent *));
483*0Sstevel@tonic-gate 			if (newalglist == NULL) {
484*0Sstevel@tonic-gate 				freeipsecalgent(curalg);
485*0Sstevel@tonic-gate 				goto bail;
486*0Sstevel@tonic-gate 			}
487*0Sstevel@tonic-gate 			newalglist[new_proto->proto_numalgs] = curalg;
488*0Sstevel@tonic-gate 			new_proto->proto_numalgs++;
489*0Sstevel@tonic-gate 			new_proto->proto_algs = newalglist;
490*0Sstevel@tonic-gate 
491*0Sstevel@tonic-gate 		} else if (strncasecmp(line, LIBIPSEC_ALGS_LINE_PKGSTART,
492*0Sstevel@tonic-gate 		    sizeof (LIBIPSEC_ALGS_LINE_PKGSTART) - 1) == 0) {
493*0Sstevel@tonic-gate 			/* start of package delimiter */
494*0Sstevel@tonic-gate 			if (doing_pkg) {
495*0Sstevel@tonic-gate 				snprintf(diag_buf, sizeof (diag_buf),
496*0Sstevel@tonic-gate 				    "duplicate package start delimiters");
497*0Sstevel@tonic-gate 				goto bail;
498*0Sstevel@tonic-gate 			}
499*0Sstevel@tonic-gate 			(void) strncpy(cur_pkg, line +
500*0Sstevel@tonic-gate 			    (sizeof (LIBIPSEC_ALGS_LINE_PKGSTART) - 1),
501*0Sstevel@tonic-gate 			    sizeof (cur_pkg));
502*0Sstevel@tonic-gate 			/* remove trailing '\n' */
503*0Sstevel@tonic-gate 			cur_pkg[strlen(cur_pkg) - 1] = '\0';
504*0Sstevel@tonic-gate 			doing_pkg = B_TRUE;
505*0Sstevel@tonic-gate 
506*0Sstevel@tonic-gate 		} else {
507*0Sstevel@tonic-gate 			/* end of package delimiter */
508*0Sstevel@tonic-gate 			char tmp_pkg[1024];
509*0Sstevel@tonic-gate 
510*0Sstevel@tonic-gate 			if (!doing_pkg) {
511*0Sstevel@tonic-gate 				snprintf(diag_buf, sizeof (diag_buf),
512*0Sstevel@tonic-gate 				    "end package delimiter without start");
513*0Sstevel@tonic-gate 				goto bail;
514*0Sstevel@tonic-gate 			}
515*0Sstevel@tonic-gate 			/*
516*0Sstevel@tonic-gate 			 * Get specified pkg name, fail if it doesn't match
517*0Sstevel@tonic-gate 			 * the package specified by the last # Begin.
518*0Sstevel@tonic-gate 			 */
519*0Sstevel@tonic-gate 			(void) strncpy(tmp_pkg, line +
520*0Sstevel@tonic-gate 			    (sizeof (LIBIPSEC_ALGS_LINE_PKGEND) - 1),
521*0Sstevel@tonic-gate 			    sizeof (tmp_pkg));
522*0Sstevel@tonic-gate 			/* remove trailing '\n' */
523*0Sstevel@tonic-gate 			tmp_pkg[strlen(tmp_pkg) - 1] = '\0';
524*0Sstevel@tonic-gate 			if (strncmp(cur_pkg, tmp_pkg, sizeof (cur_pkg)) != 0)
525*0Sstevel@tonic-gate 				goto bail;
526*0Sstevel@tonic-gate 			doing_pkg = B_FALSE;
527*0Sstevel@tonic-gate 		}
528*0Sstevel@tonic-gate 	}
529*0Sstevel@tonic-gate 
530*0Sstevel@tonic-gate 	*num = rc_num;
531*0Sstevel@tonic-gate 	return (rc);
532*0Sstevel@tonic-gate 
533*0Sstevel@tonic-gate bail:
534*0Sstevel@tonic-gate 	if (strlen(diag_buf) > 0) {
535*0Sstevel@tonic-gate 		syslog(LOG_ERR, "possibly corrupt %s file: %s\n",
536*0Sstevel@tonic-gate 		    INET_IPSECALGSFILE, diag_buf);
537*0Sstevel@tonic-gate 	}
538*0Sstevel@tonic-gate 	_clean_trash(rc, rc_num);
539*0Sstevel@tonic-gate 	return (NULL);
540*0Sstevel@tonic-gate }
541*0Sstevel@tonic-gate 
542*0Sstevel@tonic-gate /*
543*0Sstevel@tonic-gate  * If alg_context is NULL, update the library's cached copy of
544*0Sstevel@tonic-gate  * INET_IPSECALGSFILE.  If alg_context is non-NULL, hang a
545*0Sstevel@tonic-gate  * library-internal representation of a cached copy.  The latter is useful
546*0Sstevel@tonic-gate  * for routines in libipsecutil that _write_ the contents out.
547*0Sstevel@tonic-gate  */
548*0Sstevel@tonic-gate void
549*0Sstevel@tonic-gate _build_internal_algs(ipsec_proto_t **alg_context, int *alg_nums)
550*0Sstevel@tonic-gate {
551*0Sstevel@tonic-gate 	FILE *f = NULL;
552*0Sstevel@tonic-gate 	int fd, rc, trash_num;
553*0Sstevel@tonic-gate 	ipsec_proto_t *new_protos = NULL, *trash;
554*0Sstevel@tonic-gate 	time_t filetime;
555*0Sstevel@tonic-gate 	struct stat statbuf;
556*0Sstevel@tonic-gate 
557*0Sstevel@tonic-gate 	/*
558*0Sstevel@tonic-gate 	 * Construct new_protos from the file.
559*0Sstevel@tonic-gate 	 */
560*0Sstevel@tonic-gate 	if (alg_context == NULL) {
561*0Sstevel@tonic-gate 		/*
562*0Sstevel@tonic-gate 		 * Check the time w/o holding the lock.  This is just a
563*0Sstevel@tonic-gate 		 * cache reality check.  We'll do it again for real if this
564*0Sstevel@tonic-gate 		 * surface check fails.
565*0Sstevel@tonic-gate 		 */
566*0Sstevel@tonic-gate 		if (stat(INET_IPSECALGSFILE, &statbuf) == -1 ||
567*0Sstevel@tonic-gate 		    (statbuf.st_mtime < proto_last_update &&
568*0Sstevel@tonic-gate 			protos != NULL))
569*0Sstevel@tonic-gate 			return;
570*0Sstevel@tonic-gate 		rw_wrlock(&proto_rw);
571*0Sstevel@tonic-gate 	}
572*0Sstevel@tonic-gate 
573*0Sstevel@tonic-gate 	fd = open(INET_IPSECALGSFILE, O_RDONLY);
574*0Sstevel@tonic-gate 	if (fd != -1) {
575*0Sstevel@tonic-gate 		f = fdopen(fd, "r");
576*0Sstevel@tonic-gate 		if (f == NULL) {
577*0Sstevel@tonic-gate 			close(fd);
578*0Sstevel@tonic-gate 		} else {
579*0Sstevel@tonic-gate 			rc = fstat(fd, &statbuf);
580*0Sstevel@tonic-gate 			if (rc != -1) {
581*0Sstevel@tonic-gate 				/*
582*0Sstevel@tonic-gate 				 * Update if the file is newer than our
583*0Sstevel@tonic-gate 				 * last cached copy.
584*0Sstevel@tonic-gate 				 */
585*0Sstevel@tonic-gate 				filetime = statbuf.st_mtime;
586*0Sstevel@tonic-gate 				if (alg_context != NULL ||
587*0Sstevel@tonic-gate 				    filetime > proto_last_update)
588*0Sstevel@tonic-gate 					new_protos = build_list(f, &rc);
589*0Sstevel@tonic-gate 			}
590*0Sstevel@tonic-gate 		}
591*0Sstevel@tonic-gate 	}
592*0Sstevel@tonic-gate 
593*0Sstevel@tonic-gate 	if (alg_context == NULL) {
594*0Sstevel@tonic-gate 		/*
595*0Sstevel@tonic-gate 		 * If we have failed anywhere above, new_protoss will be NULL.
596*0Sstevel@tonic-gate 		 * This way, the previous cached protos will still be intact.
597*0Sstevel@tonic-gate 		 */
598*0Sstevel@tonic-gate 		if (new_protos != NULL) {
599*0Sstevel@tonic-gate 			proto_last_update = filetime;
600*0Sstevel@tonic-gate 			trash = protos;
601*0Sstevel@tonic-gate 			trash_num = num_protos;
602*0Sstevel@tonic-gate 			protos = new_protos;
603*0Sstevel@tonic-gate 			num_protos = rc;
604*0Sstevel@tonic-gate 		} else {
605*0Sstevel@tonic-gate 			/*
606*0Sstevel@tonic-gate 			 * Else the original protocols and algorithms lists
607*0Sstevel@tonic-gate 			 * remains the same.
608*0Sstevel@tonic-gate 			 */
609*0Sstevel@tonic-gate 			trash = NULL;
610*0Sstevel@tonic-gate 		}
611*0Sstevel@tonic-gate 		rw_unlock(&proto_rw);
612*0Sstevel@tonic-gate 		_clean_trash(trash, trash_num);
613*0Sstevel@tonic-gate 	} else {
614*0Sstevel@tonic-gate 		/*
615*0Sstevel@tonic-gate 		 * Assume caller has done the appropriate locking,
616*0Sstevel@tonic-gate 		 * cleanup, etc.  And if new_protos is NULL, it's the caller's
617*0Sstevel@tonic-gate 		 * problem.
618*0Sstevel@tonic-gate 		 */
619*0Sstevel@tonic-gate 		*alg_context = new_protos;
620*0Sstevel@tonic-gate 		*alg_nums = rc;
621*0Sstevel@tonic-gate 	}
622*0Sstevel@tonic-gate 
623*0Sstevel@tonic-gate 	/* Since f is read-only, can avoid all of the failures... */
624*0Sstevel@tonic-gate 	if (f != NULL)
625*0Sstevel@tonic-gate 		(void) fclose(f);
626*0Sstevel@tonic-gate }
627*0Sstevel@tonic-gate 
628*0Sstevel@tonic-gate /*
629*0Sstevel@tonic-gate  * Assume input is 0-terminated.
630*0Sstevel@tonic-gate  */
631*0Sstevel@tonic-gate static int *
632*0Sstevel@tonic-gate duplicate_intarr(int *orig)
633*0Sstevel@tonic-gate {
634*0Sstevel@tonic-gate 	size_t allocsize = sizeof (int);
635*0Sstevel@tonic-gate 	int *iwalker = orig;
636*0Sstevel@tonic-gate 
637*0Sstevel@tonic-gate 	if (orig == NULL)
638*0Sstevel@tonic-gate 		return (NULL);
639*0Sstevel@tonic-gate 
640*0Sstevel@tonic-gate 	while (*iwalker != 0) {
641*0Sstevel@tonic-gate 		allocsize += sizeof (int);
642*0Sstevel@tonic-gate 		iwalker++;
643*0Sstevel@tonic-gate 	}
644*0Sstevel@tonic-gate 
645*0Sstevel@tonic-gate 	iwalker = malloc(allocsize);
646*0Sstevel@tonic-gate 	if (iwalker != NULL)
647*0Sstevel@tonic-gate 		memcpy(iwalker, orig, allocsize);
648*0Sstevel@tonic-gate 
649*0Sstevel@tonic-gate 	return (iwalker);
650*0Sstevel@tonic-gate }
651*0Sstevel@tonic-gate 
652*0Sstevel@tonic-gate /*
653*0Sstevel@tonic-gate  * Assume input is NULL terminated.
654*0Sstevel@tonic-gate  */
655*0Sstevel@tonic-gate static char **
656*0Sstevel@tonic-gate duplicate_strarr(char **orig)
657*0Sstevel@tonic-gate {
658*0Sstevel@tonic-gate 	int i;
659*0Sstevel@tonic-gate 	char **swalker;
660*0Sstevel@tonic-gate 	char **newbie;
661*0Sstevel@tonic-gate 
662*0Sstevel@tonic-gate 	if (orig == NULL)
663*0Sstevel@tonic-gate 		return (NULL);
664*0Sstevel@tonic-gate 
665*0Sstevel@tonic-gate 	/* count number of elements in source array */
666*0Sstevel@tonic-gate 	for (swalker = orig; *swalker != NULL; swalker++);
667*0Sstevel@tonic-gate 
668*0Sstevel@tonic-gate 	/* use calloc() to get NULL-initialization */
669*0Sstevel@tonic-gate 	newbie = calloc(swalker - orig + 1, sizeof (char *));
670*0Sstevel@tonic-gate 
671*0Sstevel@tonic-gate 	if (newbie != NULL) {
672*0Sstevel@tonic-gate 		/* do the copy */
673*0Sstevel@tonic-gate 		for (i = 0; orig[i] != NULL; i++) {
674*0Sstevel@tonic-gate 			newbie[i] = strdup(orig[i]);
675*0Sstevel@tonic-gate 			if (newbie[i] == NULL) {
676*0Sstevel@tonic-gate 				for (swalker = newbie; *swalker != NULL;
677*0Sstevel@tonic-gate 				    swalker++)
678*0Sstevel@tonic-gate 					free(*swalker);
679*0Sstevel@tonic-gate 				free(newbie);
680*0Sstevel@tonic-gate 				return (NULL);
681*0Sstevel@tonic-gate 			}
682*0Sstevel@tonic-gate 		}
683*0Sstevel@tonic-gate 	}
684*0Sstevel@tonic-gate 
685*0Sstevel@tonic-gate 	return (newbie);
686*0Sstevel@tonic-gate }
687*0Sstevel@tonic-gate 
688*0Sstevel@tonic-gate struct ipsecalgent *
689*0Sstevel@tonic-gate _duplicate_alg(struct ipsecalgent *orig)
690*0Sstevel@tonic-gate {
691*0Sstevel@tonic-gate 	struct ipsecalgent *rc;
692*0Sstevel@tonic-gate 
693*0Sstevel@tonic-gate 	/* use calloc() to get NULL-initialization. */
694*0Sstevel@tonic-gate 	rc = calloc(1, sizeof (struct ipsecalgent));
695*0Sstevel@tonic-gate 	if (rc == NULL)
696*0Sstevel@tonic-gate 		return (NULL);
697*0Sstevel@tonic-gate 
698*0Sstevel@tonic-gate 	rc->a_proto_num = orig->a_proto_num;
699*0Sstevel@tonic-gate 	rc->a_alg_num = orig->a_alg_num;
700*0Sstevel@tonic-gate 	rc->a_key_increment = orig->a_key_increment;
701*0Sstevel@tonic-gate 	rc->a_mech_name = strdup(orig->a_mech_name);
702*0Sstevel@tonic-gate 	rc->a_block_sizes = duplicate_intarr(orig->a_block_sizes);
703*0Sstevel@tonic-gate 	rc->a_key_sizes = duplicate_intarr(orig->a_key_sizes);
704*0Sstevel@tonic-gate 	rc->a_names = duplicate_strarr(orig->a_names);
705*0Sstevel@tonic-gate 
706*0Sstevel@tonic-gate 	if (rc->a_mech_name == NULL || rc->a_block_sizes == NULL ||
707*0Sstevel@tonic-gate 	    rc->a_key_sizes == NULL || rc->a_names == NULL) {
708*0Sstevel@tonic-gate 		freeipsecalgent(rc);
709*0Sstevel@tonic-gate 		return (NULL);
710*0Sstevel@tonic-gate 	}
711*0Sstevel@tonic-gate 
712*0Sstevel@tonic-gate 	return (rc);
713*0Sstevel@tonic-gate }
714*0Sstevel@tonic-gate 
715*0Sstevel@tonic-gate /*
716*0Sstevel@tonic-gate  * Assume the rwlock is held for reading.
717*0Sstevel@tonic-gate  */
718*0Sstevel@tonic-gate static ipsec_proto_t *
719*0Sstevel@tonic-gate findprotobynum(int proto_num)
720*0Sstevel@tonic-gate {
721*0Sstevel@tonic-gate 	int i;
722*0Sstevel@tonic-gate 
723*0Sstevel@tonic-gate 	for (i = 0; i < num_protos; i++) {
724*0Sstevel@tonic-gate 		if (protos[i].proto_num == proto_num)
725*0Sstevel@tonic-gate 			return (protos + i);
726*0Sstevel@tonic-gate 	}
727*0Sstevel@tonic-gate 
728*0Sstevel@tonic-gate 	return (NULL);
729*0Sstevel@tonic-gate }
730*0Sstevel@tonic-gate 
731*0Sstevel@tonic-gate static ipsec_proto_t *
732*0Sstevel@tonic-gate findprotobyname(const char *name)
733*0Sstevel@tonic-gate {
734*0Sstevel@tonic-gate 	int i;
735*0Sstevel@tonic-gate 
736*0Sstevel@tonic-gate 	if (name == NULL)
737*0Sstevel@tonic-gate 		return (NULL);
738*0Sstevel@tonic-gate 
739*0Sstevel@tonic-gate 	for (i = 0; i < num_protos; i++) {
740*0Sstevel@tonic-gate 		/* Can use strcasecmp because our proto_name is bounded. */
741*0Sstevel@tonic-gate 		if (strcasecmp(protos[i].proto_name, name) == 0)
742*0Sstevel@tonic-gate 			return (protos + i);
743*0Sstevel@tonic-gate 	}
744*0Sstevel@tonic-gate 
745*0Sstevel@tonic-gate 	return (NULL);
746*0Sstevel@tonic-gate }
747*0Sstevel@tonic-gate 
748*0Sstevel@tonic-gate int *
749*0Sstevel@tonic-gate _real_getipsecprotos(int *nentries)
750*0Sstevel@tonic-gate {
751*0Sstevel@tonic-gate 	int *rc, i;
752*0Sstevel@tonic-gate 
753*0Sstevel@tonic-gate 	if (nentries == NULL)
754*0Sstevel@tonic-gate 		return (NULL);
755*0Sstevel@tonic-gate 
756*0Sstevel@tonic-gate 	_build_internal_algs(NULL, NULL);
757*0Sstevel@tonic-gate 
758*0Sstevel@tonic-gate 	rw_rdlock(&proto_rw);
759*0Sstevel@tonic-gate 	*nentries = num_protos;
760*0Sstevel@tonic-gate 	/*
761*0Sstevel@tonic-gate 	 * Allocate 1 byte if there are no protocols so a non-NULL return
762*0Sstevel@tonic-gate 	 * happens.
763*0Sstevel@tonic-gate 	 */
764*0Sstevel@tonic-gate 	rc = malloc((num_protos == 0) ? 1 : num_protos * sizeof (int));
765*0Sstevel@tonic-gate 	if (rc != NULL) {
766*0Sstevel@tonic-gate 		for (i = 0; i < num_protos; i++)
767*0Sstevel@tonic-gate 			rc[i] = protos[i].proto_num;
768*0Sstevel@tonic-gate 	}
769*0Sstevel@tonic-gate 	rw_unlock(&proto_rw);
770*0Sstevel@tonic-gate 	return (rc);
771*0Sstevel@tonic-gate }
772*0Sstevel@tonic-gate 
773*0Sstevel@tonic-gate int *
774*0Sstevel@tonic-gate _real_getipsecalgs(int *nentries, int proto_num)
775*0Sstevel@tonic-gate {
776*0Sstevel@tonic-gate 	int *rc = NULL, i;
777*0Sstevel@tonic-gate 	ipsec_proto_t *proto;
778*0Sstevel@tonic-gate 
779*0Sstevel@tonic-gate 	if (nentries == NULL)
780*0Sstevel@tonic-gate 		return (NULL);
781*0Sstevel@tonic-gate 
782*0Sstevel@tonic-gate 	_build_internal_algs(NULL, NULL);
783*0Sstevel@tonic-gate 
784*0Sstevel@tonic-gate 	rw_rdlock(&proto_rw);
785*0Sstevel@tonic-gate 	proto = findprotobynum(proto_num);
786*0Sstevel@tonic-gate 	if (proto != NULL) {
787*0Sstevel@tonic-gate 		*nentries = proto->proto_numalgs;
788*0Sstevel@tonic-gate 		/*
789*0Sstevel@tonic-gate 		 * Allocate 1 byte if there are no algorithms so a non-NULL
790*0Sstevel@tonic-gate 		 * return happens.
791*0Sstevel@tonic-gate 		 */
792*0Sstevel@tonic-gate 		rc = malloc((proto->proto_numalgs == 0) ? 1 :
793*0Sstevel@tonic-gate 		    proto->proto_numalgs * sizeof (int));
794*0Sstevel@tonic-gate 		if (rc != NULL) {
795*0Sstevel@tonic-gate 			for (i = 0; i < proto->proto_numalgs; i++)
796*0Sstevel@tonic-gate 				rc[i] = proto->proto_algs[i]->a_alg_num;
797*0Sstevel@tonic-gate 		}
798*0Sstevel@tonic-gate 	}
799*0Sstevel@tonic-gate 	rw_unlock(&proto_rw);
800*0Sstevel@tonic-gate 	return (rc);
801*0Sstevel@tonic-gate }
802*0Sstevel@tonic-gate 
803*0Sstevel@tonic-gate struct ipsecalgent *
804*0Sstevel@tonic-gate getipsecalgbyname(const char *name, int proto_num, int *errnop)
805*0Sstevel@tonic-gate {
806*0Sstevel@tonic-gate 	ipsec_proto_t *proto;
807*0Sstevel@tonic-gate 	struct ipsecalgent *rc = NULL;
808*0Sstevel@tonic-gate 	int i, my_errno = ENOENT;
809*0Sstevel@tonic-gate 	char **name_check;
810*0Sstevel@tonic-gate 
811*0Sstevel@tonic-gate 	_build_internal_algs(NULL, NULL);
812*0Sstevel@tonic-gate 	if (name == NULL) {
813*0Sstevel@tonic-gate 		my_errno = EFAULT;
814*0Sstevel@tonic-gate 		goto bail;
815*0Sstevel@tonic-gate 	}
816*0Sstevel@tonic-gate 
817*0Sstevel@tonic-gate 	rw_rdlock(&proto_rw);
818*0Sstevel@tonic-gate 	proto = findprotobynum(proto_num);
819*0Sstevel@tonic-gate 	if (proto != NULL) {
820*0Sstevel@tonic-gate 		for (i = 0; i < proto->proto_numalgs; i++) {
821*0Sstevel@tonic-gate 			for (name_check = proto->proto_algs[i]->a_names;
822*0Sstevel@tonic-gate 			    *name_check != NULL; name_check++) {
823*0Sstevel@tonic-gate 				/*
824*0Sstevel@tonic-gate 				 * Can use strcasecmp because our name_check
825*0Sstevel@tonic-gate 				 * is bounded.
826*0Sstevel@tonic-gate 				 */
827*0Sstevel@tonic-gate 				if (strcasecmp(*name_check, name) == 0) {
828*0Sstevel@tonic-gate 					/* found match */
829*0Sstevel@tonic-gate 					rc = _duplicate_alg(
830*0Sstevel@tonic-gate 					    proto->proto_algs[i]);
831*0Sstevel@tonic-gate 					my_errno = (rc == NULL) ? ENOMEM : 0;
832*0Sstevel@tonic-gate 					rw_unlock(&proto_rw);
833*0Sstevel@tonic-gate 					goto bail;
834*0Sstevel@tonic-gate 				}
835*0Sstevel@tonic-gate 			}
836*0Sstevel@tonic-gate 		}
837*0Sstevel@tonic-gate 	} else {
838*0Sstevel@tonic-gate 		my_errno = EINVAL;
839*0Sstevel@tonic-gate 	}
840*0Sstevel@tonic-gate 
841*0Sstevel@tonic-gate 	rw_unlock(&proto_rw);
842*0Sstevel@tonic-gate bail:
843*0Sstevel@tonic-gate 	if (errnop != NULL)
844*0Sstevel@tonic-gate 		*errnop = my_errno;
845*0Sstevel@tonic-gate 	return (rc);
846*0Sstevel@tonic-gate }
847*0Sstevel@tonic-gate 
848*0Sstevel@tonic-gate struct ipsecalgent *
849*0Sstevel@tonic-gate getipsecalgbynum(int alg_num, int proto_num, int *errnop)
850*0Sstevel@tonic-gate {
851*0Sstevel@tonic-gate 	ipsec_proto_t *proto;
852*0Sstevel@tonic-gate 	struct ipsecalgent *rc = NULL;
853*0Sstevel@tonic-gate 	int i, my_errno = ENOENT;
854*0Sstevel@tonic-gate 
855*0Sstevel@tonic-gate 	_build_internal_algs(NULL, NULL);
856*0Sstevel@tonic-gate 
857*0Sstevel@tonic-gate 	rw_rdlock(&proto_rw);
858*0Sstevel@tonic-gate 
859*0Sstevel@tonic-gate 	proto = findprotobynum(proto_num);
860*0Sstevel@tonic-gate 	if (proto != NULL) {
861*0Sstevel@tonic-gate 		for (i = 0; i < proto->proto_numalgs; i++) {
862*0Sstevel@tonic-gate 			if (proto->proto_algs[i]->a_alg_num == alg_num) {
863*0Sstevel@tonic-gate 				rc = _duplicate_alg(proto->proto_algs[i]);
864*0Sstevel@tonic-gate 				my_errno = (rc == NULL) ? ENOMEM : 0;
865*0Sstevel@tonic-gate 				break;
866*0Sstevel@tonic-gate 			}
867*0Sstevel@tonic-gate 		}
868*0Sstevel@tonic-gate 	} else {
869*0Sstevel@tonic-gate 		my_errno = EINVAL;
870*0Sstevel@tonic-gate 	}
871*0Sstevel@tonic-gate 
872*0Sstevel@tonic-gate 	rw_unlock(&proto_rw);
873*0Sstevel@tonic-gate 	if (errnop != NULL)
874*0Sstevel@tonic-gate 		*errnop = my_errno;
875*0Sstevel@tonic-gate 	return (rc);
876*0Sstevel@tonic-gate }
877*0Sstevel@tonic-gate 
878*0Sstevel@tonic-gate int
879*0Sstevel@tonic-gate getipsecprotobyname(const char *proto_name)
880*0Sstevel@tonic-gate {
881*0Sstevel@tonic-gate 	int rc = -1;
882*0Sstevel@tonic-gate 	ipsec_proto_t *proto;
883*0Sstevel@tonic-gate 
884*0Sstevel@tonic-gate 	_build_internal_algs(NULL, NULL);
885*0Sstevel@tonic-gate 
886*0Sstevel@tonic-gate 	rw_rdlock(&proto_rw);
887*0Sstevel@tonic-gate 	proto = findprotobyname(proto_name);
888*0Sstevel@tonic-gate 	if (proto != NULL)
889*0Sstevel@tonic-gate 		rc = proto->proto_num;
890*0Sstevel@tonic-gate 	rw_unlock(&proto_rw);
891*0Sstevel@tonic-gate 	return (rc);
892*0Sstevel@tonic-gate }
893*0Sstevel@tonic-gate 
894*0Sstevel@tonic-gate char *
895*0Sstevel@tonic-gate getipsecprotobynum(int proto_num)
896*0Sstevel@tonic-gate {
897*0Sstevel@tonic-gate 	ipsec_proto_t *proto;
898*0Sstevel@tonic-gate 	char *rc = NULL;
899*0Sstevel@tonic-gate 
900*0Sstevel@tonic-gate 	_build_internal_algs(NULL, NULL);
901*0Sstevel@tonic-gate 
902*0Sstevel@tonic-gate 	rw_rdlock(&proto_rw);
903*0Sstevel@tonic-gate 	proto = findprotobynum(proto_num);
904*0Sstevel@tonic-gate 	if (proto != NULL)
905*0Sstevel@tonic-gate 		rc = strdup(proto->proto_name);
906*0Sstevel@tonic-gate 
907*0Sstevel@tonic-gate 	rw_unlock(&proto_rw);
908*0Sstevel@tonic-gate 	return (rc);
909*0Sstevel@tonic-gate }
910*0Sstevel@tonic-gate 
911*0Sstevel@tonic-gate void
912*0Sstevel@tonic-gate freeipsecalgent(struct ipsecalgent *ptr)
913*0Sstevel@tonic-gate {
914*0Sstevel@tonic-gate 	char **walker;
915*0Sstevel@tonic-gate 
916*0Sstevel@tonic-gate 	if (ptr == NULL)
917*0Sstevel@tonic-gate 		return;
918*0Sstevel@tonic-gate 
919*0Sstevel@tonic-gate 	if (ptr->a_names != NULL) {
920*0Sstevel@tonic-gate 		for (walker = ptr->a_names; *walker != NULL; walker++)
921*0Sstevel@tonic-gate 			free(*walker);
922*0Sstevel@tonic-gate 	}
923*0Sstevel@tonic-gate 
924*0Sstevel@tonic-gate 	/*
925*0Sstevel@tonic-gate 	 * Remember folks, free(NULL) works.
926*0Sstevel@tonic-gate 	 */
927*0Sstevel@tonic-gate 	free(ptr->a_names);
928*0Sstevel@tonic-gate 	free(ptr->a_mech_name);
929*0Sstevel@tonic-gate 	free(ptr->a_block_sizes);
930*0Sstevel@tonic-gate 	free(ptr->a_key_sizes);
931*0Sstevel@tonic-gate 	free(ptr);
932*0Sstevel@tonic-gate }
933