GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: lib/libcrypto/objects/o_names.c Lines: 109 163 66.9 %
Date: 2017-11-13 Branches: 35 80 43.8 %

Line Branch Exec Source
1
/* $OpenBSD: o_names.c,v 1.22 2017/01/29 17:49:23 beck Exp $ */
2
#include <stdio.h>
3
#include <stdlib.h>
4
#include <string.h>
5
6
#include <openssl/opensslconf.h>
7
8
#include <openssl/err.h>
9
#include <openssl/lhash.h>
10
#include <openssl/objects.h>
11
#include <openssl/safestack.h>
12
13
/* I use the ex_data stuff to manage the identifiers for the obj_name_types
14
 * that applications may define.  I only really use the free function field.
15
 */
16
DECLARE_LHASH_OF(OBJ_NAME);
17
static LHASH_OF(OBJ_NAME) *names_lh = NULL;
18
static int names_type_num = OBJ_NAME_TYPE_NUM;
19
20
typedef struct name_funcs_st {
21
	unsigned long (*hash_func)(const char *name);
22
	int (*cmp_func)(const char *a, const char *b);
23
	void (*free_func)(const char *, int, const char *);
24
} NAME_FUNCS;
25
26
DECLARE_STACK_OF(NAME_FUNCS)
27
28
static STACK_OF(NAME_FUNCS) *name_funcs_stack;
29
30
/* The LHASH callbacks now use the raw "void *" prototypes and do per-variable
31
 * casting in the functions. This prevents function pointer casting without the
32
 * need for macro-generated wrapper functions. */
33
34
/* static unsigned long obj_name_hash(OBJ_NAME *a); */
35
static unsigned long obj_name_hash(const void *a_void);
36
/* static int obj_name_cmp(OBJ_NAME *a,OBJ_NAME *b); */
37
static int obj_name_cmp(const void *a_void, const void *b_void);
38
39
2199906
static IMPLEMENT_LHASH_HASH_FN(obj_name, OBJ_NAME)
40
1187420
static IMPLEMENT_LHASH_COMP_FN(obj_name, OBJ_NAME)
41
42
int
43
OBJ_NAME_init(void)
44
{
45
5850
	if (names_lh != NULL)
46
		return (1);
47
2925
	names_lh = lh_OBJ_NAME_new();
48
2925
	return (names_lh != NULL);
49
2925
}
50
51
int
52
OBJ_NAME_new_index(unsigned long (*hash_func)(const char *),
53
    int (*cmp_func)(const char *, const char *),
54
    void (*free_func)(const char *, int, const char *))
