mem functions cleanup
[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 "o_names.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 DECLARE_LHASH_OF(OBJ_NAME);
29 static LHASH_OF(OBJ_NAME) *names_lh = NULL;
30 static int names_type_num = OBJ_NAME_TYPE_NUM;
31
32 struct name_funcs_st {
33     unsigned long (*hash_func) (const char *name);
34     int (*cmp_func) (const char *a, const char *b);
35     void (*free_func) (const char *, int, const char *);
36 };
37
38 static STACK_OF(NAME_FUNCS) *name_funcs_stack;
39
40 /*
41  * The LHASH callbacks now use the raw "void *" prototypes and do
42  * per-variable casting in the functions. This prevents function pointer
43  * casting without the need for macro-generated wrapper functions.
44  */
45
46 /* static unsigned long obj_name_hash(OBJ_NAME *a); */
47 static unsigned long obj_name_hash(const void *a_void);
48 /* static int obj_name_cmp(OBJ_NAME *a,OBJ_NAME *b); */
49 static int obj_name_cmp(const void *a_void, const void *b_void);
50
51 static IMPLEMENT_LHASH_HASH_FN(obj_name, OBJ_NAME)
52 static IMPLEMENT_LHASH_COMP_FN(obj_name, OBJ_NAME)
53
54 int OBJ_NAME_init(void)
55 {
56     if (names_lh != NULL)
57         return (1);
58     CRYPTO_mem_ctrl(CRYPTO_MEM_CHECK_DISABLE);
59     names_lh = lh_OBJ_NAME_new();
60     CRYPTO_mem_ctrl(CRYPTO_MEM_CHECK_ENABLE);
61     return (names_lh != NULL);
62 }
63
64 int OBJ_NAME_new_index(unsigned long (*hash_func) (const char *),
65                        int (*cmp_func) (const char *, const char *),
66                        void (*free_func) (const char *, int, const char *))
67 {
68     int ret;
69     int i;
70     NAME_FUNCS *name_funcs;
71
72     if (name_funcs_stack == NULL) {
73         CRYPTO_mem_ctrl(CRYPTO_MEM_CHECK_DISABLE);
74         name_funcs_stack = sk_NAME_FUNCS_new_null();
75         CRYPTO_mem_ctrl(CRYPTO_MEM_CHECK_ENABLE);
76     }
77     if (name_funcs_stack == NULL) {
78         /* ERROR */
79         return (0);
80     }
81     ret = names_type_num;
82     names_type_num++;
83     for (i = sk_NAME_FUNCS_num(name_funcs_stack); i < names_type_num; i++) {
84         CRYPTO_mem_ctrl(CRYPTO_MEM_CHECK_DISABLE);
85         name_funcs = OPENSSL_zalloc(sizeof(*name_funcs));
86         CRYPTO_mem_ctrl(CRYPTO_MEM_CHECK_ENABLE);
87         if (name_funcs == NULL) {
88             OBJerr(OBJ_F_OBJ_NAME_NEW_INDEX, ERR_R_MALLOC_FAILURE);
89             return (0);
90         }
91         name_funcs->hash_func = lh_strhash;
92         name_funcs->cmp_func = OPENSSL_strcmp;
93         CRYPTO_mem_ctrl(CRYPTO_MEM_CHECK_DISABLE);
94         sk_NAME_FUNCS_push(name_funcs_stack, name_funcs);
95         CRYPTO_mem_ctrl(CRYPTO_MEM_CHECK_ENABLE);
96     }
97     name_funcs = sk_NAME_FUNCS_value(name_funcs_stack, ret);
98     if (hash_func != NULL)
99         name_funcs->hash_func = hash_func;
100     if (cmp_func != NULL)
101         name_funcs->cmp_func = cmp_func;
102     if (free_func != NULL)
103         name_funcs->free_func = free_func;
104     return (ret);
105 }
106
107 /* static int obj_name_cmp(OBJ_NAME *a, OBJ_NAME *b) */
108 static int obj_name_cmp(const void *a_void, const void *b_void)
109 {
110     int ret;
111     const OBJ_NAME *a = (const OBJ_NAME *)a_void;
112     const OBJ_NAME *b = (const OBJ_NAME *)b_void;
113
114     ret = a->type - b->type;
115     if (ret == 0) {
116         if ((name_funcs_stack != NULL)
117             && (sk_NAME_FUNCS_num(name_funcs_stack) > a->type)) {
118             ret = sk_NAME_FUNCS_value(name_funcs_stack,
119                                       a->type)->cmp_func(a->name, b->name);
120         } else
121             ret = strcmp(a->name, b->name);
122     }
123     return (ret);
124 }
125
126 /* static unsigned long obj_name_hash(OBJ_NAME *a) */
127 static unsigned long obj_name_hash(const void *a_void)
128 {
129     unsigned long ret;
130     const OBJ_NAME *a = (const OBJ_NAME *)a_void;
131
132     if ((name_funcs_stack != NULL)
133         && (sk_NAME_FUNCS_num(name_funcs_stack) > a->type)) {
134         ret =
135             sk_NAME_FUNCS_value(name_funcs_stack,
136                                 a->type)->hash_func(a->name);
137     } else {
138         ret = lh_strhash(a->name);
139     }
140     ret ^= a->type;
141     return (ret);
142 }
143
144 const char *OBJ_NAME_get(const char *name, int type)
145 {
146     OBJ_NAME on, *ret;
147     int num = 0, alias;
148
149     if (name == NULL)
150         return (NULL);
151     if ((names_lh == NULL) && !OBJ_NAME_init())
152         return (NULL);
153
154     alias = type & OBJ_NAME_ALIAS;
155     type &= ~OBJ_NAME_ALIAS;
156
157     on.name = name;
158     on.type = type;
159
160     for (;;) {
161         ret = lh_OBJ_NAME_retrieve(names_lh, &on);
162         if (ret == NULL)
163             return (NULL);
164         if ((ret->alias) && !alias) {
165             if (++num > 10)
166                 return (NULL);
167             on.name = ret->data;
168         } else {
169             return (ret->data);
170         }
171     }
172 }
173
174 int OBJ_NAME_add(const char *name, int type, const char *data)
175 {
176     OBJ_NAME *onp, *ret;
177     int alias;
178
179     if ((names_lh == NULL) && !OBJ_NAME_init())
180         return (0);
181
182     alias = type & OBJ_NAME_ALIAS;
183     type &= ~OBJ_NAME_ALIAS;
184
185     onp = OPENSSL_malloc(sizeof(*onp));
186     if (onp == NULL) {
187         /* ERROR */
188         return (0);
189     }
190
191     onp->name = name;
192     onp->alias = alias;
193     onp->type = type;
194     onp->data = data;
195
196     ret = lh_OBJ_NAME_insert(names_lh, onp);
197     if (ret != NULL) {
198         /* free things */
199         if ((name_funcs_stack != NULL)
200             && (sk_NAME_FUNCS_num(name_funcs_stack) > ret->type)) {
201             /*
202              * XXX: I'm not sure I understand why the free function should
203              * get three arguments... -- Richard Levitte
204              */
205             sk_NAME_FUNCS_value(name_funcs_stack,
206                                 ret->type)->free_func(ret->name, ret->type,
207                                                       ret->data);
208         }
209         OPENSSL_free(ret);
210     } else {
211         if (lh_OBJ_NAME_error(names_lh)) {
212             /* ERROR */
213             return (0);
214         }
215     }
216     return (1);
217 }
218
219 int OBJ_NAME_remove(const char *name, int type)
220 {
221     OBJ_NAME on, *ret;
222
223     if (names_lh == NULL)
224         return (0);
225
226     type &= ~OBJ_NAME_ALIAS;
227     on.name = name;
228     on.type = type;
229     ret = lh_OBJ_NAME_delete(names_lh, &on);
230     if (ret != NULL) {
231         /* free things */
232         if ((name_funcs_stack != NULL)
233             && (sk_NAME_FUNCS_num(name_funcs_stack) > ret->type)) {
234             /*
235              * XXX: I'm not sure I understand why the free function should
236              * get three arguments... -- Richard Levitte
237              */
238             sk_NAME_FUNCS_value(name_funcs_stack,
239                                 ret->type)->free_func(ret->name, ret->type,
240                                                       ret->data);
241         }
242         OPENSSL_free(ret);
243         return (1);
244     } else
245         return (0);
246 }
247
248 struct doall {
249     int type;
250     void (*fn) (const OBJ_NAME *, void *arg);
251     void *arg;
252 };
253
254 static void do_all_fn_doall_arg(const OBJ_NAME *name, struct doall *d)
255 {
256     if (name->type == d->type)
257         d->fn(name, d->arg);
258 }
259
260 static IMPLEMENT_LHASH_DOALL_ARG_FN(do_all_fn, const OBJ_NAME, struct doall)
261
262 void OBJ_NAME_do_all(int type, void (*fn) (const OBJ_NAME *, void *arg),
263                      void *arg)
264 {
265     struct doall d;
266
267     d.type = type;
268     d.fn = fn;
269     d.arg = arg;
270
271     lh_OBJ_NAME_doall_arg(names_lh, LHASH_DOALL_ARG_FN(do_all_fn),
272                           struct doall, &d);
273 }
274
275 struct doall_sorted {
276     int type;
277     int n;
278     const OBJ_NAME **names;
279 };
280
281 static void do_all_sorted_fn(const OBJ_NAME *name, void *d_)
282 {
283     struct doall_sorted *d = d_;
284
285     if (name->type != d->type)
286         return;
287
288     d->names[d->n++] = name;
289 }
290
291 static int do_all_sorted_cmp(const void *n1_, const void *n2_)
292 {
293     const OBJ_NAME *const *n1 = n1_;
294     const OBJ_NAME *const *n2 = n2_;
295
296     return strcmp((*n1)->name, (*n2)->name);
297 }
298
299 void OBJ_NAME_do_all_sorted(int type,
300                             void (*fn) (const OBJ_NAME *, void *arg),
301                             void *arg)
302 {
303     struct doall_sorted d;
304     int n;
305
306     d.type = type;
307     d.names =
308         OPENSSL_malloc(sizeof(*d.names) * lh_OBJ_NAME_num_items(names_lh));
309     /* Really should return an error if !d.names...but its a void function! */
310     if (d.names != NULL) {
311         d.n = 0;
312         OBJ_NAME_do_all(type, do_all_sorted_fn, &d);
313
314         qsort((void *)d.names, d.n, sizeof(*d.names), do_all_sorted_cmp);
315
316         for (n = 0; n < d.n; ++n)
317             fn(d.names[n], arg);
318
319         OPENSSL_free((void *)d.names);
320     }
321 }
322
323 static int free_type;
324
325 static void names_lh_free_doall(OBJ_NAME *onp)
326 {
327     if (onp == NULL)
328         return;
329
330     if (free_type < 0 || free_type == onp->type)
331         OBJ_NAME_remove(onp->name, onp->type);
332 }
333
334 static IMPLEMENT_LHASH_DOALL_FN(names_lh_free, OBJ_NAME)
335
336 static void name_funcs_free(NAME_FUNCS *ptr)
337 {
338     OPENSSL_free(ptr);
339 }
340
341 void OBJ_NAME_cleanup(int type)
342 {
343     unsigned long down_load;
344
345     if (names_lh == NULL)
346         return;
347
348     free_type = type;
349     down_load = lh_OBJ_NAME_down_load(names_lh);
350     lh_OBJ_NAME_down_load(names_lh) = 0;
351
352     lh_OBJ_NAME_doall(names_lh, LHASH_DOALL_FN(names_lh_free));
353     if (type < 0) {
354         lh_OBJ_NAME_free(names_lh);
355         sk_NAME_FUNCS_pop_free(name_funcs_stack, name_funcs_free);
356         names_lh = NULL;
357         name_funcs_stack = NULL;
358     } else
359         lh_OBJ_NAME_down_load(names_lh) = down_load;
360 }