fix tab-space mixed indentation
[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  * We define this wrapper for two reasons. Firstly, later versions of
14  * DEC C add linkage information to certain functions, which makes it
15  * tricky to use them as values to regular function pointers.
16  * Secondly, in the EDK2 build environment, the strcmp function is
17  * actually an external function (AsciiStrCmp) with the Microsoft ABI,
18  * so we can't transparently assign function pointers to it.
19  * Arguably the latter is a stupidity of the UEFI environment, but
20  * since the wrapper solves the DEC C issue too, let's just use the
21  * same solution.
22  */
23 #if defined(OPENSSL_SYS_VMS_DECC) || defined(OPENSSL_SYS_UEFI)
24 static int obj_strcmp(const char *a, const char *b)
25 {
26     return strcmp(a, b);
27 }
28 #else
29 #define obj_strcmp strcmp
30 #endif
31
32 /*
33  * I use the ex_data stuff to manage the identifiers for the obj_name_types
34  * that applications may define.  I only really use the free function field.
35  */
36 static LHASH_OF(OBJ_NAME) *names_lh = NULL;
37 static int names_type_num = OBJ_NAME_TYPE_NUM;
38
39 struct name_funcs_st {
40     unsigned long (*hash_func) (const char *name);
41     int (*cmp_func) (const char *a, const char *b);
42     void (*free_func) (const char *, int, const char *);
43 };
44
45 static STACK_OF(NAME_FUNCS) *name_funcs_stack;
46
47 /*
48  * The LHASH callbacks now use the raw "void *" prototypes and do
49  * per-variable casting in the functions. This prevents function pointer
50  * casting without the need for macro-generated wrapper functions.
51  */
52
53 static unsigned long obj_name_hash(const OBJ_NAME *a);
54 static int obj_name_cmp(const OBJ_NAME *a, const OBJ_NAME *b);
55
56 int OBJ_NAME_init(void)
57 {
58     if (names_lh != NULL)
59         return (1);
60     CRYPTO_mem_ctrl(CRYPTO_MEM_CHECK_DISABLE);
61     names_lh = lh_OBJ_NAME_new(obj_name_hash, obj_name_cmp);
62     CRYPTO_mem_ctrl(CRYPTO_MEM_CHECK_ENABLE);
63     return (names_lh != NULL);
64 }
65
66 int OBJ_NAME_new_index(unsigned long (*hash_func) (const char *),
67                        int (*cmp_func) (const char *, const char *),
68                        void (*free_func) (const char *, int, const char *))
69 {
70     int ret;
71     int i;
72     NAME_FUNCS *name_funcs;
73
74     if (name_funcs_stack == NULL) {
75         CRYPTO_mem_ctrl(CRYPTO_MEM_CHECK_DISABLE);
76         name_funcs_stack = sk_NAME_FUNCS_new_null();
77         CRYPTO_mem_ctrl(CRYPTO_MEM_CHECK_ENABLE);
78     }
79     if (name_funcs_stack == NULL) {
80         /* ERROR */
81         return (0);
82     }
83     ret = names_type_num;
84     names_type_num++;
85     for (i = sk_NAME_FUNCS_num(name_funcs_stack); i < names_type_num; i++) {
86         CRYPTO_mem_ctrl(CRYPTO_MEM_CHECK_DISABLE);
87         name_funcs = OPENSSL_zalloc(sizeof(*name_funcs));
88         CRYPTO_mem_ctrl(CRYPTO_MEM_CHECK_ENABLE);
89         if (name_funcs == NULL) {
90             OBJerr(OBJ_F_OBJ_NAME_NEW_INDEX, ERR_R_MALLOC_FAILURE);
91             return (0);
92         }
93         name_funcs->hash_func = lh_strhash;
94         name_funcs->cmp_func = obj_strcmp;
95         CRYPTO_mem_ctrl(CRYPTO_MEM_CHECK_DISABLE);
96         sk_NAME_FUNCS_push(name_funcs_stack, name_funcs);
97         CRYPTO_mem_ctrl(CRYPTO_MEM_CHECK_ENABLE);
98     }
99     name_funcs = sk_NAME_FUNCS_value(name_funcs_stack, ret);
100     if (hash_func != NULL)
101         name_funcs->hash_func = hash_func;
102     if (cmp_func != NULL)
103         name_funcs->cmp_func = cmp_func;
104     if (free_func != NULL)
105         name_funcs->free_func = free_func;
106     return (ret);
107 }
108
109 static int obj_name_cmp(const OBJ_NAME *a, const OBJ_NAME *b)
110 {
111     int ret;
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(const OBJ_NAME *a)
126 {
127     unsigned long ret;
128
129     if ((name_funcs_stack != NULL)
130         && (sk_NAME_FUNCS_num(name_funcs_stack) > a->type)) {
131         ret =
132             sk_NAME_FUNCS_value(name_funcs_stack,
133                                 a->type)->hash_func(a->name);
134     } else {
135         ret = lh_strhash(a->name);
136     }
137     ret ^= a->type;
138     return (ret);
139 }
140
141 const char *OBJ_NAME_get(const char *name, int type)
142 {
143     OBJ_NAME on, *ret;
144     int num = 0, alias;
145
146     if (name == NULL)
147         return (NULL);
148     if ((names_lh == NULL) && !OBJ_NAME_init())
149         return (NULL);
150
151     alias = type & OBJ_NAME_ALIAS;
152     type &= ~OBJ_NAME_ALIAS;
153
154     on.name = name;
155     on.type = type;
156
157     for (;;) {
158         ret = lh_OBJ_NAME_retrieve(names_lh, &on);
159         if (ret == NULL)
160             return (NULL);
161         if ((ret->alias) && !alias) {
162             if (++num > 10)
163                 return (NULL);
164             on.name = ret->data;
165         } else {
166             return (ret->data);
167         }
168     }
169 }
170
171 int OBJ_NAME_add(const char *name, int type, const char *data)
172 {
173     OBJ_NAME *onp, *ret;
174     int alias;
175
176     if ((names_lh == NULL) && !OBJ_NAME_init())
177         return (0);
178
179     alias = type & OBJ_NAME_ALIAS;
180     type &= ~OBJ_NAME_ALIAS;
181
182     onp = OPENSSL_malloc(sizeof(*onp));
183     if (onp == NULL) {
184         /* ERROR */
185         return (0);
186     }
187
188     onp->name = name;
189     onp->alias = alias;
190     onp->type = type;
191     onp->data = data;
192
193     ret = lh_OBJ_NAME_insert(names_lh, onp);
194     if (ret != NULL) {
195         /* free things */
196         if ((name_funcs_stack != NULL)
197             && (sk_NAME_FUNCS_num(name_funcs_stack) > ret->type)) {
198             /*
199              * XXX: I'm not sure I understand why the free function should
200              * get three arguments... -- Richard Levitte
201              */
202             sk_NAME_FUNCS_value(name_funcs_stack,
203                                 ret->type)->free_func(ret->name, ret->type,
204                                                       ret->data);
205         }
206         OPENSSL_free(ret);
207     } else {
208         if (lh_OBJ_NAME_error(names_lh)) {
209             /* ERROR */
210             return (0);
211         }
212     }
213     return (1);
214 }
215
216 int OBJ_NAME_remove(const char *name, int type)
217 {
218     OBJ_NAME on, *ret;
219
220     if (names_lh == NULL)
221         return (0);
222
223     type &= ~OBJ_NAME_ALIAS;
224     on.name = name;
225     on.type = type;
226     ret = lh_OBJ_NAME_delete(names_lh, &on);
227     if (ret != NULL) {
228         /* free things */
229         if ((name_funcs_stack != NULL)
230             && (sk_NAME_FUNCS_num(name_funcs_stack) > ret->type)) {
231             /*
232              * XXX: I'm not sure I understand why the free function should
233              * get three arguments... -- Richard Levitte
234              */
235             sk_NAME_FUNCS_value(name_funcs_stack,
236                                 ret->type)->free_func(ret->name, ret->type,
237                                                       ret->data);
238         }
239         OPENSSL_free(ret);
240         return (1);
241     } else
242         return (0);
243 }
244
245 typedef struct {
246     int type;
247     void (*fn) (const OBJ_NAME *, void *arg);
248     void *arg;
249 } OBJ_DOALL;
250
251 static void do_all_fn(const OBJ_NAME *name, OBJ_DOALL *d)
252 {
253     if (name->type == d->type)
254         d->fn(name, d->arg);
255 }
256
257 IMPLEMENT_LHASH_DOALL_ARG_CONST(OBJ_NAME, OBJ_DOALL);
258
259 void OBJ_NAME_do_all(int type, void (*fn) (const OBJ_NAME *, void *arg),
260                      void *arg)
261 {
262     OBJ_DOALL d;
263
264     d.type = type;
265     d.fn = fn;
266     d.arg = arg;
267
268     lh_OBJ_NAME_doall_OBJ_DOALL(names_lh, do_all_fn, &d);
269 }
270
271 struct doall_sorted {
272     int type;
273     int n;
274     const OBJ_NAME **names;
275 };
276
277 static void do_all_sorted_fn(const OBJ_NAME *name, void *d_)
278 {
279     struct doall_sorted *d = d_;
280
281     if (name->type != d->type)
282         return;
283
284     d->names[d->n++] = name;
285 }
286
287 static int do_all_sorted_cmp(const void *n1_, const void *n2_)
288 {
289     const OBJ_NAME *const *n1 = n1_;
290     const OBJ_NAME *const *n2 = n2_;
291
292     return strcmp((*n1)->name, (*n2)->name);
293 }
294
295 void OBJ_NAME_do_all_sorted(int type,
296                             void (*fn) (const OBJ_NAME *, void *arg),
297                             void *arg)
298 {
299     struct doall_sorted d;
300     int n;
301
302     d.type = type;
303     d.names =
304         OPENSSL_malloc(sizeof(*d.names) * lh_OBJ_NAME_num_items(names_lh));
305     /* Really should return an error if !d.names...but its a void function! */
306     if (d.names != NULL) {
307         d.n = 0;
308         OBJ_NAME_do_all(type, do_all_sorted_fn, &d);
309
310         qsort((void *)d.names, d.n, sizeof(*d.names), do_all_sorted_cmp);
311
312         for (n = 0; n < d.n; ++n)
313             fn(d.names[n], arg);
314
315         OPENSSL_free((void *)d.names);
316     }
317 }
318
319 static int free_type;
320
321 static void names_lh_free_doall(OBJ_NAME *onp)
322 {
323     if (onp == NULL)
324         return;
325
326     if (free_type < 0 || free_type == onp->type)
327         OBJ_NAME_remove(onp->name, onp->type);
328 }
329
330 static void name_funcs_free(NAME_FUNCS *ptr)
331 {
332     OPENSSL_free(ptr);
333 }
334
335 void OBJ_NAME_cleanup(int type)
336 {
337     unsigned long down_load;
338
339     if (names_lh == NULL)
340         return;
341
342     free_type = type;
343     down_load = lh_OBJ_NAME_get_down_load(names_lh);
344     lh_OBJ_NAME_set_down_load(names_lh, 0);
345
346     lh_OBJ_NAME_doall(names_lh, names_lh_free_doall);
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_set_down_load(names_lh, down_load);
354 }