]> git.ipfire.org Git - thirdparty/openssl.git/blob - crypto/objects/o_names.c
Add lh_doall inlining
[thirdparty/openssl.git] / crypto / objects / o_names.c
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <string.h>
4
5 #include <openssl/err.h>
6 #include <openssl/lhash.h>
7 #include <openssl/objects.h>
8 #include <openssl/safestack.h>
9 #include <openssl/e_os2.h>
10 #include "obj_lcl.h"
11
12 /*
13 * Later versions of DEC C has started to add lnkage information to certain
14 * functions, which makes it tricky to use them as values to regular function
15 * pointers. One way is to define a macro that takes care of casting them
16 * correctly.
17 */
18 #ifdef OPENSSL_SYS_VMS_DECC
19 # define OPENSSL_strcmp (int (*)(const char *,const char *))strcmp
20 #else
21 # define OPENSSL_strcmp strcmp
22 #endif
23
24 /*
25 * I use the ex_data stuff to manage the identifiers for the obj_name_types
26 * that applications may define. I only really use the free function field.
27 */
28 static LHASH_OF(OBJ_NAME) *names_lh = NULL;
29 static int names_type_num = OBJ_NAME_TYPE_NUM;
30
31 struct name_funcs_st {
32 unsigned long (*hash_func) (const char *name);
33 int (*cmp_func) (const char *a, const char *b);
34 void (*free_func) (const char *, int, const char *);
35 };
36
37 static STACK_OF(NAME_FUNCS) *name_funcs_stack;
38
39 /*
40 * The LHASH callbacks now use the raw "void *" prototypes and do
41 * per-variable casting in the functions. This prevents function pointer
42 * casting without the need for macro-generated wrapper functions.
43 */
44
45 static unsigned long obj_name_hash(const OBJ_NAME *a);
46 static int obj_name_cmp(const OBJ_NAME *a, const OBJ_NAME *b);
47
48 int OBJ_NAME_init(void)
49 {
50 if (names_lh != NULL)
51 return (1);
52 CRYPTO_mem_ctrl(CRYPTO_MEM_CHECK_DISABLE);
53 names_lh = lh_OBJ_NAME_new(obj_name_hash, obj_name_cmp);
54 CRYPTO_mem_ctrl(CRYPTO_MEM_CHECK_ENABLE);
55 return (names_lh != NULL);
56 }
57
58 int OBJ_NAME_new_index(unsigned long (*hash_func) (const char *),
59 int (*cmp_func) (const char *, const char *),
60 void (*free_func) (const char *, int, const char *))
61 {
62 int ret;
63 int i;
64 NAME_FUNCS *name_funcs;
65
66 if (name_funcs_stack == NULL) {
67 CRYPTO_mem_ctrl(CRYPTO_MEM_CHECK_DISABLE);
68 name_funcs_stack = sk_NAME_FUNCS_new_null();
69 CRYPTO_mem_ctrl(CRYPTO_MEM_CHECK_ENABLE);
70 }
71 if (name_funcs_stack == NULL) {
72 /* ERROR */
73 return (0);
74 }
75 ret = names_type_num;
76 names_type_num++;
77 for (i = sk_NAME_FUNCS_num(name_funcs_stack); i < names_type_num; i++) {
78 CRYPTO_mem_ctrl(CRYPTO_MEM_CHECK_DISABLE);
79 name_funcs = OPENSSL_zalloc(sizeof(*name_funcs));
80 CRYPTO_mem_ctrl(CRYPTO_MEM_CHECK_ENABLE);
81 if (name_funcs == NULL) {
82 OBJerr(OBJ_F_OBJ_NAME_NEW_INDEX, ERR_R_MALLOC_FAILURE);
83 return (0);
84 }
85 name_funcs->hash_func = lh_strhash;
86 name_funcs->cmp_func = OPENSSL_strcmp;
87 CRYPTO_mem_ctrl(CRYPTO_MEM_CHECK_DISABLE);
88 sk_NAME_FUNCS_push(name_funcs_stack, name_funcs);
89 CRYPTO_mem_ctrl(CRYPTO_MEM_CHECK_ENABLE);
90 }
91 name_funcs = sk_NAME_FUNCS_value(name_funcs_stack, ret);
92 if (hash_func != NULL)
93 name_funcs->hash_func = hash_func;
94 if (cmp_func != NULL)
95 name_funcs->cmp_func = cmp_func;
96 if (free_func != NULL)
97 name_funcs->free_func = free_func;
98 return (ret);
99 }
100
101 static int obj_name_cmp(const OBJ_NAME *a, const OBJ_NAME *b)
102 {
103 int ret;
104
105 ret = a->type - b->type;
106 if (ret == 0) {
107 if ((name_funcs_stack != NULL)
108 && (sk_NAME_FUNCS_num(name_funcs_stack) > a->type)) {
109 ret = sk_NAME_FUNCS_value(name_funcs_stack,
110 a->type)->cmp_func(a->name, b->name);
111 } else
112 ret = strcmp(a->name, b->name);
113 }
114 return (ret);
115 }
116
117 static unsigned long obj_name_hash(const OBJ_NAME *a)
118 {
119 unsigned long ret;
120
121 if ((name_funcs_stack != NULL)
122 && (sk_NAME_FUNCS_num(name_funcs_stack) > a->type)) {
123 ret =
124 sk_NAME_FUNCS_value(name_funcs_stack,
125 a->type)->hash_func(a->name);
126 } else {
127 ret = lh_strhash(a->name);
128 }
129 ret ^= a->type;
130 return (ret);
131 }
132
133 const char *OBJ_NAME_get(const char *name, int type)
134 {
135 OBJ_NAME on, *ret;
136 int num = 0, alias;
137
138 if (name == NULL)
139 return (NULL);
140 if ((names_lh == NULL) && !OBJ_NAME_init())
141 return (NULL);
142
143 alias = type & OBJ_NAME_ALIAS;
144 type &= ~OBJ_NAME_ALIAS;
145
146 on.name = name;
147 on.type = type;
148
149 for (;;) {
150 ret = lh_OBJ_NAME_retrieve(names_lh, &on);
151 if (ret == NULL)
152 return (NULL);
153 if ((ret->alias) && !alias) {
154 if (++num > 10)
155 return (NULL);
156 on.name = ret->data;
157 } else {
158 return (ret->data);
159 }
160 }
161 }
162
163 int OBJ_NAME_add(const char *name, int type, const char *data)
164 {
165 OBJ_NAME *onp, *ret;
166 int alias;
167
168 if ((names_lh == NULL) && !OBJ_NAME_init())
169 return (0);
170
171 alias = type & OBJ_NAME_ALIAS;
172 type &= ~OBJ_NAME_ALIAS;
173
174 onp = OPENSSL_malloc(sizeof(*onp));
175 if (onp == NULL) {
176 /* ERROR */
177 return (0);
178 }
179
180 onp->name = name;
181 onp->alias = alias;
182 onp->type = type;
183 onp->data = data;
184
185 ret = lh_OBJ_NAME_insert(names_lh, onp);
186 if (ret != NULL) {
187 /* free things */
188 if ((name_funcs_stack != NULL)
189 && (sk_NAME_FUNCS_num(name_funcs_stack) > ret->type)) {
190 /*
191 * XXX: I'm not sure I understand why the free function should
192 * get three arguments... -- Richard Levitte
193 */
194 sk_NAME_FUNCS_value(name_funcs_stack,
195 ret->type)->free_func(ret->name, ret->type,
196 ret->data);
197 }
198 OPENSSL_free(ret);
199 } else {
200 if (lh_OBJ_NAME_error(names_lh)) {
201 /* ERROR */
202 return (0);
203 }
204 }
205 return (1);
206 }
207
208 int OBJ_NAME_remove(const char *name, int type)
209 {
210 OBJ_NAME on, *ret;
211
212 if (names_lh == NULL)
213 return (0);
214
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 /*
224 * XXX: I'm not sure I understand why the free function should
225 * get three arguments... -- Richard Levitte
226 */
227 sk_NAME_FUNCS_value(name_funcs_stack,
228 ret->type)->free_func(ret->name, ret->type,
229 ret->data);
230 }
231 OPENSSL_free(ret);
232 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 do_all_fn_doall_arg(const OBJ_NAME *name, struct doall *d)
244 {
245 if (name->type == d->type)
246 d->fn(name, d->arg);
247 }
248
249 static IMPLEMENT_LHASH_DOALL_ARG_FN(do_all_fn, const OBJ_NAME, struct doall)
250
251 void OBJ_NAME_do_all(int type, void (*fn) (const OBJ_NAME *, void *arg),
252 void *arg)
253 {
254 struct doall d;
255
256 d.type = type;
257 d.fn = fn;
258 d.arg = arg;
259
260 lh_OBJ_NAME_doall_arg(names_lh, LHASH_DOALL_ARG_FN(do_all_fn),
261 struct doall, &d);
262 }
263
264 struct doall_sorted {
265 int type;
266 int n;
267 const OBJ_NAME **names;
268 };
269
270 static void do_all_sorted_fn(const OBJ_NAME *name, void *d_)
271 {
272 struct doall_sorted *d = d_;
273
274 if (name->type != d->type)
275 return;
276
277 d->names[d->n++] = name;
278 }
279
280 static int do_all_sorted_cmp(const void *n1_, const void *n2_)
281 {
282 const OBJ_NAME *const *n1 = n1_;
283 const OBJ_NAME *const *n2 = n2_;
284
285 return strcmp((*n1)->name, (*n2)->name);
286 }
287
288 void OBJ_NAME_do_all_sorted(int type,
289 void (*fn) (const OBJ_NAME *, void *arg),
290 void *arg)
291 {
292 struct doall_sorted d;
293 int n;
294
295 d.type = type;
296 d.names =
297 OPENSSL_malloc(sizeof(*d.names) * lh_OBJ_NAME_num_items(names_lh));
298 /* Really should return an error if !d.names...but its a void function! */
299 if (d.names != NULL) {
300 d.n = 0;
301 OBJ_NAME_do_all(type, do_all_sorted_fn, &d);
302
303 qsort((void *)d.names, d.n, sizeof(*d.names), do_all_sorted_cmp);
304
305 for (n = 0; n < d.n; ++n)
306 fn(d.names[n], arg);
307
308 OPENSSL_free((void *)d.names);
309 }
310 }
311
312 static int free_type;
313
314 static void names_lh_free_doall(OBJ_NAME *onp)
315 {
316 if (onp == NULL)
317 return;
318
319 if (free_type < 0 || free_type == onp->type)
320 OBJ_NAME_remove(onp->name, onp->type);
321 }
322
323 static void name_funcs_free(NAME_FUNCS *ptr)
324 {
325 OPENSSL_free(ptr);
326 }
327
328 void OBJ_NAME_cleanup(int type)
329 {
330 unsigned long down_load;
331
332 if (names_lh == NULL)
333 return;
334
335 free_type = type;
336 down_load = lh_OBJ_NAME_get_down_load(names_lh);
337 lh_OBJ_NAME_set_down_load(names_lh, 0);
338
339 lh_OBJ_NAME_doall(names_lh, names_lh_free_doall);
340 if (type < 0) {
341 lh_OBJ_NAME_free(names_lh);
342 sk_NAME_FUNCS_pop_free(name_funcs_stack, name_funcs_free);
343 names_lh = NULL;
344 name_funcs_stack = NULL;
345 } else
346 lh_OBJ_NAME_set_down_load(names_lh, down_load);
347 }