55
{
56
	int ret;
57
	int i;
58
	NAME_FUNCS *name_funcs;
59
60
	if (name_funcs_stack == NULL)
61
		name_funcs_stack = sk_NAME_FUNCS_new_null();
62
	if (name_funcs_stack == NULL)
63
		return (0);
64
65
	ret = names_type_num;
66
	names_type_num++;
67
	for (i = sk_NAME_FUNCS_num(name_funcs_stack); i < names_type_num; i++) {
68
		name_funcs = malloc(sizeof(NAME_FUNCS));
69
		if (!name_funcs) {
70
			OBJerror(ERR_R_MALLOC_FAILURE);
71
			return (0);
72
		}
73
		name_funcs->hash_func = lh_strhash;
74
		name_funcs->cmp_func = strcmp;
75
		name_funcs->free_func = NULL;
76
		if (sk_NAME_FUNCS_push(name_funcs_stack, name_funcs) == 0) {
77
			free(name_funcs);
78
			OBJerror(ERR_R_MALLOC_FAILURE);
79
			return (0);
80
		}
81
	}
82
	name_funcs = sk_NAME_FUNCS_value(name_funcs_stack, ret);
83
	if (hash_func != NULL)
84
		name_funcs->hash_func = hash_func;
85
	if (cmp_func != NULL)
86
		name_funcs->cmp_func = cmp_func;
87
	if (free_func != NULL)
88
		name_funcs->free_func = free_func;
89
	return (ret);
90
}
91
92
/* static int obj_name_cmp(OBJ_NAME *a, OBJ_NAME *b) */
93
static int
94
obj_name_cmp(const void *a_void, const void *b_void)
95
{
96
	int ret;
97
1187420
	const OBJ_NAME *a = (const OBJ_NAME *)a_void;
98
593710
	const OBJ_NAME *b = (const OBJ_NAME *)b_void;
99
100
593710
	ret = a->type - b->type;
101
593710
	if (ret == 0) {
102

593710
		if ((name_funcs_stack != NULL) &&
103
		    (sk_NAME_FUNCS_num(name_funcs_stack) > a->type)) {
104
			ret = sk_NAME_FUNCS_value(name_funcs_stack,
105
			    a->type)->cmp_func(a->name, b->name);
106
		} else
107
593710
			ret = strcmp(a->name, b->name);
108
	}
109
593710
	return (ret);
110
}
111
112
/* static unsigned long obj_name_hash(OBJ_NAME *a) */
113
static unsigned long
114
obj_name_hash(const void *a_void)
115
{
116
	unsigned long ret;
117
2199906
	const OBJ_NAME *a = (const OBJ_NAME *)a_void;
118
119

1099953
	if ((name_funcs_stack != NULL) &&
120
	    (sk_NAME_FUNCS_num(name_funcs_stack) > a->type)) {
121
		ret = sk_NAME_FUNCS_value(name_funcs_stack,
122
		    a->type)->hash_func(a->name);
123
	} else {
124
1099953
		ret = lh_strhash(a->name);
125
	}
126
1099953
	ret ^= a->type;
127
1099953
	return (ret);
128
}
129
130
const char *
131
OBJ_NAME_get(const char *name, int type)
132
{
133
106418
	OBJ_NAME on, *ret;
134
	int num = 0, alias;
135
136
53209
	if (name == NULL)
137
		return (NULL);
138

53209
	if ((names_lh == NULL) && !OBJ_NAME_init())
139
		return (NULL);
140
141
53209
	alias = type&OBJ_NAME_ALIAS;
142
53209
	type&= ~OBJ_NAME_ALIAS;
143
144
53209
	on.name = name;
145
53209
	on.type = type;
146
147
53251
	for (;;) {
148
53251
		ret = lh_OBJ_NAME_retrieve(names_lh, &on);
149
53251
		if (ret == NULL)
150
872
			return (NULL);
151
52379
		if ((ret->alias) && !alias) {
152
42
			if (++num > 10)
153
				return (NULL);
154
42
			on.name = ret->data;
155
		} else {
156
52337
			return (ret->data);
157
		}
158
	}
159
53209
}
160
161
int
162
OBJ_NAME_add(const char *name, int type, const char *data)
163
{
164
	OBJ_NAME *onp, *ret;
165
	int alias;
166
167

1340551
	if ((names_lh == NULL) && !OBJ_NAME_init())
168
		return (0);
169
170
668813
	alias = type & OBJ_NAME_ALIAS;
171
668813
	type &= ~OBJ_NAME_ALIAS;
172
173
668813
	onp = malloc(sizeof(OBJ_NAME));
174
668813
	if (onp == NULL) {
175
		/* ERROR */
176
		return (0);
177
	}
178
179
668813
	onp->name = name;
180
668813
	onp->alias = alias;
181
668813
	onp->type = type;
182
668813
	onp->data = data;
183
184
668813
	ret = lh_OBJ_NAME_insert(names_lh, onp);
185
668813
	if (ret != NULL) {
186
		/* free things */
187

163442
		if ((name_funcs_stack != NULL) &&
188
		    (sk_NAME_FUNCS_num(name_funcs_stack) > ret->type)) {
189
			/* XXX: I'm not sure I understand why the free
190
			 * function should get three arguments...
191
			 * -- Richard Levitte
192
			 */
193
			sk_NAME_FUNCS_value(
194
			    name_funcs_stack, ret->type)->free_func(
195
			    ret->name, ret->type, ret->data);
196
		}
197
163442
		free(ret);
198
163442
	} else {
199
505371
		if (lh_OBJ_NAME_error(names_lh)) {
200
			/* ERROR */
201
			return (0);
202
		}
203
	}
204
668813
	return (1);
205
668813
}
206
207
int
208
OBJ_NAME_remove(const char *name, int type)
209
{
210
755778
	OBJ_NAME on, *ret;
211
212
377889
	if (names_lh == NULL)
213
		return (0);
214
215
377889
	type &= ~OBJ_NAME_ALIAS;
216
377889
	on.name = name;
217
377889
	on.type = type;
218
377889
	ret = lh_OBJ_NAME_delete(names_lh, &on);
219
377889
	if (ret != NULL) {
220
		/* free things */
221

377889
		if ((name_funcs_stack != NULL) &&
222
		    (sk_NAME_FUNCS_num(name_funcs_stack) > ret->type)) {
223
			/* XXX: I'm not sure I understand why the free
224
			 * function should get three arguments...
225
			 * -- Richard Levitte
226
			 */
227
			sk_NAME_FUNCS_value(
228
			    name_funcs_stack, ret->type)->free_func(
229
			    ret->name, ret->type, ret->data);
230
		}
231
377889
		free(ret);
232
377889
		return (1);
233
	} else
234
		return (0);
235
377889
}
236
237
struct doall {
238
	int type;
239
	void (*fn)(const OBJ_NAME *, void *arg);
240
	void *arg;
241
};
242
243
static void
244
do_all_fn_doall_arg(const OBJ_NAME *name, struct doall *d)
245
{
246
9932
	if (name->type == d->type)
247
3564
		d->fn(name, d->arg);
248
4966
}
249
250
9932
static IMPLEMENT_LHASH_DOALL_ARG_FN(do_all_fn, const OBJ_NAME, struct doall)
251
252
void
253
OBJ_NAME_do_all(int type, void (*fn)(const OBJ_NAME *, void *arg), void *arg)
254
{
255
72
	struct doall d;
256
257
36
	d.type = type;
258
36
	d.fn = fn;
259
36
	d.arg = arg;
260
261
36
	lh_OBJ_NAME_doall_arg(names_lh, LHASH_DOALL_ARG_FN(do_all_fn),
262
	    struct doall, &d);
263
36
}
264
265
struct doall_sorted {
266
	int type;
267
	int n;
268
	const OBJ_NAME **names;
269
};
270
271
static void
272
do_all_sorted_fn(const OBJ_NAME *name, void *d_)
273
{
274
4532
	struct doall_sorted *d = d_;
275
276
2266
	if (name->type != d->type)
277
		return;
278
279
2266
	d->names[d->n++] = name;
280
4532
}
281
282
static int
283
do_all_sorted_cmp(const void *n1_, const void *n2_)
284
{
285
32276
	const OBJ_NAME * const *n1 = n1_;
286
16138
	const OBJ_NAME * const *n2 = n2_;
287
288
16138
	return strcmp((*n1)->name, (*n2)->name);
289
}
290
291
void
292
OBJ_NAME_do_all_sorted(int type, void (*fn)(const OBJ_NAME *, void *arg),
293
    void *arg)
