155714Skris#include <stdio.h>
255714Skris#include <stdlib.h>
355714Skris#include <string.h>
455714Skris
5160814Ssimon#include <openssl/err.h>
655714Skris#include <openssl/lhash.h>
755714Skris#include <openssl/objects.h>
859191Skris#include <openssl/safestack.h>
9109998Smarkm#include <openssl/e_os2.h>
1055714Skris
11280304Sjkim/*
12280304Sjkim * Later versions of DEC C has started to add lnkage information to certain
13109998Smarkm * functions, which makes it tricky to use them as values to regular function
14109998Smarkm * pointers.  One way is to define a macro that takes care of casting them
15109998Smarkm * correctly.
16109998Smarkm */
17109998Smarkm#ifdef OPENSSL_SYS_VMS_DECC
18109998Smarkm# define OPENSSL_strcmp (int (*)(const char *,const char *))strcmp
19109998Smarkm#else
20109998Smarkm# define OPENSSL_strcmp strcmp
21109998Smarkm#endif
22109998Smarkm
23280304Sjkim/*
24280304Sjkim * I use the ex_data stuff to manage the identifiers for the obj_name_types
2555714Skris * that applications may define.  I only really use the free function field.
2655714Skris */
27238405SjkimDECLARE_LHASH_OF(OBJ_NAME);
28280304Sjkimstatic LHASH_OF(OBJ_NAME) *names_lh = NULL;
29280304Sjkimstatic int names_type_num = OBJ_NAME_TYPE_NUM;
3055714Skris
31280304Sjkimtypedef struct name_funcs_st {
32280304Sjkim    unsigned long (*hash_func) (const char *name);
33280304Sjkim    int (*cmp_func) (const char *a, const char *b);
34280304Sjkim    void (*free_func) (const char *, int, const char *);
35280304Sjkim} NAME_FUNCS;
3659191Skris
3759191SkrisDECLARE_STACK_OF(NAME_FUNCS)
3859191SkrisIMPLEMENT_STACK_OF(NAME_FUNCS)
3959191Skris
4059191Skrisstatic STACK_OF(NAME_FUNCS) *name_funcs_stack;
4159191Skris
42280304Sjkim/*
43280304Sjkim * The LHASH callbacks now use the raw "void *" prototypes and do
44280304Sjkim * per-variable casting in the functions. This prevents function pointer
45280304Sjkim * casting without the need for macro-generated wrapper functions.
46280304Sjkim */
4755714Skris
48109998Smarkm/* static unsigned long obj_name_hash(OBJ_NAME *a); */
49109998Smarkmstatic unsigned long obj_name_hash(const void *a_void);
50109998Smarkm/* static int obj_name_cmp(OBJ_NAME *a,OBJ_NAME *b); */
51280304Sjkimstatic int obj_name_cmp(const void *a_void, const void *b_void);
52109998Smarkm
53238405Sjkimstatic IMPLEMENT_LHASH_HASH_FN(obj_name, OBJ_NAME)
54238405Sjkimstatic IMPLEMENT_LHASH_COMP_FN(obj_name, OBJ_NAME)
55238405Sjkim
5655714Skrisint OBJ_NAME_init(void)
57280304Sjkim{
58280304Sjkim    if (names_lh != NULL)
59280304Sjkim        return (1);
60280304Sjkim    MemCheck_off();
61280304Sjkim    names_lh = lh_OBJ_NAME_new();
62280304Sjkim    MemCheck_on();
63280304Sjkim    return (names_lh != NULL);
64280304Sjkim}
6555714Skris
66280304Sjkimint OBJ_NAME_new_index(unsigned long (*hash_func) (const char *),
67280304Sjkim                       int (*cmp_func) (const char *, const char *),
68280304Sjkim                       void (*free_func) (const char *, int, const char *))
69280304Sjkim{
70280304Sjkim    int ret;
71280304Sjkim    int i;
72280304Sjkim    NAME_FUNCS *name_funcs;
7355714Skris
74280304Sjkim    if (name_funcs_stack == NULL) {
75280304Sjkim        MemCheck_off();
76280304Sjkim        name_funcs_stack = sk_NAME_FUNCS_new_null();
77280304Sjkim        MemCheck_on();
78280304Sjkim    }
79280304Sjkim    if (name_funcs_stack == NULL) {
80280304Sjkim        /* ERROR */
81280304Sjkim        return (0);
82280304Sjkim    }
83280304Sjkim    ret = names_type_num;
84280304Sjkim    names_type_num++;
85280304Sjkim    for (i = sk_NAME_FUNCS_num(name_funcs_stack); i < names_type_num; i++) {
86280304Sjkim        MemCheck_off();
87280304Sjkim        name_funcs = OPENSSL_malloc(sizeof(NAME_FUNCS));
88280304Sjkim        MemCheck_on();
89280304Sjkim        if (!name_funcs) {
90280304Sjkim            OBJerr(OBJ_F_OBJ_NAME_NEW_INDEX, ERR_R_MALLOC_FAILURE);
91280304Sjkim            return (0);
92280304Sjkim        }
93280304Sjkim        name_funcs->hash_func = lh_strhash;
94280304Sjkim        name_funcs->cmp_func = OPENSSL_strcmp;
95280304Sjkim        name_funcs->free_func = 0; /* NULL is often declared to * ((void
96280304Sjkim                                    * *)0), which according * to Compaq C is
97280304Sjkim                                    * not really * compatible with a function
98280304Sjkim                                    * * pointer.  -- Richard Levitte */
99280304Sjkim        MemCheck_off();
100280304Sjkim        sk_NAME_FUNCS_push(name_funcs_stack, name_funcs);
101280304Sjkim        MemCheck_on();
102280304Sjkim    }
103280304Sjkim    name_funcs = sk_NAME_FUNCS_value(name_funcs_stack, ret);
104280304Sjkim    if (hash_func != NULL)
105280304Sjkim        name_funcs->hash_func = hash_func;
106280304Sjkim    if (cmp_func != NULL)
107280304Sjkim        name_funcs->cmp_func = cmp_func;
108280304Sjkim    if (free_func != NULL)
109280304Sjkim        name_funcs->free_func = free_func;
110280304Sjkim    return (ret);
111280304Sjkim}
11255714Skris
113109998Smarkm/* static int obj_name_cmp(OBJ_NAME *a, OBJ_NAME *b) */
114109998Smarkmstatic int obj_name_cmp(const void *a_void, const void *b_void)
115280304Sjkim{
116280304Sjkim    int ret;
117280304Sjkim    const OBJ_NAME *a = (const OBJ_NAME *)a_void;
118280304Sjkim    const OBJ_NAME *b = (const OBJ_NAME *)b_void;
11955714Skris
120280304Sjkim    ret = a->type - b->type;
121280304Sjkim    if (ret == 0) {
122280304Sjkim        if ((name_funcs_stack != NULL)
123280304Sjkim            && (sk_NAME_FUNCS_num(name_funcs_stack) > a->type)) {
124280304Sjkim            ret = sk_NAME_FUNCS_value(name_funcs_stack,
125280304Sjkim                                      a->type)->cmp_func(a->name, b->name);
126280304Sjkim        } else
127280304Sjkim            ret = strcmp(a->name, b->name);
128280304Sjkim    }
129280304Sjkim    return (ret);
130280304Sjkim}
13155714Skris
132109998Smarkm/* static unsigned long obj_name_hash(OBJ_NAME *a) */
133109998Smarkmstatic unsigned long obj_name_hash(const void *a_void)
134280304Sjkim{
135280304Sjkim    unsigned long ret;
136280304Sjkim    const OBJ_NAME *a = (const OBJ_NAME *)a_void;
13755714Skris
138280304Sjkim    if ((name_funcs_stack != NULL)
139280304Sjkim        && (sk_NAME_FUNCS_num(name_funcs_stack) > a->type)) {
140280304Sjkim        ret =
141280304Sjkim            sk_NAME_FUNCS_value(name_funcs_stack,
142280304Sjkim                                a->type)->hash_func(a->name);
143280304Sjkim    } else {
144280304Sjkim        ret = lh_strhash(a->name);
145280304Sjkim    }
146280304Sjkim    ret ^= a->type;
147280304Sjkim    return (ret);
148280304Sjkim}
14955714Skris
15055714Skrisconst char *OBJ_NAME_get(const char *name, int type)
151280304Sjkim{
152280304Sjkim    OBJ_NAME on, *ret;
153280304Sjkim    int num = 0, alias;
15455714Skris
155280304Sjkim    if (name == NULL)
156280304Sjkim        return (NULL);
157280304Sjkim    if ((names_lh == NULL) && !OBJ_NAME_init())
158280304Sjkim        return (NULL);
15955714Skris
160280304Sjkim    alias = type & OBJ_NAME_ALIAS;
161280304Sjkim    type &= ~OBJ_NAME_ALIAS;
16255714Skris
163280304Sjkim    on.name = name;
164280304Sjkim    on.type = type;
16555714Skris
166280304Sjkim    for (;;) {
167280304Sjkim        ret = lh_OBJ_NAME_retrieve(names_lh, &on);
168280304Sjkim        if (ret == NULL)
169280304Sjkim            return (NULL);
170280304Sjkim        if ((ret->alias) && !alias) {
171280304Sjkim            if (++num > 10)
172280304Sjkim                return (NULL);
173280304Sjkim            on.name = ret->data;
174280304Sjkim        } else {
175280304Sjkim            return (ret->data);
176280304Sjkim        }
177280304Sjkim    }
178280304Sjkim}
17955714Skris
18055714Skrisint OBJ_NAME_add(const char *name, int type, const char *data)
181280304Sjkim{
182280304Sjkim    OBJ_NAME *onp, *ret;
183280304Sjkim    int alias;
18455714Skris
185280304Sjkim    if ((names_lh == NULL) && !OBJ_NAME_init())
186280304Sjkim        return (0);
18755714Skris
188280304Sjkim    alias = type & OBJ_NAME_ALIAS;
189280304Sjkim    type &= ~OBJ_NAME_ALIAS;
19055714Skris
191280304Sjkim    onp = (OBJ_NAME *)OPENSSL_malloc(sizeof(OBJ_NAME));
192280304Sjkim    if (onp == NULL) {
193280304Sjkim        /* ERROR */
194280304Sjkim        return (0);
195280304Sjkim    }
19655714Skris
197280304Sjkim    onp->name = name;
198280304Sjkim    onp->alias = alias;
199280304Sjkim    onp->type = type;
200280304Sjkim    onp->data = data;
20155714Skris
202280304Sjkim    ret = lh_OBJ_NAME_insert(names_lh, onp);
203280304Sjkim    if (ret != NULL) {
204280304Sjkim        /* free things */
205280304Sjkim        if ((name_funcs_stack != NULL)
206280304Sjkim            && (sk_NAME_FUNCS_num(name_funcs_stack) > ret->type)) {
207280304Sjkim            /*
208280304Sjkim             * XXX: I'm not sure I understand why the free function should
209280304Sjkim             * get three arguments... -- Richard Levitte
210280304Sjkim             */
211280304Sjkim            sk_NAME_FUNCS_value(name_funcs_stack,
212280304Sjkim                                ret->type)->free_func(ret->name, ret->type,
213280304Sjkim                                                      ret->data);
214280304Sjkim        }
215280304Sjkim        OPENSSL_free(ret);
216280304Sjkim    } else {
217280304Sjkim        if (lh_OBJ_NAME_error(names_lh)) {
218280304Sjkim            /* ERROR */
219280304Sjkim            return (0);
220280304Sjkim        }
221280304Sjkim    }
222280304Sjkim    return (1);
223280304Sjkim}
22455714Skris
22555714Skrisint OBJ_NAME_remove(const char *name, int type)
226280304Sjkim{
227280304Sjkim    OBJ_NAME on, *ret;
22855714Skris
229280304Sjkim    if (names_lh == NULL)
230280304Sjkim        return (0);
23155714Skris
232280304Sjkim    type &= ~OBJ_NAME_ALIAS;
233280304Sjkim    on.name = name;
234280304Sjkim    on.type = type;
235280304Sjkim    ret = lh_OBJ_NAME_delete(names_lh, &on);
236280304Sjkim    if (ret != NULL) {
237280304Sjkim        /* free things */
238280304Sjkim        if ((name_funcs_stack != NULL)
239280304Sjkim            && (sk_NAME_FUNCS_num(name_funcs_stack) > ret->type)) {
240280304Sjkim            /*
241280304Sjkim             * XXX: I'm not sure I understand why the free function should
242280304Sjkim             * get three arguments... -- Richard Levitte
243280304Sjkim             */
244280304Sjkim            sk_NAME_FUNCS_value(name_funcs_stack,
245280304Sjkim                                ret->type)->free_func(ret->name, ret->type,
246280304Sjkim                                                      ret->data);
247280304Sjkim        }
248280304Sjkim        OPENSSL_free(ret);
249280304Sjkim        return (1);
250280304Sjkim    } else
251280304Sjkim        return (0);
252280304Sjkim}
25355714Skris
254280304Sjkimstruct doall {
255280304Sjkim    int type;
256280304Sjkim    void (*fn) (const OBJ_NAME *, void *arg);
257280304Sjkim    void *arg;
258280304Sjkim};
259109998Smarkm
260280304Sjkimstatic void do_all_fn_doall_arg(const OBJ_NAME *name, struct doall *d)
261280304Sjkim{
262280304Sjkim    if (name->type == d->type)
263280304Sjkim        d->fn(name, d->arg);
264280304Sjkim}
265109998Smarkm
266238405Sjkimstatic IMPLEMENT_LHASH_DOALL_ARG_FN(do_all_fn, const OBJ_NAME, struct doall)
267109998Smarkm
268280304Sjkimvoid OBJ_NAME_do_all(int type, void (*fn) (const OBJ_NAME *, void *arg),
269280304Sjkim                     void *arg)
270280304Sjkim{
271280304Sjkim    struct doall d;
272109998Smarkm
273280304Sjkim    d.type = type;
274280304Sjkim    d.fn = fn;
275280304Sjkim    d.arg = arg;
276109998Smarkm
277280304Sjkim    lh_OBJ_NAME_doall_arg(names_lh, LHASH_DOALL_ARG_FN(do_all_fn),
278280304Sjkim                          struct doall, &d);
279280304Sjkim}
280109998Smarkm
281280304Sjkimstruct doall_sorted {
282280304Sjkim    int type;
283280304Sjkim    int n;
284280304Sjkim    const OBJ_NAME **names;
285280304Sjkim};
286109998Smarkm
287280304Sjkimstatic void do_all_sorted_fn(const OBJ_NAME *name, void *d_)
288280304Sjkim{
289280304Sjkim    struct doall_sorted *d = d_;
290109998Smarkm
291280304Sjkim    if (name->type != d->type)
292280304Sjkim        return;
293109998Smarkm
294280304Sjkim    d->names[d->n++] = name;
295280304Sjkim}
296109998Smarkm
297280304Sjkimstatic int do_all_sorted_cmp(const void *n1_, const void *n2_)
298280304Sjkim{
299280304Sjkim    const OBJ_NAME *const *n1 = n1_;
300280304Sjkim    const OBJ_NAME *const *n2 = n2_;
301109998Smarkm
302280304Sjkim    return strcmp((*n1)->name, (*n2)->name);
303280304Sjkim}
304109998Smarkm
305280304Sjkimvoid OBJ_NAME_do_all_sorted(int type,
306280304Sjkim                            void (*fn) (const OBJ_NAME *, void *arg),
307280304Sjkim                            void *arg)
308280304Sjkim{
309280304Sjkim    struct doall_sorted d;
310280304Sjkim    int n;
311109998Smarkm
312280304Sjkim    d.type = type;
313280304Sjkim    d.names =
314280304Sjkim        OPENSSL_malloc(lh_OBJ_NAME_num_items(names_lh) * sizeof *d.names);
315280304Sjkim    /* Really should return an error if !d.names...but its a void function! */
316284285Sjkim    if (d.names) {
317280304Sjkim        d.n = 0;
318280304Sjkim        OBJ_NAME_do_all(type, do_all_sorted_fn, &d);
319109998Smarkm
320280304Sjkim        qsort((void *)d.names, d.n, sizeof *d.names, do_all_sorted_cmp);
321109998Smarkm
322280304Sjkim        for (n = 0; n < d.n; ++n)
323280304Sjkim            fn(d.names[n], arg);
324109998Smarkm
325280304Sjkim        OPENSSL_free((void *)d.names);
326280304Sjkim    }
327280304Sjkim}
328109998Smarkm
32955714Skrisstatic int free_type;
33055714Skris
331238405Sjkimstatic void names_lh_free_doall(OBJ_NAME *onp)
332280304Sjkim{
333280304Sjkim    if (onp == NULL)
334280304Sjkim        return;
33555714Skris
336280304Sjkim    if (free_type < 0 || free_type == onp->type)
337280304Sjkim        OBJ_NAME_remove(onp->name, onp->type);
338280304Sjkim}
33955714Skris
340238405Sjkimstatic IMPLEMENT_LHASH_DOALL_FN(names_lh_free, OBJ_NAME)
341109998Smarkm
34259191Skrisstatic void name_funcs_free(NAME_FUNCS *ptr)
343280304Sjkim{
344280304Sjkim    OPENSSL_free(ptr);
345280304Sjkim}
34659191Skris
34755714Skrisvoid OBJ_NAME_cleanup(int type)
348280304Sjkim{
349280304Sjkim    unsigned long down_load;
35055714Skris
351280304Sjkim    if (names_lh == NULL)
352280304Sjkim        return;
35355714Skris
354280304Sjkim    free_type = type;
355280304Sjkim    down_load = lh_OBJ_NAME_down_load(names_lh);
356280304Sjkim    lh_OBJ_NAME_down_load(names_lh) = 0;
35755714Skris
358280304Sjkim    lh_OBJ_NAME_doall(names_lh, LHASH_DOALL_FN(names_lh_free));
359280304Sjkim    if (type < 0) {
360280304Sjkim        lh_OBJ_NAME_free(names_lh);
361280304Sjkim        sk_NAME_FUNCS_pop_free(name_funcs_stack, name_funcs_free);
362280304Sjkim        names_lh = NULL;
363280304Sjkim        name_funcs_stack = NULL;
364280304Sjkim    } else
365280304Sjkim        lh_OBJ_NAME_down_load(names_lh) = down_load;
366280304Sjkim}
367