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