294
{
295
28
	struct doall_sorted d;
296
	int n;
297
298
14
	d.type = type;
299
14
	d.names = reallocarray(NULL, lh_OBJ_NAME_num_items(names_lh),
300
	    sizeof *d.names);
301
14
	d.n = 0;
302
14
	if (d.names != NULL) {
303
14
		OBJ_NAME_do_all(type, do_all_sorted_fn, &d);
304
305
14
		qsort((void *)d.names, d.n, sizeof *d.names, do_all_sorted_cmp);
306
307
4560
		for (n = 0; n < d.n; ++n)
308
2266
			fn(d.names[n], arg);
309
310
14
		free(d.names);
311
14
	}
312
14
}
313
314
static int free_type;
315
316
static void
317
names_lh_free_doall(OBJ_NAME *onp)
318
{
319
934682
	if (onp == NULL)
320
		return;
321
322

934682
	if (free_type < 0 || free_type == onp->type)
323
377889
		OBJ_NAME_remove(onp->name, onp->type);
324
467341
}
325
326
934682
static IMPLEMENT_LHASH_DOALL_FN(names_lh_free, OBJ_NAME)
327
328
static void
329
name_funcs_free(NAME_FUNCS *ptr)
330
{
331
	free(ptr);
332
}
333
334
void
335
OBJ_NAME_cleanup(int type)
336
{
337
	unsigned long down_load;
338
339
9408
	if (names_lh == NULL)
340
		return;
341
342
4704
	free_type = type;
343
4704
	down_load = lh_OBJ_NAME_down_load(names_lh);
344
4704
	lh_OBJ_NAME_down_load(names_lh) = 0;
345
346
4704
	lh_OBJ_NAME_doall(names_lh, LHASH_DOALL_FN(names_lh_free));
347
4704
	if (type < 0) {
348
1568
		lh_OBJ_NAME_free(names_lh);
349
1568
		sk_NAME_FUNCS_pop_free(name_funcs_stack, name_funcs_free);
350
1568
		names_lh = NULL;
351
1568
		name_funcs_stack = NULL;
352
1568
	} else
353
3136
		lh_OBJ_NAME_down_load(names_lh) = down_load;
354
9408
}