GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: lib/libcrypto/crypto/../../libssl/src/crypto/objects/o_names.c Lines: 78 143 54.5 %
Date: 2016-12-06 Branches: 29 80 36.3 %

Line Branch Exec Source
1
/* $OpenBSD: o_names.c,v 1.21 2015/07/18 21:21:28 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
6936
static IMPLEMENT_LHASH_HASH_FN(obj_name, OBJ_NAME)
40
3570
static IMPLEMENT_LHASH_COMP_FN(obj_name, OBJ_NAME)
41
42
int
43
OBJ_NAME_init(void)
44
15
{
45
15
	if (names_lh != NULL)
46
		return (1);
47
15
	names_lh = lh_OBJ_NAME_new();
48
15
	return (names_lh != NULL);
49
}
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
			OBJerr(OBJ_F_OBJ_NAME_NEW_INDEX, 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
			OBJerr(OBJ_F_OBJ_NAME_NEW_INDEX, 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
3570
{
96
	int ret;
97
3570
	const OBJ_NAME *a = (const OBJ_NAME *)a_void;
98
3570
	const OBJ_NAME *b = (const OBJ_NAME *)b_void;
99
100
3570
	ret = a->type - b->type;
101
3570
	if (ret == 0) {
102

3570
		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
3570
			ret = strcmp(a->name, b->name);
108
	}
109
3570
	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
6936
{
116
	unsigned long ret;
117
6936
	const OBJ_NAME *a = (const OBJ_NAME *)a_void;
118
119

6936
	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
6936
		ret = lh_strhash(a->name);
125
	}
126
6936
	ret ^= a->type;
127
6936
	return (ret);
128
}
129
130
const char *
131
OBJ_NAME_get(const char *name, int type)
132
498
{
133
	OBJ_NAME on, *ret;
134
498
	int num = 0, alias;
135
136
498
	if (name == NULL)
137
		return (NULL);
138

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

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

702
		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
702
		free(ret);
198
	} else {
199
3335
		if (lh_OBJ_NAME_error(names_lh)) {
200
			/* ERROR */
201
			return (0);
202
		}
203
	}
204
4037
	return (1);
205
}
206
207
int
208
OBJ_NAME_remove(const char *name, int type)
209
2397
{
210
	OBJ_NAME on, *ret;
211
212
2397
	if (names_lh == NULL)
213
		return (0);
214
215
2397
	type &= ~OBJ_NAME_ALIAS;
216
2397
	on.name = name;
217
2397
	on.type = type;
218
2397
	ret = lh_OBJ_NAME_delete(names_lh, &on);
219
2397
	if (ret != NULL) {
220
		/* free things */
221

2397
		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
2397
		free(ret);
232
2397
		return (1);
233
	} else
234
		return (0);
235
}
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
	if (name->type == d->type)
247
		d->fn(name, d->arg);
248
}
249
250
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
	struct doall d;
256
257
	d.type = type;
258
	d.fn = fn;
259
	d.arg = arg;
260
261
	lh_OBJ_NAME_doall_arg(names_lh, LHASH_DOALL_ARG_FN(do_all_fn),
262
	    struct doall, &d);
263
}
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
	struct doall_sorted *d = d_;
275
276
	if (name->type != d->type)
277
		return;
278
279
	d->names[d->n++] = name;
280
}
281
282
static int
283
do_all_sorted_cmp(const void *n1_, const void *n2_)
284
{
285
	const OBJ_NAME * const *n1 = n1_;
286
	const OBJ_NAME * const *n2 = n2_;
287
288
	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
	struct doall_sorted d;
296
	int n;
297
298
	d.type = type;
299
	d.names = reallocarray(NULL, lh_OBJ_NAME_num_items(names_lh),
300
	    sizeof *d.names);
301
	d.n = 0;
302
	if (d.names != NULL) {
303
		OBJ_NAME_do_all(type, do_all_sorted_fn, &d);
304
305
		qsort((void *)d.names, d.n, sizeof *d.names, do_all_sorted_cmp);
306
307
		for (n = 0; n < d.n; ++n)
308
			fn(d.names[n], arg);
309
310
		free(d.names);
311
	}
312
}
313
314
static int free_type;
315
316
static void
317
names_lh_free_doall(OBJ_NAME *onp)
318
2967
{
319
2967
	if (onp == NULL)
320
		return;
321
322

2967
	if (free_type < 0 || free_type == onp->type)
323
2397
		OBJ_NAME_remove(onp->name, onp->type);
324
}
325
326
2967
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
30
{
337
	unsigned long down_load;
338
339
30
	if (names_lh == NULL)
340
		return;
341
342
30
	free_type = type;
343
30
	down_load = lh_OBJ_NAME_down_load(names_lh);
344
30
	lh_OBJ_NAME_down_load(names_lh) = 0;
345
346
30
	lh_OBJ_NAME_doall(names_lh, LHASH_DOALL_FN(names_lh_free));
347
30
	if (type < 0) {
348
10
		lh_OBJ_NAME_free(names_lh);
349
10
		sk_NAME_FUNCS_pop_free(name_funcs_stack, name_funcs_free);
350
10
		names_lh = NULL;
351
10
		name_funcs_stack = NULL;
352
	} else
353
20
		lh_OBJ_NAME_down_load(names_lh) = down_load;
354
}