6eec77a1545052dd54c84ed2619baf1b26105567
[openssl.git] / crypto / err / err.c
1 /* crypto/err/err.c */
2 /* Copyright (C) 1995-1997 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 #include <stdio.h>
60 #include "lhash.h"
61 #include "crypto.h"
62 #include "cryptlib.h"
63 #include "buffer.h"
64 #include "err.h"
65 #include "crypto.h"
66
67
68 static LHASH *error_hash=NULL;
69 static LHASH *thread_hash=NULL;
70
71 #ifndef NOPROTO
72 static unsigned long err_hash(ERR_STRING_DATA *a);
73 static int err_cmp(ERR_STRING_DATA *a, ERR_STRING_DATA *b);
74 static unsigned long pid_hash(ERR_STATE *pid);
75 static int pid_cmp(ERR_STATE *a,ERR_STATE *pid);
76 #else
77 static unsigned long err_hash();
78 static int err_cmp();
79 static unsigned long pid_hash();
80 static int pid_cmp();
81 #endif
82
83 #ifndef NO_ERR
84 static ERR_STRING_DATA ERR_str_libraries[]=
85         {
86 {ERR_PACK(ERR_LIB_NONE,0,0)             ,"unknown library"},
87 {ERR_PACK(ERR_LIB_SYS,0,0)              ,"system library"},
88 {ERR_PACK(ERR_LIB_BN,0,0)               ,"bignum routines"},
89 {ERR_PACK(ERR_LIB_RSA,0,0)              ,"rsa routines"},
90 {ERR_PACK(ERR_LIB_DH,0,0)               ,"Diffie-Hellman routines"},
91 {ERR_PACK(ERR_LIB_EVP,0,0)              ,"digital envelope routines"},
92 {ERR_PACK(ERR_LIB_BUF,0,0)              ,"memory buffer routines"},
93 {ERR_PACK(ERR_LIB_BIO,0,0)              ,"BIO routines"},
94 {ERR_PACK(ERR_LIB_OBJ,0,0)              ,"object identifier routines"},
95 {ERR_PACK(ERR_LIB_PEM,0,0)              ,"PEM routines"},
96 {ERR_PACK(ERR_LIB_ASN1,0,0)             ,"asn1 encoding routines"},
97 {ERR_PACK(ERR_LIB_X509,0,0)             ,"x509 certificate routines"},
98 {ERR_PACK(ERR_LIB_CONF,0,0)             ,"configuation file routines"},
99 {ERR_PACK(ERR_LIB_METH,0,0)             ,"X509 lookup 'method' routines"},
100 {ERR_PACK(ERR_LIB_SSL,0,0)              ,"SSL routines"},
101 {ERR_PACK(ERR_LIB_RSAREF,0,0)           ,"RSAref routines"},
102 {ERR_PACK(ERR_LIB_PROXY,0,0)            ,"Proxy routines"},
103 {ERR_PACK(ERR_LIB_BIO,0,0)              ,"BIO routines"},
104 {ERR_PACK(ERR_LIB_PKCS7,0,0)            ,"PKCS7 routines"},
105 {0,NULL},
106         };
107
108 static ERR_STRING_DATA ERR_str_functs[]=
109         {
110         {ERR_PACK(0,SYS_F_FOPEN,0),             "fopen"},
111         {ERR_PACK(0,SYS_F_CONNECT,0),           "connect"},
112         {ERR_PACK(0,SYS_F_GETSERVBYNAME,0),     "getservbyname"},
113         {ERR_PACK(0,SYS_F_SOCKET,0),            "socket"}, 
114         {ERR_PACK(0,SYS_F_IOCTLSOCKET,0),       "ioctlsocket"},
115         {ERR_PACK(0,SYS_F_BIND,0),              "bind"},
116         {ERR_PACK(0,SYS_F_LISTEN,0),            "listen"},
117         {ERR_PACK(0,SYS_F_ACCEPT,0),            "accept"},
118 #ifdef WINDOWS
119         {ERR_PACK(0,SYS_F_WSASTARTUP,0),        "WSAstartup"},
120 #endif
121         {0,NULL},
122         };
123
124 static ERR_STRING_DATA ERR_str_reasons[]=
125         {
126 {ERR_R_FATAL                             ,"fatal"},
127 {ERR_R_SYS_LIB                          ,"system lib"},
128 {ERR_R_BN_LIB                           ,"BN lib"},
129 {ERR_R_RSA_LIB                          ,"RSA lib"},
130 {ERR_R_DH_LIB                           ,"DH lib"},
131 {ERR_R_EVP_LIB                          ,"EVP lib"},
132 {ERR_R_BUF_LIB                          ,"BUF lib"},
133 {ERR_R_BIO_LIB                          ,"BIO lib"},
134 {ERR_R_OBJ_LIB                          ,"OBJ lib"},
135 {ERR_R_PEM_LIB                          ,"PEM lib"},
136 {ERR_R_X509_LIB                         ,"X509 lib"},
137 {ERR_R_METH_LIB                         ,"METH lib"},
138 {ERR_R_ASN1_LIB                         ,"ASN1 lib"},
139 {ERR_R_CONF_LIB                         ,"CONF lib"},
140 {ERR_R_SSL_LIB                          ,"SSL lib"},
141 {ERR_R_PROXY_LIB                        ,"PROXY lib"},
142 {ERR_R_BIO_LIB                          ,"BIO lib"},
143 {ERR_R_PKCS7_LIB                        ,"PKCS7 lib"},
144 {ERR_R_MALLOC_FAILURE                   ,"Malloc failure"},
145 {ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED      ,"called a fuction you should not call"},
146 {0,NULL},
147         };
148 #endif
149
150 void ERR_load_ERR_strings()
151         {
152         static int init=1;
153
154         if (init)
155                 {
156                 CRYPTO_w_lock(CRYPTO_LOCK_ERR);
157                 if (init == 0)
158                         {
159                         CRYPTO_w_unlock(CRYPTO_LOCK_ERR);
160                         return;
161                         }
162                 init=0;
163                 CRYPTO_w_unlock(CRYPTO_LOCK_ERR);
164
165 #ifndef NO_ERR
166                 ERR_load_strings(0,ERR_str_libraries);
167                 ERR_load_strings(0,ERR_str_reasons);
168                 ERR_load_strings(ERR_LIB_SYS,ERR_str_functs);
169 #endif
170                 }
171         }
172
173 void ERR_load_strings(lib,str)
174 int lib;
175 ERR_STRING_DATA *str;
176         {
177         if (error_hash == NULL)
178                 {
179                 CRYPTO_w_lock(CRYPTO_LOCK_ERR_HASH);
180                 error_hash=lh_new(err_hash,err_cmp);
181                 if (error_hash == NULL)
182                         {
183                         CRYPTO_w_unlock(CRYPTO_LOCK_ERR_HASH);
184                         return;
185                         }
186                 CRYPTO_w_unlock(CRYPTO_LOCK_ERR_HASH);
187
188                 ERR_load_ERR_strings();
189                 }
190
191         CRYPTO_w_lock(CRYPTO_LOCK_ERR_HASH);
192         while (str->error)
193                 {
194                 str->error|=ERR_PACK(lib,0,0);
195                 lh_insert(error_hash,(char *)str);
196                 str++;
197                 }
198         CRYPTO_w_unlock(CRYPTO_LOCK_ERR_HASH);
199         }
200
201 void ERR_free_strings()
202         {
203         CRYPTO_w_lock(CRYPTO_LOCK_ERR);
204
205         if (error_hash != NULL)
206                 {
207                 lh_free(error_hash);
208                 error_hash=NULL;
209                 }
210
211         CRYPTO_w_unlock(CRYPTO_LOCK_ERR);
212         }
213
214 void ERR_put_error(lib,func,reason,file,line)
215 int lib,func,reason;
216 char *file;
217 int line;
218         {
219         ERR_STATE *es;
220
221         es=ERR_get_state();
222
223         es->top=(es->top+1)%ERR_NUM_ERRORS;
224         if (es->top == es->bottom)
225                 es->bottom=(es->bottom+1)%ERR_NUM_ERRORS;
226         es->err_buffer[es->top]=ERR_PACK(lib,func,reason);
227         es->err_file[es->top]=file;
228         es->err_line[es->top]=line;
229         }
230
231 void ERR_clear_error()
232         {
233         int i;
234         ERR_STATE *es;
235
236         es=ERR_get_state();
237
238         for (i=0; i<ERR_NUM_ERRORS; i++)
239                 {
240                 es->err_buffer[i]=0;
241                 es->err_file[i]=NULL;
242                 es->err_line[i]= -1;
243                 }
244         es->top=es->bottom=0;
245         }
246
247 unsigned long ERR_peek_error()
248         {       
249         int i;
250         ERR_STATE *es;
251
252         /* should be fine since only one thread should ever be playing
253          * with the value returned from this call */
254         es=ERR_get_state();
255
256         if (es->bottom == es->top) return(0);
257         i=(es->bottom+1)%ERR_NUM_ERRORS;
258
259
260         return(es->err_buffer[i]);
261         }
262
263 unsigned long ERR_get_error()
264         {
265         int i;
266         unsigned long ret;
267         ERR_STATE *es;
268
269         es=ERR_get_state();
270
271         if (es->bottom == es->top) return(0);
272         i=(es->bottom+1)%ERR_NUM_ERRORS;
273         es->bottom=i;
274         ret=es->err_buffer[i];
275         es->err_buffer[i]=0;
276
277
278         return(ret);
279         }
280
281 unsigned long ERR_peek_error_line(file,line)
282 char **file;
283 int *line;
284         {       
285         int i=0;
286         ERR_STATE *es;
287
288         es=ERR_get_state();
289
290         if (es->bottom == es->top)
291                 {
292                 return(0);
293                 }
294
295         i=(es->bottom+1)%ERR_NUM_ERRORS;
296         if (es->err_file[i] == NULL)
297                 {
298                 *file="NA";
299                 *line=0;
300                 }
301         else
302                 {
303                 *file=es->err_file[i];
304                 *line=es->err_line[i];
305                 }
306
307         return(es->err_buffer[i]);
308         }
309
310 unsigned long ERR_get_error_line(file,line)
311 char **file;
312 int *line;
313         {
314         int i;
315         unsigned long ret;
316         ERR_STATE *es;
317
318         es=ERR_get_state();
319
320         if (es->bottom == es->top)
321                 return(0);
322
323         i=(es->bottom+1)%ERR_NUM_ERRORS;
324         es->bottom=i;
325         ret=  es->err_buffer[i];
326         if (es->err_file[i] == NULL)
327                 {
328                 *file="NA";
329                 *line=0;
330                 }
331         else
332                 {
333                 *file=es->err_file[i];
334                 *line=es->err_line[i];
335                 }
336         es->err_buffer[i]=0;
337         es->err_file[i]=NULL;
338         es->err_line[i]= -1;
339
340         return(ret);
341         }
342
343 /* BAD for multi-threaded, uses a local buffer if ret == NULL */
344 char *ERR_error_string(e,ret)
345 unsigned long e;
346 char *ret;
347         {
348         static char buf[256];
349         char *ls,*fs,*rs;
350         unsigned long l,f,r;
351         int i;
352
353         l=ERR_GET_LIB(e);
354         f=ERR_GET_FUNC(e);
355         r=ERR_GET_REASON(e);
356
357         ls=ERR_lib_error_string(e);
358         fs=ERR_func_error_string(e);
359         rs=ERR_reason_error_string(e);
360
361         if (ret == NULL) ret=buf;
362
363         sprintf(&(ret[0]),"error:%08lX:",e);
364         i=strlen(ret);
365         if (ls == NULL)
366                 sprintf(&(ret[i]),":lib(%lu) ",l);
367         else    sprintf(&(ret[i]),"%s",ls);
368         i=strlen(ret);
369         if (fs == NULL)
370                 sprintf(&(ret[i]),":func(%lu) ",f);
371         else    sprintf(&(ret[i]),":%s",fs);
372         i=strlen(ret);
373         if (rs == NULL)
374                 sprintf(&(ret[i]),":reason(%lu)",r);
375         else    sprintf(&(ret[i]),":%s",rs);
376
377         return(ret);
378         }
379
380 LHASH *ERR_get_string_table()
381         {
382         return(error_hash);
383         }
384
385 LHASH *ERR_get_err_state_table()
386         {
387         return(thread_hash);
388         }
389
390 char *ERR_lib_error_string(e)
391 unsigned long e;
392         {
393         ERR_STRING_DATA d,*p=NULL;
394         unsigned long l;
395
396         l=ERR_GET_LIB(e);
397
398         CRYPTO_r_lock(CRYPTO_LOCK_ERR_HASH);
399
400         if (error_hash != NULL)
401                 {
402                 d.error=ERR_PACK(l,0,0);
403                 p=(ERR_STRING_DATA *)lh_retrieve(error_hash,(char *)&d);
404                 }
405
406         CRYPTO_r_unlock(CRYPTO_LOCK_ERR_HASH);
407
408         return((p == NULL)?NULL:p->string);
409         }
410
411 char *ERR_func_error_string(e)
412 unsigned long e;
413         {
414         ERR_STRING_DATA d,*p=NULL;
415         unsigned long l,f;
416
417         l=ERR_GET_LIB(e);
418         f=ERR_GET_FUNC(e);
419
420         CRYPTO_r_lock(CRYPTO_LOCK_ERR_HASH);
421
422         if (error_hash != NULL)
423                 {
424                 d.error=ERR_PACK(l,f,0);
425                 p=(ERR_STRING_DATA *)lh_retrieve(error_hash,(char *)&d);
426                 }
427
428         CRYPTO_r_unlock(CRYPTO_LOCK_ERR_HASH);
429
430         return((p == NULL)?NULL:p->string);
431         }
432
433 char *ERR_reason_error_string(e)
434 unsigned long e;
435         {
436         ERR_STRING_DATA d,*p=NULL;
437         unsigned long l,r;
438
439         l=ERR_GET_LIB(e);
440         r=ERR_GET_REASON(e);
441
442         CRYPTO_r_lock(CRYPTO_LOCK_ERR_HASH);
443
444         if (error_hash != NULL)
445                 {
446                 d.error=ERR_PACK(l,0,r);
447                 p=(ERR_STRING_DATA *)lh_retrieve(error_hash,(char *)&d);
448                 if (p == NULL)
449                         {
450                         d.error=ERR_PACK(0,0,r);
451                         p=(ERR_STRING_DATA *)lh_retrieve(error_hash,
452                                 (char *)&d);
453                         }
454                 }
455
456         CRYPTO_r_unlock(CRYPTO_LOCK_ERR_HASH);
457
458         return((p == NULL)?NULL:p->string);
459         }
460
461 static unsigned long err_hash(a)
462 ERR_STRING_DATA *a;
463         {
464         unsigned long ret,l;
465
466         l=a->error;
467         ret=l^ERR_GET_LIB(l)^ERR_GET_FUNC(l);
468         return(ret^ret%19*13);
469         }
470
471 static int err_cmp(a,b)
472 ERR_STRING_DATA *a,*b;
473         {
474         return((int)(a->error-b->error));
475         }
476
477 static unsigned long pid_hash(a)
478 ERR_STATE *a;
479         {
480         return(a->pid*13);
481         }
482
483 static int pid_cmp(a,b)
484 ERR_STATE *a,*b;
485         {
486         return((int)((long)a->pid - (long)b->pid));
487         }
488
489 void ERR_remove_state(pid)
490 unsigned long pid;
491         {
492         ERR_STATE *p,tmp;
493
494         if (thread_hash == NULL)
495                 return;
496         if (pid == 0)
497                 pid=(unsigned long)CRYPTO_thread_id();
498         tmp.pid=pid;
499         CRYPTO_w_lock(CRYPTO_LOCK_ERR);
500         p=(ERR_STATE *)lh_delete(thread_hash,(char *)&tmp);
501         if (p != NULL) Free(p);
502         CRYPTO_w_unlock(CRYPTO_LOCK_ERR);
503         }
504
505 ERR_STATE *ERR_get_state()
506         {
507         static ERR_STATE fallback;
508         ERR_STATE *ret=NULL,tmp,*tmpp;
509         unsigned long pid;
510
511         pid=(unsigned long)CRYPTO_thread_id();
512
513         CRYPTO_r_lock(CRYPTO_LOCK_ERR);
514         if (thread_hash == NULL)
515                 {
516                 CRYPTO_r_unlock(CRYPTO_LOCK_ERR);
517                 CRYPTO_w_lock(CRYPTO_LOCK_ERR);
518                 if (thread_hash == NULL)
519                         {
520                         thread_hash=lh_new(pid_hash,pid_cmp);
521                         CRYPTO_w_unlock(CRYPTO_LOCK_ERR);
522                         if (thread_hash == NULL) return(&fallback);
523                         }
524                 else
525                         CRYPTO_w_unlock(CRYPTO_LOCK_ERR);
526                 }
527         else
528                 {
529                 tmp.pid=pid;
530                 ret=(ERR_STATE *)lh_retrieve(thread_hash,(char *)&tmp);
531                 CRYPTO_r_unlock(CRYPTO_LOCK_ERR);
532                 }
533
534         /* ret == the error state, if NULL, make a new one */
535         if (ret == NULL)
536                 {
537                 ret=(ERR_STATE *)Malloc(sizeof(ERR_STATE));
538                 if (ret == NULL) return(&fallback);
539                 ret->pid=pid;
540                 ret->top=0;
541                 ret->bottom=0;
542                 CRYPTO_w_lock(CRYPTO_LOCK_ERR);
543                 tmpp=(ERR_STATE *)lh_insert(thread_hash,(char *)ret);
544                 CRYPTO_w_unlock(CRYPTO_LOCK_ERR);
545                 if (tmpp != NULL) /* old entry - should not happen */
546                         Free(tmpp);
547                 }
548         return(ret);
549         }
550