Import OpenSSL 0.9.8l
[dragonfly.git] / crypto / openssl / crypto / dyn_lck.c
1 /* crypto/cryptlib.c */
2 /* ====================================================================
3  * Copyright (c) 1998-2003 The OpenSSL Project.  All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  *
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer. 
11  *
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in
14  *    the documentation and/or other materials provided with the
15  *    distribution.
16  *
17  * 3. All advertising materials mentioning features or use of this
18  *    software must display the following acknowledgment:
19  *    "This product includes software developed by the OpenSSL Project
20  *    for use in the OpenSSL Toolkit. (http://www.openssl.org/)"
21  *
22  * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
23  *    endorse or promote products derived from this software without
24  *    prior written permission. For written permission, please contact
25  *    openssl-core@openssl.org.
26  *
27  * 5. Products derived from this software may not be called "OpenSSL"
28  *    nor may "OpenSSL" appear in their names without prior written
29  *    permission of the OpenSSL Project.
30  *
31  * 6. Redistributions of any form whatsoever must retain the following
32  *    acknowledgment:
33  *    "This product includes software developed by the OpenSSL Project
34  *    for use in the OpenSSL Toolkit (http://www.openssl.org/)"
35  *
36  * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
37  * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
38  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
39  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE OpenSSL PROJECT OR
40  * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
41  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
42  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
43  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
44  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
45  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
46  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
47  * OF THE POSSIBILITY OF SUCH DAMAGE.
48  * ====================================================================
49  *
50  * This product includes cryptographic software written by Eric Young
51  * (eay@cryptsoft.com).  This product includes software written by Tim
52  * Hudson (tjh@cryptsoft.com).
53  *
54  */
55 /* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
56  * All rights reserved.
57  *
58  * This package is an SSL implementation written
59  * by Eric Young (eay@cryptsoft.com).
60  * The implementation was written so as to conform with Netscapes SSL.
61  * 
62  * This library is free for commercial and non-commercial use as long as
63  * the following conditions are aheared to.  The following conditions
64  * apply to all code found in this distribution, be it the RC4, RSA,
65  * lhash, DES, etc., code; not just the SSL code.  The SSL documentation
66  * included with this distribution is covered by the same copyright terms
67  * except that the holder is Tim Hudson (tjh@cryptsoft.com).
68  * 
69  * Copyright remains Eric Young's, and as such any Copyright notices in
70  * the code are not to be removed.
71  * If this package is used in a product, Eric Young should be given attribution
72  * as the author of the parts of the library used.
73  * This can be in the form of a textual message at program startup or
74  * in documentation (online or textual) provided with the package.
75  * 
76  * Redistribution and use in source and binary forms, with or without
77  * modification, are permitted provided that the following conditions
78  * are met:
79  * 1. Redistributions of source code must retain the copyright
80  *    notice, this list of conditions and the following disclaimer.
81  * 2. Redistributions in binary form must reproduce the above copyright
82  *    notice, this list of conditions and the following disclaimer in the
83  *    documentation and/or other materials provided with the distribution.
84  * 3. All advertising materials mentioning features or use of this software
85  *    must display the following acknowledgement:
86  *    "This product includes cryptographic software written by
87  *     Eric Young (eay@cryptsoft.com)"
88  *    The word 'cryptographic' can be left out if the rouines from the library
89  *    being used are not cryptographic related :-).
90  * 4. If you include any Windows specific code (or a derivative thereof) from 
91  *    the apps directory (application code) you must include an acknowledgement:
92  *    "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
93  * 
94  * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
95  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
96  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
97  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
98  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
99  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
100  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
101  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
102  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
103  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
104  * SUCH DAMAGE.
105  * 
106  * The licence and distribution terms for any publically available version or
107  * derivative of this code cannot be changed.  i.e. this code cannot simply be
108  * copied and put under another distribution licence
109  * [including the GNU Public Licence.]
110  */
111 /* ====================================================================
112  * Copyright 2002 Sun Microsystems, Inc. ALL RIGHTS RESERVED.
113  * ECDH support in OpenSSL originally developed by 
114  * SUN MICROSYSTEMS, INC., and contributed to the OpenSSL project.
115  */
116
117 #include "cryptlib.h"
118 #include <openssl/safestack.h>
119
120 #if defined(OPENSSL_SYS_WIN32) || defined(OPENSSL_SYS_WIN16)
121 static double SSLeay_MSVC5_hack=0.0; /* and for VC1.5 */
122 #endif
123
124 DECLARE_STACK_OF(CRYPTO_dynlock)
125 IMPLEMENT_STACK_OF(CRYPTO_dynlock)
126
127 /* real #defines in crypto.h, keep these upto date */
128 static const char* const lock_names[CRYPTO_NUM_LOCKS] =
129         {
130         "<<ERROR>>",
131         "err",
132         "ex_data",
133         "x509",
134         "x509_info",
135         "x509_pkey",
136         "x509_crl",
137         "x509_req",
138         "dsa",
139         "rsa",
140         "evp_pkey",
141         "x509_store",
142         "ssl_ctx",
143         "ssl_cert",
144         "ssl_session",
145         "ssl_sess_cert",
146         "ssl",
147         "ssl_method",
148         "rand",
149         "rand2",
150         "debug_malloc",
151         "BIO",
152         "gethostbyname",
153         "getservbyname",
154         "readdir",
155         "RSA_blinding",
156         "dh",
157         "debug_malloc2",
158         "dso",
159         "dynlock",
160         "engine",
161         "ui",
162         "ecdsa",
163         "ec",
164         "ecdh",
165         "bn",
166         "ec_pre_comp",
167         "store",
168         "comp",
169 #ifndef OPENSSL_FIPS
170 # if CRYPTO_NUM_LOCKS != 39
171 #  error "Inconsistency between crypto.h and cryptlib.c"
172 # endif
173 #else
174         "fips",
175         "fips2",
176 # if CRYPTO_NUM_LOCKS != 41
177 #  error "Inconsistency between crypto.h and cryptlib.c"
178 # endif
179 #endif
180         };
181
182 /* This is for applications to allocate new type names in the non-dynamic
183    array of lock names.  These are numbered with positive numbers.  */
184 static STACK *app_locks=NULL;
185
186 /* For applications that want a more dynamic way of handling threads, the
187    following stack is used.  These are externally numbered with negative
188    numbers.  */
189 static STACK_OF(CRYPTO_dynlock) *dyn_locks=NULL;
190
191
192 static struct CRYPTO_dynlock_value *(MS_FAR *dynlock_create_callback)
193         (const char *file,int line)=NULL;
194 static void (MS_FAR *dynlock_lock_callback)(int mode,
195         struct CRYPTO_dynlock_value *l, const char *file,int line)=NULL;
196 static void (MS_FAR *dynlock_destroy_callback)(struct CRYPTO_dynlock_value *l,
197         const char *file,int line)=NULL;
198
199 int CRYPTO_get_new_lockid(char *name)
200         {
201         char *str;
202         int i;
203
204 #if defined(OPENSSL_SYS_WIN32) || defined(OPENSSL_SYS_WIN16)
205         /* A hack to make Visual C++ 5.0 work correctly when linking as
206          * a DLL using /MT. Without this, the application cannot use
207          * and floating point printf's.
208          * It also seems to be needed for Visual C 1.5 (win16) */
209         SSLeay_MSVC5_hack=(double)name[0]*(double)name[1];
210 #endif
211
212         if ((app_locks == NULL) && ((app_locks=sk_new_null()) == NULL))
213                 {
214                 CRYPTOerr(CRYPTO_F_CRYPTO_GET_NEW_LOCKID,ERR_R_MALLOC_FAILURE);
215                 return(0);
216                 }
217         if ((str=BUF_strdup(name)) == NULL)
218                 {
219                 CRYPTOerr(CRYPTO_F_CRYPTO_GET_NEW_LOCKID,ERR_R_MALLOC_FAILURE);
220                 return(0);
221                 }
222         i=sk_push(app_locks,str);
223         if (!i)
224                 OPENSSL_free(str);
225         else
226                 i+=CRYPTO_NUM_LOCKS; /* gap of one :-) */
227         return(i);
228         }
229
230 int CRYPTO_get_new_dynlockid(void)
231         {
232         int i = 0;
233         CRYPTO_dynlock *pointer = NULL;
234
235         if (dynlock_create_callback == NULL)
236                 {
237                 CRYPTOerr(CRYPTO_F_CRYPTO_GET_NEW_DYNLOCKID,CRYPTO_R_NO_DYNLOCK_CREATE_CALLBACK);
238                 return(0);
239                 }
240         CRYPTO_w_lock(CRYPTO_LOCK_DYNLOCK);
241         if ((dyn_locks == NULL)
242                 && ((dyn_locks=sk_CRYPTO_dynlock_new_null()) == NULL))
243                 {
244                 CRYPTO_w_unlock(CRYPTO_LOCK_DYNLOCK);
245                 CRYPTOerr(CRYPTO_F_CRYPTO_GET_NEW_DYNLOCKID,ERR_R_MALLOC_FAILURE);
246                 return(0);
247                 }
248         CRYPTO_w_unlock(CRYPTO_LOCK_DYNLOCK);
249
250         pointer = (CRYPTO_dynlock *)OPENSSL_malloc(sizeof(CRYPTO_dynlock));
251         if (pointer == NULL)
252                 {
253                 CRYPTOerr(CRYPTO_F_CRYPTO_GET_NEW_DYNLOCKID,ERR_R_MALLOC_FAILURE);
254                 return(0);
255                 }
256         pointer->references = 1;
257         pointer->data = dynlock_create_callback(__FILE__,__LINE__);
258         if (pointer->data == NULL)
259                 {
260                 OPENSSL_free(pointer);
261                 CRYPTOerr(CRYPTO_F_CRYPTO_GET_NEW_DYNLOCKID,ERR_R_MALLOC_FAILURE);
262                 return(0);
263                 }
264
265         CRYPTO_w_lock(CRYPTO_LOCK_DYNLOCK);
266         /* First, try to find an existing empty slot */
267         i=sk_CRYPTO_dynlock_find(dyn_locks,NULL);
268         /* If there was none, push, thereby creating a new one */
269         if (i == -1)
270                 /* Since sk_push() returns the number of items on the
271                    stack, not the location of the pushed item, we need
272                    to transform the returned number into a position,
273                    by decreasing it.  */
274                 i=sk_CRYPTO_dynlock_push(dyn_locks,pointer) - 1;
275         else
276                 /* If we found a place with a NULL pointer, put our pointer
277                    in it.  */
278                 (void)sk_CRYPTO_dynlock_set(dyn_locks,i,pointer);
279         CRYPTO_w_unlock(CRYPTO_LOCK_DYNLOCK);
280
281         if (i == -1)
282                 {
283                 dynlock_destroy_callback(pointer->data,__FILE__,__LINE__);
284                 OPENSSL_free(pointer);
285                 }
286         else
287                 i += 1; /* to avoid 0 */
288         return -i;
289         }
290
291 void CRYPTO_destroy_dynlockid(int i)
292         {
293         CRYPTO_dynlock *pointer = NULL;
294         if (i)
295                 i = -i-1;
296         if (dynlock_destroy_callback == NULL)
297                 return;
298
299         CRYPTO_w_lock(CRYPTO_LOCK_DYNLOCK);
300
301         if (dyn_locks == NULL || i >= sk_CRYPTO_dynlock_num(dyn_locks))
302                 {
303                 CRYPTO_w_unlock(CRYPTO_LOCK_DYNLOCK);
304                 return;
305                 }
306         pointer = sk_CRYPTO_dynlock_value(dyn_locks, i);
307         if (pointer != NULL)
308                 {
309                 --pointer->references;
310 #ifdef REF_CHECK
311                 if (pointer->references < 0)
312                         {
313                         fprintf(stderr,"CRYPTO_destroy_dynlockid, bad reference count\n");
314                         abort();
315                         }
316                 else
317 #endif
318                         if (pointer->references <= 0)
319                                 {
320                                 (void)sk_CRYPTO_dynlock_set(dyn_locks, i, NULL);
321                                 }
322                         else
323                                 pointer = NULL;
324                 }
325         CRYPTO_w_unlock(CRYPTO_LOCK_DYNLOCK);
326
327         if (pointer)
328                 {
329                 dynlock_destroy_callback(pointer->data,__FILE__,__LINE__);
330                 OPENSSL_free(pointer);
331                 }
332         }
333
334 struct CRYPTO_dynlock_value *CRYPTO_get_dynlock_value(int i)
335         {
336         CRYPTO_dynlock *pointer = NULL;
337         if (i)
338                 i = -i-1;
339
340         CRYPTO_w_lock(CRYPTO_LOCK_DYNLOCK);
341
342         if (dyn_locks != NULL && i < sk_CRYPTO_dynlock_num(dyn_locks))
343                 pointer = sk_CRYPTO_dynlock_value(dyn_locks, i);
344         if (pointer)
345                 pointer->references++;
346
347         CRYPTO_w_unlock(CRYPTO_LOCK_DYNLOCK);
348
349         if (pointer)
350                 return pointer->data;
351         return NULL;
352         }
353
354 struct CRYPTO_dynlock_value *(*CRYPTO_get_dynlock_create_callback(void))
355         (const char *file,int line)
356         {
357         return(dynlock_create_callback);
358         }
359
360 void (*CRYPTO_get_dynlock_lock_callback(void))(int mode,
361         struct CRYPTO_dynlock_value *l, const char *file,int line)
362         {
363         return(dynlock_lock_callback);
364         }
365
366 void (*CRYPTO_get_dynlock_destroy_callback(void))
367         (struct CRYPTO_dynlock_value *l, const char *file,int line)
368         {
369         return(dynlock_destroy_callback);
370         }
371
372 void CRYPTO_set_dynlock_create_callback(struct CRYPTO_dynlock_value *(*func)
373         (const char *file, int line))
374         {
375         dynlock_create_callback=func;
376         }
377
378 static void do_dynlock(int mode, int type, const char *file, int line)
379         {
380         if (dynlock_lock_callback != NULL)
381                 {
382                 struct CRYPTO_dynlock_value *pointer
383                                 = CRYPTO_get_dynlock_value(type);
384
385                 OPENSSL_assert(pointer != NULL);
386
387                 dynlock_lock_callback(mode, pointer, file, line);
388
389                 CRYPTO_destroy_dynlockid(type);
390                 }
391         }
392
393 void CRYPTO_set_dynlock_lock_callback(void (*func)(int mode,
394         struct CRYPTO_dynlock_value *l, const char *file, int line))
395         {
396         /* Set callback so CRYPTO_lock() can now handle dynamic locks.
397          * This is OK because at this point and application shouldn't be using
398          * OpenSSL from multiple threads because it is setting up the locking
399          * callbacks.
400          */
401         static int done = 0;
402         if (!done)
403                 {
404                 int_CRYPTO_set_do_dynlock_callback(do_dynlock);
405                 done = 1;
406                 }
407                 
408         dynlock_lock_callback=func;
409         }
410
411 void CRYPTO_set_dynlock_destroy_callback(void (*func)
412         (struct CRYPTO_dynlock_value *l, const char *file, int line))
413         {
414         dynlock_destroy_callback=func;
415         }
416
417 const char *CRYPTO_get_lock_name(int type)
418         {
419         if (type < 0)
420                 return("dynamic");
421         else if (type < CRYPTO_NUM_LOCKS)
422                 return(lock_names[type]);
423         else if (type-CRYPTO_NUM_LOCKS > sk_num(app_locks))
424                 return("ERROR");
425         else
426                 return(sk_value(app_locks,type-CRYPTO_NUM_LOCKS));
427         }
428