1 /*
2 * Copyright 1998-2021 The OpenSSL Project Authors. All Rights Reserved.
3 *
4 * Licensed under the OpenSSL license (the "License"). You may not use
5 * this file except in compliance with the License. You can obtain a copy
6 * in the file LICENSE in the source distribution or at
7 * https://www.openssl.org/source/license.html
8 */
9
10 #include <stdio.h>
11 #include <stdlib.h>
12 #include <string.h>
13
14 #include <openssl/err.h>
15 #include <openssl/lhash.h>
16 #include <openssl/objects.h>
17 #include <openssl/safestack.h>
18 #include <openssl/e_os2.h>
19 #include "internal/thread_once.h"
20 #include "crypto/lhash.h"
21 #include "obj_local.h"
22 #include "e_os.h"
23
24 /*
25 * We define this wrapper for two reasons. Firstly, later versions of
26 * DEC C add linkage information to certain functions, which makes it
27 * tricky to use them as values to regular function pointers.
28 * Secondly, in the EDK2 build environment, the strcasecmp function is
29 * actually an external function with the Microsoft ABI, so we can't
30 * transparently assign function pointers to it.
31 */
32 #if defined(OPENSSL_SYS_VMS_DECC) || defined(OPENSSL_SYS_UEFI)
obj_strcasecmp(const char * a,const char * b)33 static int obj_strcasecmp(const char *a, const char *b)
34 {
35 return strcasecmp(a, b);
36 }
37 #else
38 #define obj_strcasecmp strcasecmp
39 #endif
40
41 /*
42 * I use the ex_data stuff to manage the identifiers for the obj_name_types
43 * that applications may define. I only really use the free function field.
44 */
45 static LHASH_OF(OBJ_NAME) *names_lh = NULL;
46 static int names_type_num = OBJ_NAME_TYPE_NUM;
47 static CRYPTO_RWLOCK *obj_lock = NULL;
48
49 struct name_funcs_st {
50 unsigned long (*hash_func) (const char *name);
51 int (*cmp_func) (const char *a, const char *b);
52 void (*free_func) (const char *, int, const char *);
53 };
54
55 static STACK_OF(NAME_FUNCS) *name_funcs_stack;
56
57 /*
58 * The LHASH callbacks now use the raw "void *" prototypes and do
59 * per-variable casting in the functions. This prevents function pointer
60 * casting without the need for macro-generated wrapper functions.
61 */
62
63 static unsigned long obj_name_hash(const OBJ_NAME *a);
64 static int obj_name_cmp(const OBJ_NAME *a, const OBJ_NAME *b);
65
66 static CRYPTO_ONCE init = CRYPTO_ONCE_STATIC_INIT;
DEFINE_RUN_ONCE_STATIC(o_names_init)67 DEFINE_RUN_ONCE_STATIC(o_names_init)
68 {
69 CRYPTO_mem_ctrl(CRYPTO_MEM_CHECK_DISABLE);
70 names_lh = NULL;
71 obj_lock = CRYPTO_THREAD_lock_new();
72 if (obj_lock != NULL)
73 names_lh = lh_OBJ_NAME_new(obj_name_hash, obj_name_cmp);
74 if (names_lh == NULL) {
75 CRYPTO_THREAD_lock_free(obj_lock);
76 obj_lock = NULL;
77 }
78 CRYPTO_mem_ctrl(CRYPTO_MEM_CHECK_ENABLE);
79 return names_lh != NULL && obj_lock != NULL;
80 }
81
OBJ_NAME_init(void)82 int OBJ_NAME_init(void)
83 {
84 return RUN_ONCE(&init, o_names_init);
85 }
86
OBJ_NAME_new_index(unsigned long (* hash_func)(const char *),int (* cmp_func)(const char *,const char *),void (* free_func)(const char *,int,const char *))87 int OBJ_NAME_new_index(unsigned long (*hash_func) (const char *),
88 int (*cmp_func) (const char *, const char *),
89 void (*free_func) (const char *, int, const char *))
90 {
91 int ret = 0, i, push;
92 NAME_FUNCS *name_funcs;
93
94 if (!OBJ_NAME_init())
95 return 0;
96
97 CRYPTO_THREAD_write_lock(obj_lock);
98
99 if (name_funcs_stack == NULL) {
100 CRYPTO_mem_ctrl(CRYPTO_MEM_CHECK_DISABLE);
101 name_funcs_stack = sk_NAME_FUNCS_new_null();
102 CRYPTO_mem_ctrl(CRYPTO_MEM_CHECK_ENABLE);
103 }
104 if (name_funcs_stack == NULL) {
105 /* ERROR */
106 goto out;
107 }
108 ret = names_type_num;
109 names_type_num++;
110 for (i = sk_NAME_FUNCS_num(name_funcs_stack); i < names_type_num; i++) {
111 CRYPTO_mem_ctrl(CRYPTO_MEM_CHECK_DISABLE);
112 name_funcs = OPENSSL_zalloc(sizeof(*name_funcs));
113 CRYPTO_mem_ctrl(CRYPTO_MEM_CHECK_ENABLE);
114 if (name_funcs == NULL) {
115 OBJerr(OBJ_F_OBJ_NAME_NEW_INDEX, ERR_R_MALLOC_FAILURE);
116 ret = 0;
117 goto out;
118 }
119 name_funcs->hash_func = openssl_lh_strcasehash;
120 name_funcs->cmp_func = obj_strcasecmp;
121 CRYPTO_mem_ctrl(CRYPTO_MEM_CHECK_DISABLE);
122
123 push = sk_NAME_FUNCS_push(name_funcs_stack, name_funcs);
124 CRYPTO_mem_ctrl(CRYPTO_MEM_CHECK_ENABLE);
125
126 if (!push) {
127 OBJerr(OBJ_F_OBJ_NAME_NEW_INDEX, ERR_R_MALLOC_FAILURE);
128 OPENSSL_free(name_funcs);
129 ret = 0;
130 goto out;
131 }
132 }
133 name_funcs = sk_NAME_FUNCS_value(name_funcs_stack, ret);
134 if (hash_func != NULL)
135 name_funcs->hash_func = hash_func;
136 if (cmp_func != NULL)
137 name_funcs->cmp_func = cmp_func;
138 if (free_func != NULL)
139 name_funcs->free_func = free_func;
140
141 out:
142 CRYPTO_THREAD_unlock(obj_lock);
143 return ret;
144 }
145
obj_name_cmp(const OBJ_NAME * a,const OBJ_NAME * b)146 static int obj_name_cmp(const OBJ_NAME *a, const OBJ_NAME *b)
147 {
148 int ret;
149
150 ret = a->type - b->type;
151 if (ret == 0) {
152 if ((name_funcs_stack != NULL)
153 && (sk_NAME_FUNCS_num(name_funcs_stack) > a->type)) {
154 ret = sk_NAME_FUNCS_value(name_funcs_stack,
155 a->type)->cmp_func(a->name, b->name);
156 } else
157 ret = strcasecmp(a->name, b->name);
158 }
159 return ret;
160 }
161
obj_name_hash(const OBJ_NAME * a)162 static unsigned long obj_name_hash(const OBJ_NAME *a)
163 {
164 unsigned long ret;
165
166 if ((name_funcs_stack != NULL)
167 && (sk_NAME_FUNCS_num(name_funcs_stack) > a->type)) {
168 ret =
169 sk_NAME_FUNCS_value(name_funcs_stack,
170 a->type)->hash_func(a->name);
171 } else {
172 ret = openssl_lh_strcasehash(a->name);
173 }
174 ret ^= a->type;
175 return ret;
176 }
177
OBJ_NAME_get(const char * name,int type)178 const char *OBJ_NAME_get(const char *name, int type)
179 {
180 OBJ_NAME on, *ret;
181 int num = 0, alias;
182 const char *value = NULL;
183
184 if (name == NULL)
185 return NULL;
186 if (!OBJ_NAME_init())
187 return NULL;
188 CRYPTO_THREAD_read_lock(obj_lock);
189
190 alias = type & OBJ_NAME_ALIAS;
191 type &= ~OBJ_NAME_ALIAS;
192
193 on.name = name;
194 on.type = type;
195
196 for (;;) {
197 ret = lh_OBJ_NAME_retrieve(names_lh, &on);
198 if (ret == NULL)
199 break;
200 if ((ret->alias) && !alias) {
201 if (++num > 10)
202 break;
203 on.name = ret->data;
204 } else {
205 value = ret->data;
206 break;
207 }
208 }
209
210 CRYPTO_THREAD_unlock(obj_lock);
211 return value;
212 }
213
OBJ_NAME_add(const char * name,int type,const char * data)214 int OBJ_NAME_add(const char *name, int type, const char *data)
215 {
216 OBJ_NAME *onp, *ret;
217 int alias, ok = 0;
218
219 if (!OBJ_NAME_init())
220 return 0;
221
222 alias = type & OBJ_NAME_ALIAS;
223 type &= ~OBJ_NAME_ALIAS;
224
225 onp = OPENSSL_malloc(sizeof(*onp));
226 if (onp == NULL)
227 return 0;
228
229 onp->name = name;
230 onp->alias = alias;
231 onp->type = type;
232 onp->data = data;
233
234 CRYPTO_THREAD_write_lock(obj_lock);
235
236 ret = lh_OBJ_NAME_insert(names_lh, onp);
237 if (ret != NULL) {
238 /* free things */
239 if ((name_funcs_stack != NULL)
240 && (sk_NAME_FUNCS_num(name_funcs_stack) > ret->type)) {
241 /*
242 * XXX: I'm not sure I understand why the free function should
243 * get three arguments... -- Richard Levitte
244 */
245 sk_NAME_FUNCS_value(name_funcs_stack,
246 ret->type)->free_func(ret->name, ret->type,
247 ret->data);
248 }
249 OPENSSL_free(ret);
250 } else {
251 if (lh_OBJ_NAME_error(names_lh)) {
252 /* ERROR */
253 OPENSSL_free(onp);
254 goto unlock;
255 }
256 }
257
258 ok = 1;
259
260 unlock:
261 CRYPTO_THREAD_unlock(obj_lock);
262 return ok;
263 }
264
OBJ_NAME_remove(const char * name,int type)265 int OBJ_NAME_remove(const char *name, int type)
266 {
267 OBJ_NAME on, *ret;
268 int ok = 0;
269
270 if (!OBJ_NAME_init())
271 return 0;
272
273 CRYPTO_THREAD_write_lock(obj_lock);
274
275 type &= ~OBJ_NAME_ALIAS;
276 on.name = name;
277 on.type = type;
278 ret = lh_OBJ_NAME_delete(names_lh, &on);
279 if (ret != NULL) {
280 /* free things */
281 if ((name_funcs_stack != NULL)
282 && (sk_NAME_FUNCS_num(name_funcs_stack) > ret->type)) {
283 /*
284 * XXX: I'm not sure I understand why the free function should
285 * get three arguments... -- Richard Levitte
286 */
287 sk_NAME_FUNCS_value(name_funcs_stack,
288 ret->type)->free_func(ret->name, ret->type,
289 ret->data);
290 }
291 OPENSSL_free(ret);
292 ok = 1;
293 }
294
295 CRYPTO_THREAD_unlock(obj_lock);
296 return ok;
297 }
298
299 typedef struct {
300 int type;
301 void (*fn) (const OBJ_NAME *, void *arg);
302 void *arg;
303 } OBJ_DOALL;
304
do_all_fn(const OBJ_NAME * name,OBJ_DOALL * d)305 static void do_all_fn(const OBJ_NAME *name, OBJ_DOALL *d)
306 {
307 if (name->type == d->type)
308 d->fn(name, d->arg);
309 }
310
311 IMPLEMENT_LHASH_DOALL_ARG_CONST(OBJ_NAME, OBJ_DOALL);
312
OBJ_NAME_do_all(int type,void (* fn)(const OBJ_NAME *,void * arg),void * arg)313 void OBJ_NAME_do_all(int type, void (*fn) (const OBJ_NAME *, void *arg),
314 void *arg)
315 {
316 OBJ_DOALL d;
317
318 d.type = type;
319 d.fn = fn;
320 d.arg = arg;
321
322 lh_OBJ_NAME_doall_OBJ_DOALL(names_lh, do_all_fn, &d);
323 }
324
325 struct doall_sorted {
326 int type;
327 int n;
328 const OBJ_NAME **names;
329 };
330
do_all_sorted_fn(const OBJ_NAME * name,void * d_)331 static void do_all_sorted_fn(const OBJ_NAME *name, void *d_)
332 {
333 struct doall_sorted *d = d_;
334
335 if (name->type != d->type)
336 return;
337
338 d->names[d->n++] = name;
339 }
340
do_all_sorted_cmp(const void * n1_,const void * n2_)341 static int do_all_sorted_cmp(const void *n1_, const void *n2_)
342 {
343 const OBJ_NAME *const *n1 = n1_;
344 const OBJ_NAME *const *n2 = n2_;
345
346 return strcmp((*n1)->name, (*n2)->name);
347 }
348
OBJ_NAME_do_all_sorted(int type,void (* fn)(const OBJ_NAME *,void * arg),void * arg)349 void OBJ_NAME_do_all_sorted(int type,
350 void (*fn) (const OBJ_NAME *, void *arg),
351 void *arg)
352 {
353 struct doall_sorted d;
354 int n;
355
356 d.type = type;
357 d.names =
358 OPENSSL_malloc(sizeof(*d.names) * lh_OBJ_NAME_num_items(names_lh));
359 /* Really should return an error if !d.names...but its a void function! */
360 if (d.names != NULL) {
361 d.n = 0;
362 OBJ_NAME_do_all(type, do_all_sorted_fn, &d);
363
364 qsort((void *)d.names, d.n, sizeof(*d.names), do_all_sorted_cmp);
365
366 for (n = 0; n < d.n; ++n)
367 fn(d.names[n], arg);
368
369 OPENSSL_free((void *)d.names);
370 }
371 }
372
373 static int free_type;
374
names_lh_free_doall(OBJ_NAME * onp)375 static void names_lh_free_doall(OBJ_NAME *onp)
376 {
377 if (onp == NULL)
378 return;
379
380 if (free_type < 0 || free_type == onp->type)
381 OBJ_NAME_remove(onp->name, onp->type);
382 }
383
name_funcs_free(NAME_FUNCS * ptr)384 static void name_funcs_free(NAME_FUNCS *ptr)
385 {
386 OPENSSL_free(ptr);
387 }
388
OBJ_NAME_cleanup(int type)389 void OBJ_NAME_cleanup(int type)
390 {
391 unsigned long down_load;
392
393 if (names_lh == NULL)
394 return;
395
396 free_type = type;
397 down_load = lh_OBJ_NAME_get_down_load(names_lh);
398 lh_OBJ_NAME_set_down_load(names_lh, 0);
399
400 lh_OBJ_NAME_doall(names_lh, names_lh_free_doall);
401 if (type < 0) {
402 lh_OBJ_NAME_free(names_lh);
403 sk_NAME_FUNCS_pop_free(name_funcs_stack, name_funcs_free);
404 CRYPTO_THREAD_lock_free(obj_lock);
405 names_lh = NULL;
406 name_funcs_stack = NULL;
407 obj_lock = NULL;
408 } else
409 lh_OBJ_NAME_set_down_load(names_lh, down_load);
410 }
411