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