Unleashed v1.4
[unleashed.git] / lib / libcrypto / objects / o_names.c
bloba9e5f859d57208226d0f5f0c4e2ae908a0c85293
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>
6 #include <openssl/opensslconf.h>
8 #include <openssl/err.h>
9 #include <openssl/lhash.h>
10 #include <openssl/objects.h>
11 #include <openssl/safestack.h>
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.
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;
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;
26 DECLARE_STACK_OF(NAME_FUNCS)
28 static STACK_OF(NAME_FUNCS) *name_funcs_stack;
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. */
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);
39 static IMPLEMENT_LHASH_HASH_FN(obj_name, OBJ_NAME)
40 static IMPLEMENT_LHASH_COMP_FN(obj_name, OBJ_NAME)
42 int
43 OBJ_NAME_init(void)
45 if (names_lh != NULL)
46 return (1);
47 names_lh = lh_OBJ_NAME_new();
48 return (names_lh != NULL);
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 *))
56 int ret;
57 int i;
58 NAME_FUNCS *name_funcs;
60 if (name_funcs_stack == NULL)
61 name_funcs_stack = sk_NAME_FUNCS_new_null();
62 if (name_funcs_stack == NULL)
63 return (0);
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);
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);
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);
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)
96 int ret;
97 const OBJ_NAME *a = (const OBJ_NAME *)a_void;
98 const OBJ_NAME *b = (const OBJ_NAME *)b_void;
100 ret = a->type - b->type;
101 if (ret == 0) {
102 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 ret = strcmp(a->name, b->name);
109 return (ret);
112 /* static unsigned long obj_name_hash(OBJ_NAME *a) */
113 static unsigned long
114 obj_name_hash(const void *a_void)
116 unsigned long ret;
117 const OBJ_NAME *a = (const OBJ_NAME *)a_void;
119 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 ret = lh_strhash(a->name);
126 ret ^= a->type;
127 return (ret);
130 const char *
131 OBJ_NAME_get(const char *name, int type)
133 OBJ_NAME on, *ret;
134 int num = 0, alias;
136 if (name == NULL)
137 return (NULL);
138 if ((names_lh == NULL) && !OBJ_NAME_init())
139 return (NULL);
141 alias = type&OBJ_NAME_ALIAS;
142 type&= ~OBJ_NAME_ALIAS;
144 on.name = name;
145 on.type = type;
147 for (;;) {
148 ret = lh_OBJ_NAME_retrieve(names_lh, &on);
149 if (ret == NULL)
150 return (NULL);
151 if ((ret->alias) && !alias) {
152 if (++num > 10)
153 return (NULL);
154 on.name = ret->data;
155 } else {
156 return (ret->data);
162 OBJ_NAME_add(const char *name, int type, const char *data)
164 OBJ_NAME *onp, *ret;
165 int alias;
167 if ((names_lh == NULL) && !OBJ_NAME_init())
168 return (0);
170 alias = type & OBJ_NAME_ALIAS;
171 type &= ~OBJ_NAME_ALIAS;
173 onp = malloc(sizeof(OBJ_NAME));
174 if (onp == NULL) {
175 /* ERROR */
176 return (0);
179 onp->name = name;
180 onp->alias = alias;
181 onp->type = type;
182 onp->data = data;
184 ret = lh_OBJ_NAME_insert(names_lh, onp);
185 if (ret != NULL) {
186 /* free things */
187 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
193 sk_NAME_FUNCS_value(
194 name_funcs_stack, ret->type)->free_func(
195 ret->name, ret->type, ret->data);
197 free(ret);
198 } else {
199 if (lh_OBJ_NAME_error(names_lh)) {
200 /* ERROR */
201 return (0);
204 return (1);
208 OBJ_NAME_remove(const char *name, int type)
210 OBJ_NAME on, *ret;
212 if (names_lh == NULL)
213 return (0);
215 type &= ~OBJ_NAME_ALIAS;
216 on.name = name;
217 on.type = type;
218 ret = lh_OBJ_NAME_delete(names_lh, &on);
219 if (ret != NULL) {
220 /* free things */
221 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
227 sk_NAME_FUNCS_value(
228 name_funcs_stack, ret->type)->free_func(
229 ret->name, ret->type, ret->data);
231 free(ret);
232 return (1);
233 } else
234 return (0);
237 struct doall {
238 int type;
239 void (*fn)(const OBJ_NAME *, void *arg);
240 void *arg;
243 static void
244 do_all_fn_doall_arg(const OBJ_NAME *name, struct doall *d)
246 if (name->type == d->type)
247 d->fn(name, d->arg);
250 static IMPLEMENT_LHASH_DOALL_ARG_FN(do_all_fn, const OBJ_NAME, struct doall)
252 void
253 OBJ_NAME_do_all(int type, void (*fn)(const OBJ_NAME *, void *arg), void *arg)
255 struct doall d;
257 d.type = type;
258 d.fn = fn;
259 d.arg = arg;
261 lh_OBJ_NAME_doall_arg(names_lh, LHASH_DOALL_ARG_FN(do_all_fn),
262 struct doall, &d);
265 struct doall_sorted {
266 int type;
267 int n;
268 const OBJ_NAME **names;
271 static void
272 do_all_sorted_fn(const OBJ_NAME *name, void *d_)
274 struct doall_sorted *d = d_;
276 if (name->type != d->type)
277 return;
279 d->names[d->n++] = name;
282 static int
283 do_all_sorted_cmp(const void *n1_, const void *n2_)
285 const OBJ_NAME * const *n1 = n1_;
286 const OBJ_NAME * const *n2 = n2_;
288 return strcmp((*n1)->name, (*n2)->name);
291 void
292 OBJ_NAME_do_all_sorted(int type, void (*fn)(const OBJ_NAME *, void *arg),
293 void *arg)
295 struct doall_sorted d;
296 int n;
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);
305 qsort((void *)d.names, d.n, sizeof *d.names, do_all_sorted_cmp);
307 for (n = 0; n < d.n; ++n)
308 fn(d.names[n], arg);
310 free(d.names);
314 static int free_type;
316 static void
317 names_lh_free_doall(OBJ_NAME *onp)
319 if (onp == NULL)
320 return;
322 if (free_type < 0 || free_type == onp->type)
323 OBJ_NAME_remove(onp->name, onp->type);
326 static IMPLEMENT_LHASH_DOALL_FN(names_lh_free, OBJ_NAME)
328 static void
329 name_funcs_free(NAME_FUNCS *ptr)
331 free(ptr);
334 void
335 OBJ_NAME_cleanup(int type)
337 unsigned long down_load;
339 if (names_lh == NULL)
340 return;
342 free_type = type;
343 down_load = lh_OBJ_NAME_down_load(names_lh);
344 lh_OBJ_NAME_down_load(names_lh) = 0;
346 lh_OBJ_NAME_doall(names_lh, LHASH_DOALL_FN(names_lh_free));
347 if (type < 0) {
348 lh_OBJ_NAME_free(names_lh);
349 sk_NAME_FUNCS_pop_free(name_funcs_stack, name_funcs_free);
350 names_lh = NULL;
351 name_funcs_stack = NULL;
352 } else
353 lh_OBJ_NAME_down_load(names_lh) = down_load;