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