1 /* crypto/cryptlib.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 #include <stdio.h> 60 #include <string.h> 61 #include "cryptlib.h" 62 #include <openssl/crypto.h> 63 #include <openssl/safestack.h> 64 65 #if defined(WIN32) || defined(WIN16) 66 static double SSLeay_MSVC5_hack=0.0; /* and for VC1.5 */ 67 #endif 68 69 DECLARE_STACK_OF(CRYPTO_dynlock) 70 IMPLEMENT_STACK_OF(CRYPTO_dynlock) 71 72 /* real #defines in crypto.h, keep these upto date */ 73 static const char* lock_names[CRYPTO_NUM_LOCKS] = 74 { 75 "<<ERROR>>", 76 "err", 77 "err_hash", 78 "x509", 79 "x509_info", 80 "x509_pkey", 81 "x509_crl", 82 "x509_req", 83 "dsa", 84 "rsa", 85 "evp_pkey", 86 "x509_store", 87 "ssl_ctx", 88 "ssl_cert", 89 "ssl_session", 90 "ssl_sess_cert", 91 "ssl", 92 "rand", 93 "debug_malloc", 94 "BIO", 95 "gethostbyname", 96 "getservbyname", 97 "readdir", 98 "RSA_blinding", 99 "dh", 100 "debug_malloc2", 101 "dso", 102 "dynlock", 103 #if CRYPTO_NUM_LOCKS != 28 104 # error "Inconsistency between crypto.h and cryptlib.c" 105 #endif 106 }; 107 108 /* This is for applications to allocate new type names in the non-dynamic 109 array of lock names. These are numbered with positive numbers. */ 110 static STACK *app_locks=NULL; 111 112 /* For applications that want a more dynamic way of handling threads, the 113 following stack is used. These are externally numbered with negative 114 numbers. */ 115 static STACK_OF(CRYPTO_dynlock) *dyn_locks=NULL; 116 117 118 static void (MS_FAR *locking_callback)(int mode,int type, 119 const char *file,int line)=NULL; 120 static int (MS_FAR *add_lock_callback)(int *pointer,int amount, 121 int type,const char *file,int line)=NULL; 122 static unsigned long (MS_FAR *id_callback)(void)=NULL; 123 static struct CRYPTO_dynlock_value *(MS_FAR *dynlock_create_callback) 124 (const char *file,int line)=NULL; 125 static void (MS_FAR *dynlock_lock_callback)(int mode, 126 struct CRYPTO_dynlock_value *l, const char *file,int line)=NULL; 127 static void (MS_FAR *dynlock_destroy_callback)(struct CRYPTO_dynlock_value *l, 128 const char *file,int line)=NULL; 129 130 int CRYPTO_get_new_lockid(char *name) 131 { 132 char *str; 133 int i; 134 135 /* A hack to make Visual C++ 5.0 work correctly when linking as 136 * a DLL using /MT. Without this, the application cannot use 137 * and floating point printf's. 138 * It also seems to be needed for Visual C 1.5 (win16) */ 139 #if defined(WIN32) || defined(WIN16) 140 SSLeay_MSVC5_hack=(double)name[0]*(double)name[1]; 141 #endif 142 143 if ((app_locks == NULL) && ((app_locks=sk_new_null()) == NULL)) 144 { 145 CRYPTOerr(CRYPTO_F_CRYPTO_GET_NEW_LOCKID,ERR_R_MALLOC_FAILURE); 146 return(0); 147 } 148 if ((str=BUF_strdup(name)) == NULL) 149 { 150 CRYPTOerr(CRYPTO_F_CRYPTO_GET_NEW_LOCKID,ERR_R_MALLOC_FAILURE); 151 return(0); 152 } 153 i=sk_push(app_locks,str); 154 if (!i) 155 OPENSSL_free(str); 156 else 157 i+=CRYPTO_NUM_LOCKS; /* gap of one :-) */ 158 return(i); 159 } 160 161 int CRYPTO_num_locks(void) 162 { 163 return CRYPTO_NUM_LOCKS; 164 } 165 166 int CRYPTO_get_new_dynlockid(void) 167 { 168 int i = 0; 169 CRYPTO_dynlock *pointer = NULL; 170 171 if (dynlock_create_callback == NULL) 172 { 173 CRYPTOerr(CRYPTO_F_CRYPTO_GET_NEW_DYNLOCKID,CRYPTO_R_NO_DYNLOCK_CREATE_CALLBACK); 174 return(0); 175 } 176 CRYPTO_w_lock(CRYPTO_LOCK_DYNLOCK); 177 if ((dyn_locks == NULL) 178 && ((dyn_locks=sk_CRYPTO_dynlock_new_null()) == NULL)) 179 { 180 CRYPTO_w_unlock(CRYPTO_LOCK_DYNLOCK); 181 CRYPTOerr(CRYPTO_F_CRYPTO_GET_NEW_DYNLOCKID,ERR_R_MALLOC_FAILURE); 182 return(0); 183 } 184 CRYPTO_w_unlock(CRYPTO_LOCK_DYNLOCK); 185 186 pointer = (CRYPTO_dynlock *)OPENSSL_malloc(sizeof(CRYPTO_dynlock)); 187 if (pointer == NULL) 188 { 189 CRYPTOerr(CRYPTO_F_CRYPTO_GET_NEW_DYNLOCKID,ERR_R_MALLOC_FAILURE); 190 return(0); 191 } 192 pointer->references = 1; 193 pointer->data = dynlock_create_callback(__FILE__,__LINE__); 194 if (pointer->data == NULL) 195 { 196 OPENSSL_free(pointer); 197 CRYPTOerr(CRYPTO_F_CRYPTO_GET_NEW_DYNLOCKID,ERR_R_MALLOC_FAILURE); 198 return(0); 199 } 200 201 CRYPTO_w_lock(CRYPTO_LOCK_DYNLOCK); 202 /* First, try to find an existing empty slot */ 203 i=sk_CRYPTO_dynlock_find(dyn_locks,NULL); 204 /* If there was none, push, thereby creating a new one */ 205 if (i == -1) 206 i=sk_CRYPTO_dynlock_push(dyn_locks,pointer); 207 CRYPTO_w_unlock(CRYPTO_LOCK_DYNLOCK); 208 209 if (!i) 210 { 211 dynlock_destroy_callback(pointer->data,__FILE__,__LINE__); 212 OPENSSL_free(pointer); 213 } 214 else 215 i += 1; /* to avoid 0 */ 216 return -i; 217 } 218 219 void CRYPTO_destroy_dynlockid(int i) 220 { 221 CRYPTO_dynlock *pointer = NULL; 222 if (i) 223 i = -i-1; 224 if (dynlock_destroy_callback == NULL) 225 return; 226 227 CRYPTO_w_lock(CRYPTO_LOCK_DYNLOCK); 228 229 if (dyn_locks == NULL || i >= sk_CRYPTO_dynlock_num(dyn_locks)) 230 return; 231 pointer = sk_CRYPTO_dynlock_value(dyn_locks, i); 232 if (pointer != NULL) 233 { 234 --pointer->references; 235 #ifdef REF_CHECK 236 if (pointer->references < 0) 237 { 238 fprintf(stderr,"CRYPTO_destroy_dynlockid, bad reference count\n"); 239 abort(); 240 } 241 else 242 #endif 243 if (--(pointer->references) <= 0) 244 { 245 sk_CRYPTO_dynlock_set(dyn_locks, i, NULL); 246 } 247 else 248 pointer = NULL; 249 } 250 CRYPTO_w_unlock(CRYPTO_LOCK_DYNLOCK); 251 252 if (pointer) 253 { 254 dynlock_destroy_callback(pointer->data,__FILE__,__LINE__); 255 OPENSSL_free(pointer); 256 } 257 } 258 259 struct CRYPTO_dynlock_value *CRYPTO_get_dynlock_value(int i) 260 { 261 CRYPTO_dynlock *pointer = NULL; 262 if (i) 263 i = -i-1; 264 265 CRYPTO_w_lock(CRYPTO_LOCK_DYNLOCK); 266 267 if (dyn_locks != NULL && i < sk_CRYPTO_dynlock_num(dyn_locks)) 268 pointer = sk_CRYPTO_dynlock_value(dyn_locks, i); 269 if (pointer) 270 pointer->references++; 271 272 CRYPTO_w_unlock(CRYPTO_LOCK_DYNLOCK); 273 274 if (pointer) 275 return pointer->data; 276 return NULL; 277 } 278 279 struct CRYPTO_dynlock_value *(*CRYPTO_get_dynlock_create_callback(void)) 280 (const char *file,int line) 281 { 282 return(dynlock_create_callback); 283 } 284 285 void (*CRYPTO_get_dynlock_lock_callback(void))(int mode, 286 struct CRYPTO_dynlock_value *l, const char *file,int line) 287 { 288 return(dynlock_lock_callback); 289 } 290 291 void (*CRYPTO_get_dynlock_destroy_callback(void)) 292 (struct CRYPTO_dynlock_value *l, const char *file,int line) 293 { 294 return(dynlock_destroy_callback); 295 } 296 297 void CRYPTO_set_dynlock_create_callback(struct CRYPTO_dynlock_value *(*func) 298 (const char *file, int line)) 299 { 300 dynlock_create_callback=func; 301 } 302 303 void CRYPTO_set_dynlock_lock_callback(void (*func)(int mode, 304 struct CRYPTO_dynlock_value *l, const char *file, int line)) 305 { 306 dynlock_lock_callback=func; 307 } 308 309 void CRYPTO_set_dynlock_destroy_callback(void (*func) 310 (struct CRYPTO_dynlock_value *l, const char *file, int line)) 311 { 312 dynlock_destroy_callback=func; 313 } 314 315 316 void (*CRYPTO_get_locking_callback(void))(int mode,int type,const char *file, 317 int line) 318 { 319 return(locking_callback); 320 } 321 322 int (*CRYPTO_get_add_lock_callback(void))(int *num,int mount,int type, 323 const char *file,int line) 324 { 325 return(add_lock_callback); 326 } 327 328 void CRYPTO_set_locking_callback(void (*func)(int mode,int type, 329 const char *file,int line)) 330 { 331 locking_callback=func; 332 } 333 334 void CRYPTO_set_add_lock_callback(int (*func)(int *num,int mount,int type, 335 const char *file,int line)) 336 { 337 add_lock_callback=func; 338 } 339 340 unsigned long (*CRYPTO_get_id_callback(void))(void) 341 { 342 return(id_callback); 343 } 344 345 void CRYPTO_set_id_callback(unsigned long (*func)(void)) 346 { 347 id_callback=func; 348 } 349 350 unsigned long CRYPTO_thread_id(void) 351 { 352 unsigned long ret=0; 353 354 if (id_callback == NULL) 355 { 356 #ifdef WIN16 357 ret=(unsigned long)GetCurrentTask(); 358 #elif defined(WIN32) 359 ret=(unsigned long)GetCurrentThreadId(); 360 #elif defined(GETPID_IS_MEANINGLESS) 361 ret=1L; 362 #else 363 ret=(unsigned long)getpid(); 364 #endif 365 } 366 else 367 ret=id_callback(); 368 return(ret); 369 } 370 371 void CRYPTO_lock(int mode, int type, const char *file, int line) 372 { 373 #ifdef LOCK_DEBUG 374 { 375 char *rw_text,*operation_text; 376 377 if (mode & CRYPTO_LOCK) 378 operation_text="lock "; 379 else if (mode & CRYPTO_UNLOCK) 380 operation_text="unlock"; 381 else 382 operation_text="ERROR "; 383 384 if (mode & CRYPTO_READ) 385 rw_text="r"; 386 else if (mode & CRYPTO_WRITE) 387 rw_text="w"; 388 else 389 rw_text="ERROR"; 390 391 fprintf(stderr,"lock:%08lx:(%s)%s %-18s %s:%d\n", 392 CRYPTO_thread_id(), rw_text, operation_text, 393 CRYPTO_get_lock_name(type), file, line); 394 } 395 #endif 396 if (type < 0) 397 { 398 int i = -type - 1; 399 struct CRYPTO_dynlock_value *pointer 400 = CRYPTO_get_dynlock_value(i); 401 402 if (pointer) 403 { 404 dynlock_lock_callback(mode, pointer, file, line); 405 } 406 407 CRYPTO_destroy_dynlockid(i); 408 } 409 else 410 if (locking_callback != NULL) 411 locking_callback(mode,type,file,line); 412 } 413 414 int CRYPTO_add_lock(int *pointer, int amount, int type, const char *file, 415 int line) 416 { 417 int ret = 0; 418 419 if (add_lock_callback != NULL) 420 { 421 #ifdef LOCK_DEBUG 422 int before= *pointer; 423 #endif 424 425 ret=add_lock_callback(pointer,amount,type,file,line); 426 #ifdef LOCK_DEBUG 427 fprintf(stderr,"ladd:%08lx:%2d+%2d->%2d %-18s %s:%d\n", 428 CRYPTO_thread_id(), 429 before,amount,ret, 430 CRYPTO_get_lock_name(type), 431 file,line); 432 #endif 433 *pointer=ret; 434 } 435 else 436 { 437 CRYPTO_lock(CRYPTO_LOCK|CRYPTO_WRITE,type,file,line); 438 439 ret= *pointer+amount; 440 #ifdef LOCK_DEBUG 441 fprintf(stderr,"ladd:%08lx:%2d+%2d->%2d %-18s %s:%d\n", 442 CRYPTO_thread_id(), 443 *pointer,amount,ret, 444 CRYPTO_get_lock_name(type), 445 file,line); 446 #endif 447 *pointer=ret; 448 CRYPTO_lock(CRYPTO_UNLOCK|CRYPTO_WRITE,type,file,line); 449 } 450 return(ret); 451 } 452 453 const char *CRYPTO_get_lock_name(int type) 454 { 455 if (type < 0) 456 return("dynamic"); 457 else if (type < CRYPTO_NUM_LOCKS) 458 return(lock_names[type]); 459 else if (type-CRYPTO_NUM_LOCKS >= sk_num(app_locks)) 460 return("ERROR"); 461 else 462 return(sk_value(app_locks,type-CRYPTO_NUM_LOCKS)); 463 } 464 465 #ifdef _DLL 466 #ifdef WIN32 467 468 /* All we really need to do is remove the 'error' state when a thread 469 * detaches */ 470 471 BOOL WINAPI DLLEntryPoint(HINSTANCE hinstDLL, DWORD fdwReason, 472 LPVOID lpvReserved) 473 { 474 switch(fdwReason) 475 { 476 case DLL_PROCESS_ATTACH: 477 break; 478 case DLL_THREAD_ATTACH: 479 break; 480 case DLL_THREAD_DETACH: 481 ERR_remove_state(0); 482 break; 483 case DLL_PROCESS_DETACH: 484 break; 485 } 486 return(TRUE); 487 } 488 #endif 489 490 #endif 491