xref: /openbsd-src/lib/libcrypto/stack/stack.c (revision f6aab3d83b51b91c24247ad2c2573574de475a82)
1 /* $OpenBSD: stack.c,v 1.23 2023/04/24 15:35:22 beck Exp $ */
2 /* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
3  * All rights reserved.
4  *
5  * This package is an SSL implementation written
6  * by Eric Young (eay@cryptsoft.com).
7  * The implementation was written so as to conform with Netscapes SSL.
8  *
9  * This library is free for commercial and non-commercial use as long as
10  * the following conditions are aheared to.  The following conditions
11  * apply to all code found in this distribution, be it the RC4, RSA,
12  * lhash, DES, etc., code; not just the SSL code.  The SSL documentation
13  * included with this distribution is covered by the same copyright terms
14  * except that the holder is Tim Hudson (tjh@cryptsoft.com).
15  *
16  * Copyright remains Eric Young's, and as such any Copyright notices in
17  * the code are not to be removed.
18  * If this package is used in a product, Eric Young should be given attribution
19  * as the author of the parts of the library used.
20  * This can be in the form of a textual message at program startup or
21  * in documentation (online or textual) provided with the package.
22  *
23  * Redistribution and use in source and binary forms, with or without
24  * modification, are permitted provided that the following conditions
25  * are met:
26  * 1. Redistributions of source code must retain the copyright
27  *    notice, this list of conditions and the following disclaimer.
28  * 2. Redistributions in binary form must reproduce the above copyright
29  *    notice, this list of conditions and the following disclaimer in the
30  *    documentation and/or other materials provided with the distribution.
31  * 3. All advertising materials mentioning features or use of this software
32  *    must display the following acknowledgement:
33  *    "This product includes cryptographic software written by
34  *     Eric Young (eay@cryptsoft.com)"
35  *    The word 'cryptographic' can be left out if the rouines from the library
36  *    being used are not cryptographic related :-).
37  * 4. If you include any Windows specific code (or a derivative thereof) from
38  *    the apps directory (application code) you must include an acknowledgement:
39  *    "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
40  *
41  * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
42  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
43  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
44  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
45  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
46  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
47  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
48  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
49  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
50  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
51  * SUCH DAMAGE.
52  *
53  * The licence and distribution terms for any publically available version or
54  * derivative of this code cannot be changed.  i.e. this code cannot simply be
55  * copied and put under another distribution licence
56  * [including the GNU Public Licence.]
57  */
58 
59 #include <stdio.h>
60 #include <string.h>
61 
62 #include <openssl/objects.h>
63 #include <openssl/stack.h>
64 
65 #undef MIN_NODES
66 #define MIN_NODES	4
67 
68 #include <errno.h>
69 
70 int
71 (*sk_set_cmp_func(_STACK *sk, int (*c)(const void *, const void *)))(
72     const void *, const void *)
73 {
74 	int (*old)(const void *, const void *) = sk->comp;
75 
76 	if (sk->comp != c)
77 		sk->sorted = 0;
78 	sk->comp = c;
79 
80 	return old;
81 }
82 LCRYPTO_ALIAS(sk_set_cmp_func);
83 
84 _STACK *
85 sk_dup(_STACK *sk)
86 {
87 	_STACK *ret;
88 	char **s;
89 
90 	if ((ret = sk_new(sk->comp)) == NULL)
91 		goto err;
92 	s = reallocarray(ret->data, sk->num_alloc, sizeof(char *));
93 	if (s == NULL)
94 		goto err;
95 	ret->data = s;
96 
97 	ret->num = sk->num;
98 	memcpy(ret->data, sk->data, sizeof(char *) * sk->num);
99 	ret->sorted = sk->sorted;
100 	ret->num_alloc = sk->num_alloc;
101 	ret->comp = sk->comp;
102 	return (ret);
103 
104 err:
105 	if (ret)
106 		sk_free(ret);
107 	return (NULL);
108 }
109 LCRYPTO_ALIAS(sk_dup);
110 
111 _STACK *
112 sk_new_null(void)
113 {
114 	return sk_new((int (*)(const void *, const void *))0);
115 }
116 LCRYPTO_ALIAS(sk_new_null);
117 
118 _STACK *
119 sk_new(int (*c)(const void *, const void *))
120 {
121 	_STACK *ret;
122 	int i;
123 
124 	if ((ret = malloc(sizeof(_STACK))) == NULL)
125 		goto err;
126 	if ((ret->data = reallocarray(NULL, MIN_NODES, sizeof(char *))) == NULL)
127 		goto err;
128 	for (i = 0; i < MIN_NODES; i++)
129 		ret->data[i] = NULL;
130 	ret->comp = c;
131 	ret->num_alloc = MIN_NODES;
132 	ret->num = 0;
133 	ret->sorted = 0;
134 	return (ret);
135 
136 err:
137 	free(ret);
138 	return (NULL);
139 }
140 LCRYPTO_ALIAS(sk_new);
141 
142 int
143 sk_insert(_STACK *st, void *data, int loc)
144 {
145 	char **s;
146 
147 	if (st == NULL)
148 		return 0;
149 	if (st->num_alloc <= st->num + 1) {
150 		s = reallocarray(st->data, st->num_alloc, 2 * sizeof(char *));
151 		if (s == NULL)
152 			return (0);
153 		st->data = s;
154 		st->num_alloc *= 2;
155 	}
156 	if ((loc >= (int)st->num) || (loc < 0))
157 		st->data[st->num] = data;
158 	else {
159 		memmove(&(st->data[loc + 1]), &(st->data[loc]),
160 		    sizeof(char *)*(st->num - loc));
161 		st->data[loc] = data;
162 	}
163 	st->num++;
164 	st->sorted = 0;
165 	return (st->num);
166 }
167 LCRYPTO_ALIAS(sk_insert);
168 
169 void *
170 sk_delete_ptr(_STACK *st, void *p)
171 {
172 	int i;
173 
174 	for (i = 0; i < st->num; i++)
175 		if (st->data[i] == p)
176 			return (sk_delete(st, i));
177 	return (NULL);
178 }
179 LCRYPTO_ALIAS(sk_delete_ptr);
180 
181 void *
182 sk_delete(_STACK *st, int loc)
183 {
184 	char *ret;
185 
186 	if (!st || (loc < 0) || (loc >= st->num))
187 		return NULL;
188 
189 	ret = st->data[loc];
190 	if (loc != st->num - 1) {
191 		memmove(&(st->data[loc]), &(st->data[loc + 1]),
192 		    sizeof(char *)*(st->num - 1 - loc));
193 	}
194 	st->num--;
195 	return (ret);
196 }
197 LCRYPTO_ALIAS(sk_delete);
198 
199 static int
200 internal_find(_STACK *st, void *data, int ret_val_options)
201 {
202 	const void * const *r;
203 	int i;
204 
205 	if (st == NULL)
206 		return -1;
207 
208 	if (st->comp == NULL) {
209 		for (i = 0; i < st->num; i++)
210 			if (st->data[i] == data)
211 				return (i);
212 		return (-1);
213 	}
214 	sk_sort(st);
215 	if (data == NULL)
216 		return (-1);
217 	r = OBJ_bsearch_ex_(&data, st->data, st->num, sizeof(void *), st->comp,
218 	    ret_val_options);
219 	if (r == NULL)
220 		return (-1);
221 	return (int)((char **)r - st->data);
222 }
223 
224 int
225 sk_find(_STACK *st, void *data)
226 {
227 	return internal_find(st, data, OBJ_BSEARCH_FIRST_VALUE_ON_MATCH);
228 }
229 LCRYPTO_ALIAS(sk_find);
230 
231 int
232 sk_find_ex(_STACK *st, void *data)
233 {
234 	return internal_find(st, data, OBJ_BSEARCH_VALUE_ON_NOMATCH);
235 }
236 LCRYPTO_ALIAS(sk_find_ex);
237 
238 int
239 sk_push(_STACK *st, void *data)
240 {
241 	return (sk_insert(st, data, st->num));
242 }
243 LCRYPTO_ALIAS(sk_push);
244 
245 int
246 sk_unshift(_STACK *st, void *data)
247 {
248 	return (sk_insert(st, data, 0));
249 }
250 LCRYPTO_ALIAS(sk_unshift);
251 
252 void *
253 sk_shift(_STACK *st)
254 {
255 	if (st == NULL)
256 		return (NULL);
257 	if (st->num <= 0)
258 		return (NULL);
259 	return (sk_delete(st, 0));
260 }
261 LCRYPTO_ALIAS(sk_shift);
262 
263 void *
264 sk_pop(_STACK *st)
265 {
266 	if (st == NULL)
267 		return (NULL);
268 	if (st->num <= 0)
269 		return (NULL);
270 	return (sk_delete(st, st->num - 1));
271 }
272 LCRYPTO_ALIAS(sk_pop);
273 
274 void
275 sk_zero(_STACK *st)
276 {
277 	if (st == NULL)
278 		return;
279 	if (st->num <= 0)
280 		return;
281 	memset(st->data, 0, sizeof(st->data)*st->num);
282 	st->num = 0;
283 }
284 LCRYPTO_ALIAS(sk_zero);
285 
286 void
287 sk_pop_free(_STACK *st, void (*func)(void *))
288 {
289 	int i;
290 
291 	if (st == NULL)
292 		return;
293 	for (i = 0; i < st->num; i++)
294 		if (st->data[i] != NULL)
295 			func(st->data[i]);
296 	sk_free(st);
297 }
298 LCRYPTO_ALIAS(sk_pop_free);
299 
300 void
301 sk_free(_STACK *st)
302 {
303 	if (st == NULL)
304 		return;
305 	free(st->data);
306 	free(st);
307 }
308 LCRYPTO_ALIAS(sk_free);
309 
310 int
311 sk_num(const _STACK *st)
312 {
313 	if (st == NULL)
314 		return -1;
315 	return st->num;
316 }
317 LCRYPTO_ALIAS(sk_num);
318 
319 void *
320 sk_value(const _STACK *st, int i)
321 {
322 	if (!st || (i < 0) || (i >= st->num))
323 		return NULL;
324 	return st->data[i];
325 }
326 LCRYPTO_ALIAS(sk_value);
327 
328 void *
329 sk_set(_STACK *st, int i, void *value)
330 {
331 	if (!st || (i < 0) || (i >= st->num))
332 		return NULL;
333 	st->sorted = 0;
334 	return (st->data[i] = value);
335 }
336 LCRYPTO_ALIAS(sk_set);
337 
338 void
339 sk_sort(_STACK *st)
340 {
341 	if (st && !st->sorted) {
342 		int (*comp_func)(const void *, const void *);
343 
344 		/* same comment as in sk_find ... previously st->comp was declared
345 		 * as a (void*,void*) callback type, but this made the population
346 		 * of the callback pointer illogical - our callbacks compare
347 		 * type** with type**, so we leave the casting until absolutely
348 		 * necessary (ie. "now"). */
349 		comp_func = (int (*)(const void *, const void *))(st->comp);
350 		qsort(st->data, st->num, sizeof(char *), comp_func);
351 		st->sorted = 1;
352 	}
353 }
354 LCRYPTO_ALIAS(sk_sort);
355 
356 int
357 sk_is_sorted(const _STACK *st)
358 {
359 	if (st == NULL)
360 		return 1;
361 
362 	if (st->sorted)
363 		return 1;
364 
365 	/* If there is no comparison function we cannot sort. */
366 	if (st->comp == NULL)
367 		return 0;
368 
369 	/* Lists with zero or one elements are always sorted. */
370 	return st->num <= 1;
371 }
372 LCRYPTO_ALIAS(sk_is_sorted);
373