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