make update
[openssl.git] / crypto / lock.c
1 /* crypto/cryptlib.c */
2 /* ====================================================================
3  * Copyright (c) 1998-2006 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 "internal/cryptlib.h"
118 #include <openssl/safestack.h>
119
120 #if defined(OPENSSL_SYS_WIN32)
121 static double SSLeay_MSVC5_hack = 0.0; /* and for VC1.5 */
122 #endif
123
124 DECLARE_STACK_OF(CRYPTO_dynlock)
125
126 /* real #defines in crypto.h, keep these upto date */
127 static const char *const lock_names[CRYPTO_NUM_LOCKS] = {
128     "<<ERROR>>",
129     "err",
130     "ex_data",
131     "x509",
132     "x509_info",
133     "x509_pkey",
134     "x509_crl",
135     "x509_req",
136     "dsa",
137     "rsa",
138     "evp_pkey",
139     "x509_store",
140     "ssl_ctx",
141     "ssl_cert",
142     "ssl_session",
143     "ssl_sess_cert",
144     "ssl",
145     "ssl_method",
146     "rand",
147     "rand2",
148     "debug_malloc",
149     "BIO",
150     "gethostbyname",
151     "getservbyname",
152     "readdir",
153     "RSA_blinding",
154     "dh",
155     "debug_malloc2",
156     "dso",
157     "dynlock",
158     "engine",
159     "ui",
160     "ecdsa",
161     "ec",
162     "ecdh",
163     "bn",
164     "ec_pre_comp",
165     "store",
166     "comp",
167     "fips",
168     "fips2",
169 #if CRYPTO_NUM_LOCKS != 41
170 # error "Inconsistency between crypto.h and cryptlib.c"
171 #endif
172 };
173
174 /*
175  * This is for applications to allocate new type names in the non-dynamic
176  * array of lock names.  These are numbered with positive numbers.
177  */
178 static STACK_OF(OPENSSL_STRING) *app_locks = NULL;
179
180 /*
181  * For applications that want a more dynamic way of handling threads, the
182  * following stack is used.  These are externally numbered with negative
183  * numbers.
184  */
185 static STACK_OF(CRYPTO_dynlock) *dyn_locks = NULL;
186
187 static void (*locking_callback) (int mode, int type,
188                                  const char *file, int line) = 0;
189 static int (*add_lock_callback) (int *pointer, int amount,
190                                  int type, const char *file, int line) = 0;
191 static struct CRYPTO_dynlock_value *(*dynlock_create_callback)
192  (const char *file, int line) = 0;
193 static void (*dynlock_lock_callback) (int mode,
194                                       struct CRYPTO_dynlock_value *l,
195                                       const char *file, int line) = 0;
196 static void (*dynlock_destroy_callback) (struct CRYPTO_dynlock_value *l,
197                                          const char *file, int line) = 0;
198
199 int CRYPTO_get_new_lockid(char *name)
200 {
201     char *str;
202     int i;
203
204 #if defined(OPENSSL_SYS_WIN32)
205     /*
206      * A hack to make Visual C++ 5.0 work correctly when linking as a DLL
207      * using /MT. Without this, the application cannot use any floating point
208      * printf's. It also seems to be needed for Visual C 1.5 (win16)
209      */
210     SSLeay_MSVC5_hack = (double)name[0] * (double)name[1];
211 #endif
212
213     if ((app_locks == NULL)
214         && ((app_locks = sk_OPENSSL_STRING_new_null()) == NULL)) {
215         CRYPTOerr(CRYPTO_F_CRYPTO_GET_NEW_LOCKID, ERR_R_MALLOC_FAILURE);
216         return (0);
217     }
218     if ((str = BUF_strdup(name)) == NULL) {
219         CRYPTOerr(CRYPTO_F_CRYPTO_GET_NEW_LOCKID, ERR_R_MALLOC_FAILURE);
220         return (0);
221     }
222     i = sk_OPENSSL_STRING_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_num_locks(void)
231 {
232     return CRYPTO_NUM_LOCKS;
233 }
234
235 int CRYPTO_get_new_dynlockid(void)
236 {
237     int i = 0;
238     CRYPTO_dynlock *pointer = NULL;
239
240     if (dynlock_create_callback == NULL) {
241         CRYPTOerr(CRYPTO_F_CRYPTO_GET_NEW_DYNLOCKID,
242                   CRYPTO_R_NO_DYNLOCK_CREATE_CALLBACK);
243         return (0);
244     }
245     CRYPTO_w_lock(CRYPTO_LOCK_DYNLOCK);
246     if ((dyn_locks == NULL)
247         && ((dyn_locks = sk_CRYPTO_dynlock_new_null()) == NULL)) {
248         CRYPTO_w_unlock(CRYPTO_LOCK_DYNLOCK);
249         CRYPTOerr(CRYPTO_F_CRYPTO_GET_NEW_DYNLOCKID, ERR_R_MALLOC_FAILURE);
250         return (0);
251     }
252     CRYPTO_w_unlock(CRYPTO_LOCK_DYNLOCK);
253
254     pointer = OPENSSL_malloc(sizeof(*pointer));
255     if (pointer == NULL) {
256         CRYPTOerr(CRYPTO_F_CRYPTO_GET_NEW_DYNLOCKID, ERR_R_MALLOC_FAILURE);
257         return (0);
258     }
259     pointer->references = 1;
260     pointer->data = dynlock_create_callback(__FILE__, __LINE__);
261     if (pointer->data == NULL) {
262         OPENSSL_free(pointer);
263         CRYPTOerr(CRYPTO_F_CRYPTO_GET_NEW_DYNLOCKID, ERR_R_MALLOC_FAILURE);
264         return (0);
265     }
266
267     CRYPTO_w_lock(CRYPTO_LOCK_DYNLOCK);
268     /* First, try to find an existing empty slot */
269     i = sk_CRYPTO_dynlock_find(dyn_locks, NULL);
270     /* If there was none, push, thereby creating a new one */
271     if (i == -1)
272         /*
273          * Since sk_push() returns the number of items on the stack, not the
274          * location of the pushed item, we need to transform the returned
275          * number into a position, by decreasing it.
276          */
277         i = sk_CRYPTO_dynlock_push(dyn_locks, pointer) - 1;
278     else
279         /*
280          * If we found a place with a NULL pointer, put our pointer in it.
281          */
282         (void)sk_CRYPTO_dynlock_set(dyn_locks, i, pointer);
283     CRYPTO_w_unlock(CRYPTO_LOCK_DYNLOCK);
284
285     if (i == -1) {
286         dynlock_destroy_callback(pointer->data, __FILE__, __LINE__);
287         OPENSSL_free(pointer);
288     } else
289         i += 1;                 /* to avoid 0 */
290     return -i;
291 }
292
293 void CRYPTO_destroy_dynlockid(int i)
294 {
295     CRYPTO_dynlock *pointer = NULL;
296     if (i)
297         i = -i - 1;
298     if (dynlock_destroy_callback == NULL)
299         return;
300
301     CRYPTO_w_lock(CRYPTO_LOCK_DYNLOCK);
302
303     if (dyn_locks == NULL || i >= sk_CRYPTO_dynlock_num(dyn_locks)) {
304         CRYPTO_w_unlock(CRYPTO_LOCK_DYNLOCK);
305         return;
306     }
307     pointer = sk_CRYPTO_dynlock_value(dyn_locks, i);
308     if (pointer != NULL) {
309         --pointer->references;
310 #ifdef REF_CHECK
311         if (pointer->references < 0) {
312             fprintf(stderr,
313                     "CRYPTO_destroy_dynlockid, bad reference count\n");
314             abort();
315         } else
316 #endif
317         if (pointer->references <= 0) {
318             (void)sk_CRYPTO_dynlock_set(dyn_locks, i, NULL);
319         } else
320             pointer = NULL;
321     }
322     CRYPTO_w_unlock(CRYPTO_LOCK_DYNLOCK);
323
324     if (pointer) {
325         dynlock_destroy_callback(pointer->data, __FILE__, __LINE__);
326         OPENSSL_free(pointer);
327     }
328 }
329
330 struct CRYPTO_dynlock_value *CRYPTO_get_dynlock_value(int i)
331 {
332     CRYPTO_dynlock *pointer = NULL;
333     if (i)
334         i = -i - 1;
335
336     CRYPTO_w_lock(CRYPTO_LOCK_DYNLOCK);
337
338     if (dyn_locks != NULL && i < sk_CRYPTO_dynlock_num(dyn_locks))
339         pointer = sk_CRYPTO_dynlock_value(dyn_locks, i);
340     if (pointer)
341         pointer->references++;
342
343     CRYPTO_w_unlock(CRYPTO_LOCK_DYNLOCK);
344
345     if (pointer)
346         return pointer->data;
347     return NULL;
348 }
349
350 struct CRYPTO_dynlock_value *(*CRYPTO_get_dynlock_create_callback(void))
351  (const char *file, int line) {
352     return (dynlock_create_callback);
353 }
354
355 void (*CRYPTO_get_dynlock_lock_callback(void)) (int mode,
356                                                 struct CRYPTO_dynlock_value
357                                                 *l, const char *file,
358                                                 int line) {
359     return (dynlock_lock_callback);
360 }
361
362 void (*CRYPTO_get_dynlock_destroy_callback(void))
363  (struct CRYPTO_dynlock_value *l, const char *file, int line) {
364     return (dynlock_destroy_callback);
365 }
366
367 void CRYPTO_set_dynlock_create_callback(struct CRYPTO_dynlock_value *(*func)
368                                          (const char *file, int line))
369 {
370     dynlock_create_callback = func;
371 }
372
373 void CRYPTO_set_dynlock_lock_callback(void (*func) (int mode,
374                                                     struct
375                                                     CRYPTO_dynlock_value *l,
376                                                     const char *file,
377                                                     int line))
378 {
379 #ifdef OPENSSL_FIPS
380     FIPS_set_locking_callbacks(CRYPTO_lock, CRYPTO_add_lock);
381 #endif
382     dynlock_lock_callback = func;
383 }
384
385 void CRYPTO_set_dynlock_destroy_callback(void (*func)
386                                           (struct CRYPTO_dynlock_value *l,
387                                            const char *file, int line))
388 {
389     dynlock_destroy_callback = func;
390 }
391
392 void (*CRYPTO_get_locking_callback(void)) (int mode, int type,
393                                            const char *file, int line) {
394     return (locking_callback);
395 }
396
397 int (*CRYPTO_get_add_lock_callback(void)) (int *num, int mount, int type,
398                                            const char *file, int line) {
399     return (add_lock_callback);
400 }
401
402 void CRYPTO_set_locking_callback(void (*func) (int mode, int type,
403                                                const char *file, int line))
404 {
405 #ifdef OPENSSL_FIPS
406     FIPS_set_locking_callbacks(CRYPTO_lock, CRYPTO_add_lock);
407 #endif
408     locking_callback = func;
409 }
410
411 void CRYPTO_set_add_lock_callback(int (*func) (int *num, int mount, int type,
412                                                const char *file, int line))
413 {
414     add_lock_callback = func;
415 }
416
417 void CRYPTO_lock(int mode, int type, const char *file, int line)
418 {
419 #ifdef LOCK_DEBUG
420     {
421         CRYPTO_THREADID id;
422         char *rw_text, *operation_text;
423
424         if (mode & CRYPTO_LOCK)
425             operation_text = "lock  ";
426         else if (mode & CRYPTO_UNLOCK)
427             operation_text = "unlock";
428         else
429             operation_text = "ERROR ";
430
431         if (mode & CRYPTO_READ)
432             rw_text = "r";
433         else if (mode & CRYPTO_WRITE)
434             rw_text = "w";
435         else
436             rw_text = "ERROR";
437
438         CRYPTO_THREADID_current(&id);
439         fprintf(stderr, "lock:%08lx:(%s)%s %-18s %s:%d\n",
440                 CRYPTO_THREADID_hash(&id), rw_text, operation_text,
441                 CRYPTO_get_lock_name(type), file, line);
442     }
443 #endif
444     if (type < 0) {
445         if (dynlock_lock_callback != NULL) {
446             struct CRYPTO_dynlock_value *pointer
447                 = CRYPTO_get_dynlock_value(type);
448
449             OPENSSL_assert(pointer != NULL);
450
451             dynlock_lock_callback(mode, pointer, file, line);
452
453             CRYPTO_destroy_dynlockid(type);
454         }
455     } else if (locking_callback != NULL)
456         locking_callback(mode, type, file, line);
457 }
458
459 int CRYPTO_add_lock(int *pointer, int amount, int type, const char *file,
460                     int line)
461 {
462     int ret = 0;
463
464     if (add_lock_callback != NULL) {
465 #ifdef LOCK_DEBUG
466         int before = *pointer;
467 #endif
468
469         ret = add_lock_callback(pointer, amount, type, file, line);
470 #ifdef LOCK_DEBUG
471         {
472             CRYPTO_THREADID id;
473             CRYPTO_THREADID_current(&id);
474             fprintf(stderr, "ladd:%08lx:%2d+%2d->%2d %-18s %s:%d\n",
475                     CRYPTO_THREADID_hash(&id), before, amount, ret,
476                     CRYPTO_get_lock_name(type), file, line);
477         }
478 #endif
479     } else {
480         CRYPTO_lock(CRYPTO_LOCK | CRYPTO_WRITE, type, file, line);
481
482         ret = *pointer + amount;
483 #ifdef LOCK_DEBUG
484         {
485             CRYPTO_THREADID id;
486             CRYPTO_THREADID_current(&id);
487             fprintf(stderr, "ladd:%08lx:%2d+%2d->%2d %-18s %s:%d\n",
488                     CRYPTO_THREADID_hash(&id),
489                     *pointer, amount, ret,
490                     CRYPTO_get_lock_name(type), file, line);
491         }
492 #endif
493         *pointer = ret;
494         CRYPTO_lock(CRYPTO_UNLOCK | CRYPTO_WRITE, type, file, line);
495     }
496     return (ret);
497 }
498
499 const char *CRYPTO_get_lock_name(int type)
500 {
501     if (type < 0)
502         return ("dynamic");
503     else if (type < CRYPTO_NUM_LOCKS)
504         return (lock_names[type]);
505     else if (type - CRYPTO_NUM_LOCKS > sk_OPENSSL_STRING_num(app_locks))
506         return ("ERROR");
507     else
508         return (sk_OPENSSL_STRING_value(app_locks, type - CRYPTO_NUM_LOCKS));
509 }