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