@@ -36,38 +36,38 @@ #define F2N( key, dsp) \ (((key) == NULL) ? (char *) NULL : \ Tcl_TranslateFileName(interp, (key), (dsp))) #define REASON() ERR_reason_error_string(ERR_get_error()) -static void InfoCallback _ANSI_ARGS_ ((CONST SSL *ssl, int where, int ret)); - -static int CiphersObjCmd _ANSI_ARGS_ ((ClientData clientData, - Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[])); - -static int HandshakeObjCmd _ANSI_ARGS_ ((ClientData clientData, - Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[])); - -static int ImportObjCmd _ANSI_ARGS_ ((ClientData clientData, - Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[])); - -static int StatusObjCmd _ANSI_ARGS_ ((ClientData clientData, - Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[])); - -static int VersionObjCmd _ANSI_ARGS_ ((ClientData clientData, - Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[])); - -static int MiscObjCmd _ANSI_ARGS_ ((ClientData clientData, - Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[])); - -static int UnimportObjCmd _ANSI_ARGS_ ((ClientData clientData, - Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[])); - -static SSL_CTX *CTX_Init _ANSI_ARGS_((State *statePtr, int proto, char *key, +static void InfoCallback(CONST SSL *ssl, int where, int ret); + +static int CiphersObjCmd(ClientData clientData, + Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]); + +static int HandshakeObjCmd(ClientData clientData, + Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]); + +static int ImportObjCmd(ClientData clientData, + Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]); + +static int StatusObjCmd(ClientData clientData, + Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]); + +static int VersionObjCmd(ClientData clientData, + Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]); + +static int MiscObjCmd(ClientData clientData, + Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]); + +static int UnimportObjCmd(ClientData clientData, + Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]); + +static SSL_CTX *CTX_Init(State *statePtr, int proto, char *key, char *cert, char *CAdir, char *CAfile, char *ciphers, - char *DHparams)); + char *DHparams); -static int TlsLibInit _ANSI_ARGS_ ((void)) ; +static int TlsLibInit(int uninitialize); #define TLS_PROTO_SSL2 0x01 #define TLS_PROTO_SSL3 0x02 #define TLS_PROTO_TLS1 0x04 #define TLS_PROTO_TLS1_1 0x08 @@ -80,16 +80,10 @@ #ifndef OPENSSL_NO_DH #include "dh_params.h" #endif -/* - * Defined in Tls_Init to determine what kind of channels we are using - * (old-style 8.2.0-8.3.1 or new-style 8.3.2+). - */ -int channelTypeVersion = TLS_CHANNEL_VERSION_2; - /* * We lose the tcl password callback when we use the RSA BSAFE SSL-C 1.1.2 * libraries instead of the current OpenSSL libraries. */ @@ -121,30 +115,42 @@ /* * Threaded operation requires locking callbacks * Based from /crypto/cryptlib.c of OpenSSL and NSOpenSSL. */ -static Tcl_Mutex locks[CRYPTO_NUM_LOCKS]; +static Tcl_Mutex *locks = NULL; +static int locksCount = 0; static Tcl_Mutex init_mx; -static void CryptoThreadLockCallback (int mode, int n, const char *file, int line); -static unsigned long CryptoThreadIdCallback (void); - -static void -CryptoThreadLockCallback(int mode, int n, const char *file, int line) -{ - if (mode & CRYPTO_LOCK) { - Tcl_MutexLock(&locks[n]); - } else { - Tcl_MutexUnlock(&locks[n]); - } -} - -static unsigned long -CryptoThreadIdCallback(void) -{ - return (unsigned long) Tcl_GetCurrentThread(); +void CryptoThreadLockCallback(int mode, int n, const char *file, int line) { + + if (mode & CRYPTO_LOCK) { + /* This debugging is turned off by default -- it's too noisy. */ + /* dprintf("Called to lock (n=%i of %i)", n, locksCount); */ + Tcl_MutexLock(&locks[n]); + } else { + /* dprintf("Called to unlock (n=%i of %i)", n, locksCount); */ + Tcl_MutexUnlock(&locks[n]); + } + + dprintf("Returning"); + + return; + file = file; + line = line; +} + +unsigned long CryptoThreadIdCallback(void) { + unsigned long ret; + + dprintf("Called"); + + ret = (unsigned long) Tcl_GetCurrentThread(); + + dprintf("Returning %lu", ret); + + return(ret); } #endif /* OPENSSL_THREADS */ #endif /* TCL_THREADS */ @@ -166,10 +172,12 @@ InfoCallback(CONST SSL *ssl, int where, int ret) { State *statePtr = (State*)SSL_get_app_data((SSL *)ssl); Tcl_Obj *cmdPtr; char *major; char *minor; + + dprintf("Called"); if (statePtr->callback == (Tcl_Obj*)NULL) return; cmdPtr = Tcl_DuplicateObj(statePtr->callback); @@ -262,11 +270,11 @@ VerifyCallback(int ok, X509_STORE_CTX *ctx) { Tcl_Obj *cmdPtr, *result; char *errStr, *string; int length; - SSL *ssl = (SSL*)X509_STORE_CTX_get_app_data(ctx); + SSL *ssl = (SSL*)X509_STORE_CTX_get_ex_data(ctx, SSL_get_ex_data_X509_STORE_CTX_idx()); X509 *cert = X509_STORE_CTX_get_current_cert(ctx); State *statePtr = (State*)SSL_get_app_data(ssl); int depth = X509_STORE_CTX_get_error_depth(ctx); int err = X509_STORE_CTX_get_error(ctx); @@ -352,10 +360,12 @@ void Tls_Error(State *statePtr, char *msg) { Tcl_Obj *cmdPtr; + dprintf("Called"); + if (msg && *msg) { Tcl_SetErrorCode(statePtr->interp, "SSL", msg, (char *)NULL); } else { msg = Tcl_GetStringFromObj(Tcl_GetObjResult(statePtr->interp), NULL); } @@ -410,19 +420,24 @@ */ static int PasswordCallback(char *buf, int size, int verify) { return -1; + buf = buf; + size = size; + verify = verify; } #else static int PasswordCallback(char *buf, int size, int verify, void *udata) { State *statePtr = (State *) udata; Tcl_Interp *interp = statePtr->interp; Tcl_Obj *cmdPtr; int result; + + dprintf("Called"); if (statePtr->password == NULL) { if (Tcl_EvalEx(interp, "tls::password", -1, TCL_EVAL_GLOBAL) == TCL_OK) { char *ret = (char *) Tcl_GetStringResult(interp); @@ -453,10 +468,11 @@ strncpy(buf, ret, (size_t) size); return (int)strlen(ret); } else { return -1; } + verify = verify; } #endif /* *------------------------------------------------------------------- @@ -491,10 +507,12 @@ SSL_CTX *ctx = NULL; SSL *ssl = NULL; STACK_OF(SSL_CIPHER) *sk; char *cp, buf[BUFSIZ]; int index, verbose = 0; + + dprintf("Called"); if (objc < 2 || objc > 3) { Tcl_WrongNumArgs(interp, 1, objv, "protocol ?verbose?"); return TCL_ERROR; } @@ -586,10 +604,11 @@ SSL_free(ssl); SSL_CTX_free(ctx); Tcl_SetObjResult( interp, objPtr); return TCL_OK; + clientData = clientData; } /* *------------------------------------------------------------------- * @@ -616,56 +635,62 @@ { Tcl_Channel chan; /* The channel to set a mode on. */ State *statePtr; /* client state for ssl socket */ int ret = 1; + dprintf("Called"); + if (objc != 2) { Tcl_WrongNumArgs(interp, 1, objv, "channel"); return TCL_ERROR; } chan = Tcl_GetChannel(interp, Tcl_GetStringFromObj(objv[1], NULL), NULL); if (chan == (Tcl_Channel) NULL) { return TCL_ERROR; } - if (channelTypeVersion == TLS_CHANNEL_VERSION_2) { - /* - * Make sure to operate on the topmost channel - */ - chan = Tcl_GetTopChannel(chan); - } + + /* + * Make sure to operate on the topmost channel + */ + chan = Tcl_GetTopChannel(chan); if (Tcl_GetChannelType(chan) != Tls_ChannelType()) { Tcl_AppendResult(interp, "bad channel \"", Tcl_GetChannelName(chan), "\": not a TLS channel", NULL); return TCL_ERROR; } statePtr = (State *)Tcl_GetChannelInstanceData(chan); if (!SSL_is_init_finished(statePtr->ssl)) { int err = 0; + dprintf("Calling Tls_WaitForConnect"); ret = Tls_WaitForConnect(statePtr, &err); + dprintf("Tls_WaitForConnect returned: %i", ret); + if ((statePtr->flags & TLS_TCL_ASYNC) && err == EAGAIN) { dprintf("Async set and err = EAGAIN"); ret = 0; } + if (ret < 0) { CONST char *errStr = statePtr->err; Tcl_ResetResult(interp); Tcl_SetErrno(err); if (!errStr || *errStr == 0) { errStr = Tcl_PosixError(interp); } - Tcl_AppendResult(interp, "handshake failed: ", errStr, - (char *) NULL); + Tcl_AppendResult(interp, "handshake failed: ", errStr, (char *) NULL); + dprintf("Returning TCL_ERROR with handshake failed: %s", errStr); return TCL_ERROR; } } Tcl_SetObjResult(interp, Tcl_NewIntObj(ret)); return TCL_OK; + clientData = clientData; } /* *------------------------------------------------------------------- * @@ -735,25 +760,26 @@ int tls1_2 = 1; #endif int proto = 0; int verify = 0, require = 0, request = 1; + dprintf("Called"); + if (objc < 2) { Tcl_WrongNumArgs(interp, 1, objv, "channel ?options?"); return TCL_ERROR; } chan = Tcl_GetChannel(interp, Tcl_GetStringFromObj(objv[1], NULL), NULL); if (chan == (Tcl_Channel) NULL) { return TCL_ERROR; } - if (channelTypeVersion == TLS_CHANNEL_VERSION_2) { - /* - * Make sure to operate on the topmost channel - */ - chan = Tcl_GetTopChannel(chan); - } + + /* + * Make sure to operate on the topmost channel + */ + chan = Tcl_GetTopChannel(chan); for (idx = 2; idx < objc; idx++) { char *opt = Tcl_GetStringFromObj(objv[idx], NULL); if (opt[0] != '-') @@ -836,16 +862,15 @@ chan = Tcl_GetChannel(interp, model, &mode); if (chan == (Tcl_Channel) NULL) { Tls_Free((char *) statePtr); return TCL_ERROR; } - if (channelTypeVersion == TLS_CHANNEL_VERSION_2) { - /* - * Make sure to operate on the topmost channel - */ - chan = Tcl_GetTopChannel(chan); - } + + /* + * Make sure to operate on the topmost channel + */ + chan = Tcl_GetTopChannel(chan); if (Tcl_GetChannelType(chan) != Tls_ChannelType()) { Tcl_AppendResult(interp, "bad channel \"", Tcl_GetChannelName(chan), "\": not a TLS channel", NULL); Tls_Free((char *) statePtr); return TCL_ERROR; @@ -866,22 +891,14 @@ * encryption not to get goofed up). * We only want to adjust the buffering in pre-v2 channels, where * each channel in the stack maintained its own buffers. */ Tcl_SetChannelOption(interp, chan, "-translation", "binary"); - if (channelTypeVersion == TLS_CHANNEL_VERSION_1) { - Tcl_SetChannelOption(interp, chan, "-buffering", "none"); - } - - if (channelTypeVersion == TLS_CHANNEL_VERSION_2) { - statePtr->self = Tcl_StackChannel(interp, Tls_ChannelType(), - (ClientData) statePtr, (TCL_READABLE | TCL_WRITABLE), chan); - } else { - statePtr->self = chan; - Tcl_StackChannel(interp, Tls_ChannelType(), - (ClientData) statePtr, (TCL_READABLE | TCL_WRITABLE), chan); - } + Tcl_SetChannelOption(interp, chan, "-blocking", "true"); + dprintf("Consuming Tcl channel %s", Tcl_GetChannelName(chan)); + statePtr->self = Tcl_StackChannel(interp, Tls_ChannelType(), (ClientData) statePtr, (TCL_READABLE | TCL_WRITABLE), chan); + dprintf("Created channel named %s", Tcl_GetChannelName(statePtr->self)); if (statePtr->self == (Tcl_Channel) NULL) { /* * No use of Tcl_EventuallyFree because no possible Tcl_Preserve. */ Tls_Free((char *) statePtr); @@ -921,11 +938,11 @@ SSL_set_verify(statePtr->ssl, verify, VerifyCallback); SSL_CTX_set_info_callback(statePtr->ctx, InfoCallback); /* Create Tcl_Channel BIO Handler */ - statePtr->p_bio = BIO_new_tcl(statePtr, BIO_CLOSE); + statePtr->p_bio = BIO_new_tcl(statePtr, BIO_NOCLOSE); statePtr->bio = BIO_new(BIO_f_ssl()); if (server) { statePtr->flags |= TLS_TCL_SERVER; SSL_set_accept_state(statePtr->ssl); @@ -936,13 +953,15 @@ BIO_set_ssl(statePtr->bio, statePtr->ssl, BIO_NOCLOSE); /* * End of SSL Init */ + dprintf("Returning %s", Tcl_GetChannelName(statePtr->self)); Tcl_SetResult(interp, (char *) Tcl_GetChannelName(statePtr->self), TCL_VOLATILE); return TCL_OK; + clientData = clientData; } /* *------------------------------------------------------------------- * @@ -966,10 +985,12 @@ int objc; Tcl_Obj *CONST objv[]; { Tcl_Channel chan; /* The channel to set a mode on. */ + dprintf("Called"); + if (objc != 2) { Tcl_WrongNumArgs(interp, 1, objv, "channel"); return TCL_ERROR; } @@ -976,16 +997,14 @@ chan = Tcl_GetChannel(interp, Tcl_GetString(objv[1]), NULL); if (chan == (Tcl_Channel) NULL) { return TCL_ERROR; } - if (channelTypeVersion == TLS_CHANNEL_VERSION_2) { - /* - * Make sure to operate on the topmost channel - */ - chan = Tcl_GetTopChannel(chan); - } + /* + * Make sure to operate on the topmost channel + */ + chan = Tcl_GetTopChannel(chan); if (Tcl_GetChannelType(chan) != Tls_ChannelType()) { Tcl_AppendResult(interp, "bad channel \"", Tcl_GetChannelName(chan), "\": not a TLS channel", NULL); return TCL_ERROR; @@ -994,10 +1013,11 @@ if (Tcl_UnstackChannel(interp, chan) == TCL_ERROR) { return TCL_ERROR; } return TCL_OK; + clientData = clientData; } /* *------------------------------------------------------------------- * @@ -1027,10 +1047,12 @@ SSL_CTX *ctx = NULL; Tcl_DString ds; Tcl_DString ds1; int off = 0; const SSL_METHOD *method; + + dprintf("Called"); if (!proto) { Tcl_AppendResult(interp, "no valid protocol selected", NULL); return (SSL_CTX *)0; } @@ -1277,10 +1299,12 @@ Tcl_Obj *objPtr; Tcl_Channel chan; char *channelName, *ciphers; int mode; + dprintf("Called"); + switch (objc) { case 2: channelName = Tcl_GetStringFromObj(objv[1], NULL); break; @@ -1297,16 +1321,14 @@ chan = Tcl_GetChannel(interp, channelName, &mode); if (chan == (Tcl_Channel) NULL) { return TCL_ERROR; } - if (channelTypeVersion == TLS_CHANNEL_VERSION_2) { - /* - * Make sure to operate on the topmost channel - */ - chan = Tcl_GetTopChannel(chan); - } + /* + * Make sure to operate on the topmost channel + */ + chan = Tcl_GetTopChannel(chan); if (Tcl_GetChannelType(chan) != Tls_ChannelType()) { Tcl_AppendResult(interp, "bad channel \"", Tcl_GetChannelName(chan), "\": not a TLS channel", NULL); return TCL_ERROR; } @@ -1335,10 +1357,11 @@ Tcl_ListObjAppendElement(interp, objPtr, Tcl_NewStringObj(SSL_get_cipher(statePtr->ssl), -1)); } Tcl_SetObjResult( interp, objPtr); return TCL_OK; + clientData = clientData; } /* *------------------------------------------------------------------- * @@ -1358,15 +1381,20 @@ Tcl_Interp *interp; int objc; Tcl_Obj *CONST objv[]; { Tcl_Obj *objPtr; + + dprintf("Called"); objPtr = Tcl_NewStringObj(OPENSSL_VERSION_TEXT, -1); Tcl_SetObjResult(interp, objPtr); return TCL_OK; + clientData = clientData; + objc = objc; + objv = objv; } /* *------------------------------------------------------------------- * @@ -1388,10 +1416,12 @@ Tcl_Obj *CONST objv[]; { static CONST84 char *commands [] = { "req", NULL }; enum command { C_REQ, C_DUMMY }; int cmd; + + dprintf("Called"); if (objc < 2) { Tcl_WrongNumArgs(interp, 1, objv, "subcommand ?args?"); return TCL_ERROR; } @@ -1525,10 +1555,11 @@ break; default: break; } return TCL_OK; + clientData = clientData; } /* *------------------------------------------------------------------- * @@ -1547,10 +1578,12 @@ */ void Tls_Free( char *blockPtr ) { State *statePtr = (State *)blockPtr; + + dprintf("Called"); Tls_Clean(statePtr); ckfree(blockPtr); } @@ -1570,17 +1603,16 @@ * Side effects: * Frees all the state * *------------------------------------------------------------------- */ -void -Tls_Clean(State *statePtr) -{ +void Tls_Clean(State *statePtr) { + dprintf("Called"); + /* * we're assuming here that we're single-threaded */ - if (statePtr->timer != (Tcl_TimerToken) NULL) { Tcl_DeleteTimerHandler(statePtr->timer); statePtr->timer = NULL; } @@ -1605,10 +1637,12 @@ } if (statePtr->password) { Tcl_DecrRefCount(statePtr->password); statePtr->password = NULL; } + + dprintf("Returning"); } /* *------------------------------------------------------------------- * @@ -1623,84 +1657,51 @@ * create the ssl command, initialise ssl context * *------------------------------------------------------------------- */ -int -Tls_Init(Tcl_Interp *interp) /* Interpreter in which the package is - * to be made available. */ -{ - const char tlsTclInitScript[] = { +int Tls_Init(Tcl_Interp *interp) { + const char tlsTclInitScript[] = { #include "tls.tcl.h" - }; - - int major, minor, patchlevel, release; - - /* - * The original 8.2.0 stacked channel implementation (and the patch - * that preceded it) had problems with scalability and robustness. - * These were address in 8.3.2 / 8.4a2, so we now require that as a - * minimum for TLS 1.4+. We only support 8.2+ now (8.3.2+ preferred). - */ - if ( + , 0x00 + }; + + dprintf("Called"); + + /* + * We only support Tcl 8.4 or newer + */ + if ( #ifdef USE_TCL_STUBS - Tcl_InitStubs(interp, "8.2", 0) + Tcl_InitStubs(interp, "8.4", 0) #else - Tcl_PkgRequire(interp, "Tcl", "8.2", 0) -#endif - == NULL) { - return TCL_ERROR; - } - - /* - * Get the version so we can runtime switch on available functionality. - * TLS should really only be used in 8.3.2+, but the other works for - * some limited functionality, so an attempt at support is made. - */ - Tcl_GetVersion(&major, &minor, &patchlevel, &release); - if ((major > 8) || ((major == 8) && ((minor > 3) || ((minor == 3) && - (release == TCL_FINAL_RELEASE) && (patchlevel >= 2))))) { - /* 8.3.2+ */ - channelTypeVersion = TLS_CHANNEL_VERSION_2; - } else { - /* 8.2.0 - 8.3.1 */ - channelTypeVersion = TLS_CHANNEL_VERSION_1; - } - - if (TlsLibInit() != TCL_OK) { - Tcl_AppendResult(interp, "could not initialize SSL library", NULL); - return TCL_ERROR; - } - - Tcl_CreateObjCommand(interp, "tls::ciphers", CiphersObjCmd, - (ClientData) 0, (Tcl_CmdDeleteProc *) NULL); - - Tcl_CreateObjCommand(interp, "tls::handshake", HandshakeObjCmd, - (ClientData) 0, (Tcl_CmdDeleteProc *) NULL); - - Tcl_CreateObjCommand(interp, "tls::import", ImportObjCmd, - (ClientData) 0, (Tcl_CmdDeleteProc *) NULL); - - Tcl_CreateObjCommand(interp, "tls::unimport", UnimportObjCmd, - (ClientData) 0, (Tcl_CmdDeleteProc *) NULL); - - Tcl_CreateObjCommand(interp, "tls::status", StatusObjCmd, - (ClientData) 0, (Tcl_CmdDeleteProc *) NULL); - - Tcl_CreateObjCommand(interp, "tls::version", VersionObjCmd, - (ClientData) 0, (Tcl_CmdDeleteProc *) NULL); - - Tcl_CreateObjCommand(interp, "tls::misc", MiscObjCmd, - (ClientData) 0, (Tcl_CmdDeleteProc *) NULL); - - if (interp) { - Tcl_Eval(interp, tlsTclInitScript); - } - - return Tcl_PkgProvide(interp, "tls", PACKAGE_VERSION); -} - + Tcl_PkgRequire(interp, "Tcl", "8.4", 0) +#endif + == NULL) { + return TCL_ERROR; + } + + if (TlsLibInit(0) != TCL_OK) { + Tcl_AppendResult(interp, "could not initialize SSL library", NULL); + return TCL_ERROR; + } + + Tcl_CreateObjCommand(interp, "tls::ciphers", CiphersObjCmd, (ClientData) 0, (Tcl_CmdDeleteProc *) NULL); + Tcl_CreateObjCommand(interp, "tls::handshake", HandshakeObjCmd, (ClientData) 0, (Tcl_CmdDeleteProc *) NULL); + Tcl_CreateObjCommand(interp, "tls::import", ImportObjCmd, (ClientData) 0, (Tcl_CmdDeleteProc *) NULL); + Tcl_CreateObjCommand(interp, "tls::unimport", UnimportObjCmd, (ClientData) 0, (Tcl_CmdDeleteProc *) NULL); + Tcl_CreateObjCommand(interp, "tls::status", StatusObjCmd, (ClientData) 0, (Tcl_CmdDeleteProc *) NULL); + Tcl_CreateObjCommand(interp, "tls::version", VersionObjCmd, (ClientData) 0, (Tcl_CmdDeleteProc *) NULL); + Tcl_CreateObjCommand(interp, "tls::misc", MiscObjCmd, (ClientData) 0, (Tcl_CmdDeleteProc *) NULL); + + if (interp) { + Tcl_Eval(interp, tlsTclInitScript); + } + + return(Tcl_PkgProvide(interp, "tls", PACKAGE_VERSION)); +} + /* *------------------------------------------------------* * * Tls_SafeInit -- * @@ -1716,17 +1717,15 @@ * A standard Tcl error code. * *------------------------------------------------------* */ -int -Tls_SafeInit (Tcl_Interp* interp) -{ - return Tls_Init (interp); +int Tls_SafeInit(Tcl_Interp *interp) { + dprintf("Called"); + return(Tls_Init(interp)); } - /* *------------------------------------------------------* * * TlsLibInit -- * @@ -1740,71 +1739,106 @@ * Result: * none * *------------------------------------------------------* */ -static int TlsLibInit (void) { - static int initialized = 0; - int i; - char rnd_seed[16] = "GrzSlplKqUdnnzP!"; /* 16 bytes */ - int status=TCL_OK; - - if (initialized) { - return status; - } - initialized = 1; - -#if defined(OPENSSL_THREADS) && defined(TCL_THREADS) - size_t num_locks; - - Tcl_MutexLock(&init_mx); -#endif - - if (CRYPTO_set_mem_functions((void *(*)(size_t))Tcl_Alloc, - (void *(*)(void *, size_t))Tcl_Realloc, - (void(*)(void *))Tcl_Free) == 0) { - /* Not using Tcl's mem functions ... not critical */ - } - -#if defined(OPENSSL_THREADS) && defined(TCL_THREADS) - /* should we consider allocating mutexes? */ - num_locks = CRYPTO_num_locks(); - if (num_locks > CRYPTO_NUM_LOCKS) { - status=TCL_ERROR; - goto done; - } - - CRYPTO_set_locking_callback(CryptoThreadLockCallback); - CRYPTO_set_id_callback(CryptoThreadIdCallback); -#endif - - if (SSL_library_init() != 1) { - status=TCL_ERROR; - goto done; - } - SSL_load_error_strings(); - ERR_load_crypto_strings(); - - /* - * Seed the random number generator in the SSL library, - * using the do/while construct because of the bug note in the - * OpenSSL FAQ at http://www.openssl.org/support/faq.html#USER1 - * - * The crux of the problem is that Solaris 7 does not have a - * /dev/random or /dev/urandom device so it cannot gather enough - * entropy from the RAND_seed() when TLS initializes and refuses - * to go further. Earlier versions of OpenSSL carried on regardless. - */ - srand((unsigned int) time((time_t *) NULL)); - do { - for (i = 0; i < 16; i++) { - rnd_seed[i] = 1 + (char) (255.0 * rand()/(RAND_MAX+1.0)); - } - RAND_seed(rnd_seed, sizeof(rnd_seed)); - } while (RAND_status() != 1); -done: - +static int TlsLibInit(int uninitialize) { + static int initialized = 0; + int status = TCL_OK; +#if defined(OPENSSL_THREADS) && defined(TCL_THREADS) + size_t num_locks; +#endif + + if (uninitialize) { + if (!initialized) { + dprintf("Asked to uninitialize, but we are not initialized"); + + return(TCL_OK); + } + + dprintf("Asked to uninitialize"); + +#if defined(OPENSSL_THREADS) && defined(TCL_THREADS) + Tcl_MutexLock(&init_mx); + + CRYPTO_set_locking_callback(NULL); + CRYPTO_set_id_callback(NULL); + + if (locks) { + free(locks); + locks = NULL; + locksCount = 0; + } +#endif + initialized = 0; + +#if defined(OPENSSL_THREADS) && defined(TCL_THREADS) + Tcl_MutexUnlock(&init_mx); +#endif + + return(TCL_OK); + } + + if (initialized) { + dprintf("Called, but using cached value"); + return(status); + } + + dprintf("Called"); + +#if defined(OPENSSL_THREADS) && defined(TCL_THREADS) + Tcl_MutexLock(&init_mx); +#endif + initialized = 1; + +#if defined(OPENSSL_THREADS) && defined(TCL_THREADS) + num_locks = CRYPTO_num_locks(); + locksCount = num_locks; + locks = malloc(sizeof(*locks) * num_locks); + memset(locks, 0, sizeof(*locks) * num_locks); + + CRYPTO_set_locking_callback(CryptoThreadLockCallback); + CRYPTO_set_id_callback(CryptoThreadIdCallback); +#endif + + if (SSL_library_init() != 1) { + status = TCL_ERROR; + goto done; + } + + SSL_load_error_strings(); + ERR_load_crypto_strings(); + + BIO_new_tcl(NULL, 0); + +#if 0 + /* + * XXX:TODO: Remove this code and replace it with a check + * for enough entropy and do not try to create our own + * terrible entropy + */ + /* + * Seed the random number generator in the SSL library, + * using the do/while construct because of the bug note in the + * OpenSSL FAQ at http://www.openssl.org/support/faq.html#USER1 + * + * The crux of the problem is that Solaris 7 does not have a + * /dev/random or /dev/urandom device so it cannot gather enough + * entropy from the RAND_seed() when TLS initializes and refuses + * to go further. Earlier versions of OpenSSL carried on regardless. + */ + srand((unsigned int) time((time_t *) NULL)); + do { + for (i = 0; i < 16; i++) { + rnd_seed[i] = 1 + (char) (255.0 * rand()/(RAND_MAX+1.0)); + } + RAND_seed(rnd_seed, sizeof(rnd_seed)); + } while (RAND_status() != 1); +#endif + +done: #if defined(OPENSSL_THREADS) && defined(TCL_THREADS) Tcl_MutexUnlock(&init_mx); #endif - return status; + + return(status); }