1/* crypto/err/err_def.c */
2/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
3 * All rights reserved.
4 *
5 * This package is an SSL implementation written
6 * by Eric Young (eay@cryptsoft.com).
7 * The implementation was written so as to conform with Netscapes SSL.
8 *
9 * This library is free for commercial and non-commercial use as long as
10 * the following conditions are aheared to.  The following conditions
11 * apply to all code found in this distribution, be it the RC4, RSA,
12 * lhash, DES, etc., code; not just the SSL code.  The SSL documentation
13 * included with this distribution is covered by the same copyright terms
14 * except that the holder is Tim Hudson (tjh@cryptsoft.com).
15 *
16 * Copyright remains Eric Young's, and as such any Copyright notices in
17 * the code are not to be removed.
18 * If this package is used in a product, Eric Young should be given attribution
19 * as the author of the parts of the library used.
20 * This can be in the form of a textual message at program startup or
21 * in documentation (online or textual) provided with the package.
22 *
23 * Redistribution and use in source and binary forms, with or without
24 * modification, are permitted provided that the following conditions
25 * are met:
26 * 1. Redistributions of source code must retain the copyright
27 *    notice, this list of conditions and the following disclaimer.
28 * 2. Redistributions in binary form must reproduce the above copyright
29 *    notice, this list of conditions and the following disclaimer in the
30 *    documentation and/or other materials provided with the distribution.
31 * 3. All advertising materials mentioning features or use of this software
32 *    must display the following acknowledgement:
33 *    "This product includes cryptographic software written by
34 *     Eric Young (eay@cryptsoft.com)"
35 *    The word 'cryptographic' can be left out if the rouines from the library
36 *    being used are not cryptographic related :-).
37 * 4. If you include any Windows specific code (or a derivative thereof) from
38 *    the apps directory (application code) you must include an acknowledgement:
39 *    "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
40 *
41 * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
42 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
43 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
44 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
45 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
46 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
47 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
48 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
49 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
50 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
51 * SUCH DAMAGE.
52 *
53 * The licence and distribution terms for any publically available version or
54 * derivative of this code cannot be changed.  i.e. this code cannot simply be
55 * copied and put under another distribution licence
56 * [including the GNU Public Licence.]
57 */
58/* ====================================================================
59 * Copyright (c) 1998-2001 The OpenSSL Project.  All rights reserved.
60 *
61 * Redistribution and use in source and binary forms, with or without
62 * modification, are permitted provided that the following conditions
63 * are met:
64 *
65 * 1. Redistributions of source code must retain the above copyright
66 *    notice, this list of conditions and the following disclaimer.
67 *
68 * 2. Redistributions in binary form must reproduce the above copyright
69 *    notice, this list of conditions and the following disclaimer in
70 *    the documentation and/or other materials provided with the
71 *    distribution.
72 *
73 * 3. All advertising materials mentioning features or use of this
74 *    software must display the following acknowledgment:
75 *    "This product includes software developed by the OpenSSL Project
76 *    for use in the OpenSSL Toolkit. (http://www.openssl.org/)"
77 *
78 * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
79 *    endorse or promote products derived from this software without
80 *    prior written permission. For written permission, please contact
81 *    openssl-core@openssl.org.
82 *
83 * 5. Products derived from this software may not be called "OpenSSL"
84 *    nor may "OpenSSL" appear in their names without prior written
85 *    permission of the OpenSSL Project.
86 *
87 * 6. Redistributions of any form whatsoever must retain the following
88 *    acknowledgment:
89 *    "This product includes software developed by the OpenSSL Project
90 *    for use in the OpenSSL Toolkit (http://www.openssl.org/)"
91 *
92 * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
93 * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
94 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
95 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE OpenSSL PROJECT OR
96 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
97 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
98 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
99 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
100 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
101 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
102 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
103 * OF THE POSSIBILITY OF SUCH DAMAGE.
104 * ====================================================================
105 *
106 * This product includes cryptographic software written by Eric Young
107 * (eay@cryptsoft.com).  This product includes software written by Tim
108 * Hudson (tjh@cryptsoft.com).
109 *
110 */
111
112#include <stdio.h>
113#include <stdarg.h>
114#include <string.h>
115#include "cryptlib.h"
116#include <openssl/lhash.h>
117#include <openssl/crypto.h>
118#include <openssl/buffer.h>
119#include <openssl/bio.h>
120#include <openssl/err.h>
121
122#define err_clear_data(p,i) \
123	do { \
124	if (((p)->err_data[i] != NULL) && \
125		(p)->err_data_flags[i] & ERR_TXT_MALLOCED) \
126		{  \
127		OPENSSL_free((p)->err_data[i]); \
128		(p)->err_data[i]=NULL; \
129		} \
130	(p)->err_data_flags[i]=0; \
131	} while(0)
132
133#define err_clear(p,i) \
134	do { \
135	(p)->err_flags[i]=0; \
136	(p)->err_buffer[i]=0; \
137	err_clear_data(p,i); \
138	(p)->err_file[i]=NULL; \
139	(p)->err_line[i]= -1; \
140	} while(0)
141
142static void err_load_strings(int lib, ERR_STRING_DATA *str);
143
144static void ERR_STATE_free(ERR_STATE *s);
145
146/* Define the predeclared (but externally opaque) "ERR_FNS" type */
147struct st_ERR_FNS
148	{
149	/* Works on the "error_hash" string table */
150	LHASH *(*cb_err_get)(int create);
151	void (*cb_err_del)(void);
152	ERR_STRING_DATA *(*cb_err_get_item)(const ERR_STRING_DATA *);
153	ERR_STRING_DATA *(*cb_err_set_item)(ERR_STRING_DATA *);
154	ERR_STRING_DATA *(*cb_err_del_item)(ERR_STRING_DATA *);
155	/* Works on the "thread_hash" error-state table */
156	LHASH *(*cb_thread_get)(int create);
157	void (*cb_thread_release)(LHASH **hash);
158	ERR_STATE *(*cb_thread_get_item)(const ERR_STATE *);
159	ERR_STATE *(*cb_thread_set_item)(ERR_STATE *);
160	void (*cb_thread_del_item)(const ERR_STATE *);
161	/* Returns the next available error "library" numbers */
162	int (*cb_get_next_lib)(void);
163	};
164
165/* Predeclarations of the "err_defaults" functions */
166static LHASH *int_err_get(int create);
167static void int_err_del(void);
168static ERR_STRING_DATA *int_err_get_item(const ERR_STRING_DATA *);
169static ERR_STRING_DATA *int_err_set_item(ERR_STRING_DATA *);
170static ERR_STRING_DATA *int_err_del_item(ERR_STRING_DATA *);
171static LHASH *int_thread_get(int create);
172static void int_thread_release(LHASH **hash);
173static ERR_STATE *int_thread_get_item(const ERR_STATE *);
174static ERR_STATE *int_thread_set_item(ERR_STATE *);
175static void int_thread_del_item(const ERR_STATE *);
176static int int_err_get_next_lib(void);
177/* The static ERR_FNS table using these defaults functions */
178static const ERR_FNS err_defaults =
179	{
180	int_err_get,
181	int_err_del,
182	int_err_get_item,
183	int_err_set_item,
184	int_err_del_item,
185	int_thread_get,
186	int_thread_release,
187	int_thread_get_item,
188	int_thread_set_item,
189	int_thread_del_item,
190	int_err_get_next_lib
191	};
192
193/* The replacable table of ERR_FNS functions we use at run-time */
194static const ERR_FNS *err_fns = NULL;
195
196/* Eg. rather than using "err_get()", use "ERRFN(err_get)()". */
197#define ERRFN(a) err_fns->cb_##a
198
199/* The internal state used by "err_defaults" - as such, the setting, reading,
200 * creating, and deleting of this data should only be permitted via the
201 * "err_defaults" functions. This way, a linked module can completely defer all
202 * ERR state operation (together with requisite locking) to the implementations
203 * and state in the loading application. */
204static LHASH *int_error_hash = NULL;
205static LHASH *int_thread_hash = NULL;
206static int int_thread_hash_references = 0;
207static int int_err_library_number= ERR_LIB_USER;
208
209/* Internal function that checks whether "err_fns" is set and if not, sets it to
210 * the defaults. */
211static void err_fns_check(void)
212	{
213	if (err_fns) return;
214
215	CRYPTO_w_lock(CRYPTO_LOCK_ERR);
216	if (!err_fns)
217		err_fns = &err_defaults;
218	CRYPTO_w_unlock(CRYPTO_LOCK_ERR);
219	}
220
221/* API functions to get or set the underlying ERR functions. */
222
223const ERR_FNS *ERR_get_implementation(void)
224	{
225	err_fns_check();
226	return err_fns;
227	}
228
229int ERR_set_implementation(const ERR_FNS *fns)
230	{
231	int ret = 0;
232
233	CRYPTO_w_lock(CRYPTO_LOCK_ERR);
234	/* It's too late if 'err_fns' is non-NULL. BTW: not much point setting
235	 * an error is there?! */
236	if (!err_fns)
237		{
238		err_fns = fns;
239		ret = 1;
240		}
241	CRYPTO_w_unlock(CRYPTO_LOCK_ERR);
242	return ret;
243	}
244
245/* These are the callbacks provided to "lh_new()" when creating the LHASH tables
246 * internal to the "err_defaults" implementation. */
247
248/* static unsigned long err_hash(ERR_STRING_DATA *a); */
249static unsigned long err_hash(const void *a_void);
250/* static int err_cmp(ERR_STRING_DATA *a, ERR_STRING_DATA *b); */
251static int err_cmp(const void *a_void, const void *b_void);
252/* static unsigned long pid_hash(ERR_STATE *pid); */
253static unsigned long pid_hash(const void *pid_void);
254/* static int pid_cmp(ERR_STATE *a,ERR_STATE *pid); */
255static int pid_cmp(const void *a_void,const void *pid_void);
256
257/* The internal functions used in the "err_defaults" implementation */
258
259static LHASH *int_err_get(int create)
260	{
261	LHASH *ret = NULL;
262
263	CRYPTO_w_lock(CRYPTO_LOCK_ERR);
264	if (!int_error_hash && create)
265		{
266		CRYPTO_push_info("int_err_get (err.c)");
267		int_error_hash = lh_new(err_hash, err_cmp);
268		CRYPTO_pop_info();
269		}
270	if (int_error_hash)
271		ret = int_error_hash;
272	CRYPTO_w_unlock(CRYPTO_LOCK_ERR);
273
274	return ret;
275	}
276
277static void int_err_del(void)
278	{
279	CRYPTO_w_lock(CRYPTO_LOCK_ERR);
280	if (int_error_hash)
281		{
282		lh_free(int_error_hash);
283		int_error_hash = NULL;
284		}
285	CRYPTO_w_unlock(CRYPTO_LOCK_ERR);
286	}
287
288static ERR_STRING_DATA *int_err_get_item(const ERR_STRING_DATA *d)
289	{
290	ERR_STRING_DATA *p;
291	LHASH *hash;
292
293	err_fns_check();
294	hash = ERRFN(err_get)(0);
295	if (!hash)
296		return NULL;
297
298	CRYPTO_r_lock(CRYPTO_LOCK_ERR);
299	p = (ERR_STRING_DATA *)lh_retrieve(hash, d);
300	CRYPTO_r_unlock(CRYPTO_LOCK_ERR);
301
302	return p;
303	}
304
305static ERR_STRING_DATA *int_err_set_item(ERR_STRING_DATA *d)
306	{
307	ERR_STRING_DATA *p;
308	LHASH *hash;
309
310	err_fns_check();
311	hash = ERRFN(err_get)(1);
312	if (!hash)
313		return NULL;
314
315	CRYPTO_w_lock(CRYPTO_LOCK_ERR);
316	p = (ERR_STRING_DATA *)lh_insert(hash, d);
317	CRYPTO_w_unlock(CRYPTO_LOCK_ERR);
318
319	return p;
320	}
321
322static ERR_STRING_DATA *int_err_del_item(ERR_STRING_DATA *d)
323	{
324	ERR_STRING_DATA *p;
325	LHASH *hash;
326
327	err_fns_check();
328	hash = ERRFN(err_get)(0);
329	if (!hash)
330		return NULL;
331
332	CRYPTO_w_lock(CRYPTO_LOCK_ERR);
333	p = (ERR_STRING_DATA *)lh_delete(hash, d);
334	CRYPTO_w_unlock(CRYPTO_LOCK_ERR);
335
336	return p;
337	}
338
339static LHASH *int_thread_get(int create)
340	{
341	LHASH *ret = NULL;
342
343	CRYPTO_w_lock(CRYPTO_LOCK_ERR);
344	if (!int_thread_hash && create)
345		{
346		CRYPTO_push_info("int_thread_get (err.c)");
347		int_thread_hash = lh_new(pid_hash, pid_cmp);
348		CRYPTO_pop_info();
349		}
350	if (int_thread_hash)
351		{
352		int_thread_hash_references++;
353		ret = int_thread_hash;
354		}
355	CRYPTO_w_unlock(CRYPTO_LOCK_ERR);
356	return ret;
357	}
358
359static void int_thread_release(LHASH **hash)
360	{
361	int i;
362
363	if (hash == NULL || *hash == NULL)
364		return;
365
366	i = CRYPTO_add(&int_thread_hash_references, -1, CRYPTO_LOCK_ERR);
367
368#ifdef REF_PRINT
369	fprintf(stderr,"%4d:%s\n",int_thread_hash_references,"ERR");
370#endif
371	if (i > 0) return;
372#ifdef REF_CHECK
373	if (i < 0)
374		{
375		fprintf(stderr,"int_thread_release, bad reference count\n");
376		abort(); /* ok */
377		}
378#endif
379	*hash = NULL;
380	}
381
382static ERR_STATE *int_thread_get_item(const ERR_STATE *d)
383	{
384	ERR_STATE *p;
385	LHASH *hash;
386
387	err_fns_check();
388	hash = ERRFN(thread_get)(0);
389	if (!hash)
390		return NULL;
391
392	CRYPTO_r_lock(CRYPTO_LOCK_ERR);
393	p = (ERR_STATE *)lh_retrieve(hash, d);
394	CRYPTO_r_unlock(CRYPTO_LOCK_ERR);
395
396	ERRFN(thread_release)(&hash);
397	return p;
398	}
399
400static ERR_STATE *int_thread_set_item(ERR_STATE *d)
401	{
402	ERR_STATE *p;
403	LHASH *hash;
404
405	err_fns_check();
406	hash = ERRFN(thread_get)(1);
407	if (!hash)
408		return NULL;
409
410	CRYPTO_w_lock(CRYPTO_LOCK_ERR);
411	p = (ERR_STATE *)lh_insert(hash, d);
412	CRYPTO_w_unlock(CRYPTO_LOCK_ERR);
413
414	ERRFN(thread_release)(&hash);
415	return p;
416	}
417
418static void int_thread_del_item(const ERR_STATE *d)
419	{
420	ERR_STATE *p;
421	LHASH *hash;
422
423	err_fns_check();
424	hash = ERRFN(thread_get)(0);
425	if (!hash)
426		return;
427
428	CRYPTO_w_lock(CRYPTO_LOCK_ERR);
429	p = (ERR_STATE *)lh_delete(hash, d);
430	/* make sure we don't leak memory */
431	if (int_thread_hash_references == 1
432		&& int_thread_hash && (lh_num_items(int_thread_hash) == 0))
433		{
434		lh_free(int_thread_hash);
435		int_thread_hash = NULL;
436		}
437	CRYPTO_w_unlock(CRYPTO_LOCK_ERR);
438
439	ERRFN(thread_release)(&hash);
440	if (p)
441		ERR_STATE_free(p);
442	}
443
444static int int_err_get_next_lib(void)
445	{
446	int ret;
447
448	CRYPTO_w_lock(CRYPTO_LOCK_ERR);
449	ret = int_err_library_number++;
450	CRYPTO_w_unlock(CRYPTO_LOCK_ERR);
451
452	return ret;
453	}
454
455static void ERR_STATE_free(ERR_STATE *s)
456	{
457	int i;
458
459	if (s == NULL)
460	    return;
461
462	for (i=0; i<ERR_NUM_ERRORS; i++)
463		{
464		err_clear_data(s,i);
465		}
466	OPENSSL_free(s);
467	}
468
469static void err_load_strings(int lib, ERR_STRING_DATA *str)
470	{
471	while (str->error)
472		{
473		if (lib)
474			str->error|=ERR_PACK(lib,0,0);
475		ERRFN(err_set_item)(str);
476		str++;
477		}
478	}
479
480void ERR_load_strings(int lib, ERR_STRING_DATA *str)
481	{
482	err_fns_check();
483	err_load_strings(lib, str);
484	}
485
486void ERR_unload_strings(int lib, ERR_STRING_DATA *str)
487	{
488	while (str->error)
489		{
490		if (lib)
491			str->error|=ERR_PACK(lib,0,0);
492		ERRFN(err_del_item)(str);
493		str++;
494		}
495	}
496
497void ERR_free_strings(void)
498	{
499	err_fns_check();
500	ERRFN(err_del)();
501	}
502
503LHASH *ERR_get_string_table(void)
504	{
505	err_fns_check();
506	return ERRFN(err_get)(0);
507	}
508
509LHASH *ERR_get_err_state_table(void)
510	{
511	err_fns_check();
512	return ERRFN(thread_get)(0);
513	}
514
515void ERR_release_err_state_table(LHASH **hash)
516	{
517	err_fns_check();
518	ERRFN(thread_release)(hash);
519	}
520
521const char *ERR_lib_error_string(unsigned long e)
522	{
523	ERR_STRING_DATA d,*p;
524	unsigned long l;
525
526	err_fns_check();
527	l=ERR_GET_LIB(e);
528	d.error=ERR_PACK(l,0,0);
529	p=ERRFN(err_get_item)(&d);
530	return((p == NULL)?NULL:p->string);
531	}
532
533const char *ERR_func_error_string(unsigned long e)
534	{
535	ERR_STRING_DATA d,*p;
536	unsigned long l,f;
537
538	err_fns_check();
539	l=ERR_GET_LIB(e);
540	f=ERR_GET_FUNC(e);
541	d.error=ERR_PACK(l,f,0);
542	p=ERRFN(err_get_item)(&d);
543	return((p == NULL)?NULL:p->string);
544	}
545
546const char *ERR_reason_error_string(unsigned long e)
547	{
548	ERR_STRING_DATA d,*p=NULL;
549	unsigned long l,r;
550
551	err_fns_check();
552	l=ERR_GET_LIB(e);
553	r=ERR_GET_REASON(e);
554	d.error=ERR_PACK(l,0,r);
555	p=ERRFN(err_get_item)(&d);
556	if (!p)
557		{
558		d.error=ERR_PACK(0,0,r);
559		p=ERRFN(err_get_item)(&d);
560		}
561	return((p == NULL)?NULL:p->string);
562	}
563
564/* static unsigned long err_hash(ERR_STRING_DATA *a) */
565static unsigned long err_hash(const void *a_void)
566	{
567	unsigned long ret,l;
568
569	l=((const ERR_STRING_DATA *)a_void)->error;
570	ret=l^ERR_GET_LIB(l)^ERR_GET_FUNC(l);
571	return(ret^ret%19*13);
572	}
573
574/* static int err_cmp(ERR_STRING_DATA *a, ERR_STRING_DATA *b) */
575static int err_cmp(const void *a_void, const void *b_void)
576	{
577	return((int)(((const ERR_STRING_DATA *)a_void)->error -
578			((const ERR_STRING_DATA *)b_void)->error));
579	}
580
581/* static unsigned long pid_hash(ERR_STATE *a) */
582static unsigned long pid_hash(const void *a_void)
583	{
584	return(((const ERR_STATE *)a_void)->pid*13);
585	}
586
587/* static int pid_cmp(ERR_STATE *a, ERR_STATE *b) */
588static int pid_cmp(const void *a_void, const void *b_void)
589	{
590	return((int)((long)((const ERR_STATE *)a_void)->pid -
591			(long)((const ERR_STATE *)b_void)->pid));
592	}
593#ifdef OPENSSL_FIPS
594static void int_err_remove_state(unsigned long pid)
595#else
596void ERR_remove_state(unsigned long pid)
597#endif
598	{
599	ERR_STATE tmp;
600
601	err_fns_check();
602	if (pid == 0)
603		pid=(unsigned long)CRYPTO_thread_id();
604	tmp.pid=pid;
605	/* thread_del_item automatically destroys the LHASH if the number of
606	 * items reaches zero. */
607	ERRFN(thread_del_item)(&tmp);
608	}
609
610#ifdef OPENSSL_FIPS
611	static ERR_STATE *int_err_get_state(void)
612#else
613ERR_STATE *ERR_get_state(void)
614#endif
615	{
616	static ERR_STATE fallback;
617	ERR_STATE *ret,tmp,*tmpp=NULL;
618	int i;
619	unsigned long pid;
620
621	err_fns_check();
622	pid=(unsigned long)CRYPTO_thread_id();
623	tmp.pid=pid;
624	ret=ERRFN(thread_get_item)(&tmp);
625
626	/* ret == the error state, if NULL, make a new one */
627	if (ret == NULL)
628		{
629		ret=(ERR_STATE *)OPENSSL_malloc(sizeof(ERR_STATE));
630		if (ret == NULL) return(&fallback);
631		ret->pid=pid;
632		ret->top=0;
633		ret->bottom=0;
634		for (i=0; i<ERR_NUM_ERRORS; i++)
635			{
636			ret->err_data[i]=NULL;
637			ret->err_data_flags[i]=0;
638			}
639		tmpp = ERRFN(thread_set_item)(ret);
640		/* To check if insertion failed, do a get. */
641		if (ERRFN(thread_get_item)(ret) != ret)
642			{
643			ERR_STATE_free(ret); /* could not insert it */
644			return(&fallback);
645			}
646		/* If a race occured in this function and we came second, tmpp
647		 * is the first one that we just replaced. */
648		if (tmpp)
649			ERR_STATE_free(tmpp);
650		}
651	return ret;
652	}
653
654#ifdef OPENSSL_FIPS
655void int_ERR_lib_init(void)
656	{
657	int_ERR_set_state_func(int_err_get_state, int_err_remove_state);
658	}
659#endif
660
661int ERR_get_next_error_library(void)
662	{
663	err_fns_check();
664	return ERRFN(get_next_lib)();
665	}
666