5128fb83640188e13bbd88c4ae876b32b03dff52 galt Fri Feb 4 01:55:05 2022 -0800 Further moving getenv together and cloning values for better safer getenv use. diff --git src/lib/https.c src/lib/https.c index 37e17dc..53c6cbc 100644 --- src/lib/https.c +++ src/lib/https.c @@ -10,30 +10,35 @@ #include <unistd.h> #include <pthread.h> #include <signal.h> #include "common.h" #include "internet.h" #include "errAbort.h" #include "hash.h" #include "net.h" char *https_cert_check = NULL; char *https_cert_check_depth = NULL; char *https_cert_check_verbose = NULL; char *https_cert_check_domain_exceptions = NULL; +char *https_proxy = NULL; +char *log_proxy = NULL; + +char *SCRIPT_NAME = NULL; + // For use with callback. Set a variable into the connection itself, // and then use that during the callback. struct myData { char *hostName; }; int myDataIndex = -1; static pthread_mutex_t *mutexes = NULL; static unsigned long openssl_id_callback(void) { return ((unsigned long)pthread_self()); } @@ -84,35 +89,39 @@ char *thisSetting = getenv(setting); if (thisSetting) return cloneString(thisSetting); else return cloneString(defaultValue); } void openSslInit() /* do only once */ { static boolean done = FALSE; static pthread_mutex_t osiMutex = PTHREAD_MUTEX_INITIALIZER; pthread_mutex_lock( &osiMutex ); if (!done) { - // setenv here for thread-safety + // setenv avoided since not thread-safe https_cert_check = mySetenv("https_cert_check", "log"); // DEFAULT certificate check is log. https_cert_check_depth = mySetenv("https_cert_check_depth", "9"); // DEFAULT depth check level is 9. https_cert_check_verbose = mySetenv("https_cert_check_verbose", "off"); // DEFAULT verbose is off. https_cert_check_domain_exceptions = mySetenv("https_cert_check_domain_exceptions", ""); // DEFAULT space separated list is empty string. + // getenv here for thread-safety + https_proxy = cloneString(getenv("https_proxy")); + log_proxy = cloneString(getenv("log_proxy")); + SCRIPT_NAME = cloneString(getenv("SCRIPT_NAME")); SSL_library_init(); ERR_load_crypto_strings(); ERR_load_SSL_strings(); OpenSSL_add_all_algorithms(); openssl_pthread_setup(); myDataIndex = SSL_get_ex_new_index(0, "myDataIndex", NULL, NULL, NULL); initDomainWhiteListHash(); done = TRUE; } pthread_mutex_unlock( &osiMutex ); } void *netConnectHttpsThread(void *threadParam) @@ -333,34 +342,34 @@ myData = SSL_get_ex_data(ssl, myDataIndex); if (depth > atoi(https_cert_check_depth)) { preverify_ok = 0; err = X509_V_ERR_CERT_CHAIN_TOO_LONG; X509_STORE_CTX_set_error(ctx, err); } if (sameString(https_cert_check_verbose, "on")) { fprintf(stderr,"depth=%d:%s\n", depth, buf); } if (!preverify_ok) { - if (getenv("SCRIPT_NAME")) // CGI mode + if (SCRIPT_NAME) // CGI mode { fprintf(stderr, "verify error:num=%d:%s:depth=%d:%s hostName=%s CGI=%s\n", err, - X509_verify_cert_error_string(err), depth, buf, myData->hostName, getenv("SCRIPT_NAME")); + X509_verify_cert_error_string(err), depth, buf, myData->hostName, SCRIPT_NAME); } if (!sameString(https_cert_check, "log")) { char *cn = strstr(buf, "/CN="); if (cn) cn+=4; // strlen /CN= if (sameString(cn, myData->hostName)) warn("%s on %s", X509_verify_cert_error_string(err), cn); else warn("%s on %s (%s)", X509_verify_cert_error_string(err), cn, myData->hostName); } } /* err contains the last verification error. */ if (!preverify_ok && (err == X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT)) { X509_NAME_oneline(X509_get_issuer_name(cert), buf, 256); @@ -518,60 +527,60 @@ safef(wildHost, sizeof wildHost, "*%s", dot); result = hashLookup(domainWhiteList, wildHost); } } return result; } int netConnectHttps(char *hostName, int port, boolean noProxy) /* Return socket for https connection with server or -1 if error. */ { int fd=0; // https_cert_check env var can be abort warn or none. -char *proxyUrl = getenv("https_proxy"); +char *proxyUrl = https_proxy; if (noProxy) proxyUrl = NULL; char *connectHost; int connectPort; BIO *fbio=NULL; // file descriptor bio BIO *sbio=NULL; // ssl bio SSL_CTX *ctx; SSL *ssl; openSslInit(); ctx = SSL_CTX_new(SSLv23_client_method()); fd_set readfds; fd_set writefds; int err; struct timeval tv; struct myData myData; boolean doSetMyData = FALSE; if (!sameString(https_cert_check, "none")) { if (checkIfInHashWithWildCard(hostName)) { // old existing domains which are not (yet) compatible with openssl. - if (getenv("SCRIPT_NAME")) // CGI mode + if (SCRIPT_NAME) // CGI mode { fprintf(stderr, "domain %s cert check skipped because it is white-listed as an exception.\n", hostName); } } else { // verify peer cert of the server. // Set TRUSTED_FIRST for openssl 1.0 // Fixes common issue openssl 1.0 had with with LetsEncrypt certs in the Fall of 2021. X509_STORE_set_flags(SSL_CTX_get_cert_store(ctx), X509_V_FLAG_TRUSTED_FIRST); // This flag causes intermediate certificates in the trust store to be treated as trust-anchors, in the same way as the self-signed root CA certificates. // This makes it possible to trust certificates issued by an intermediate CA without having to trust its ancestor root CA. // GNU-TLS uses it, and openssl probably will do it in the future. @@ -620,32 +629,31 @@ } else { connectHost = hostName; connectPort = port; } fd = netConnect(connectHost,connectPort); if (fd == -1) { warn("netConnect() failed"); goto cleanup2; } if (proxyUrl) { - char *logProxy = getenv("log_proxy"); - if (sameOk(logProxy,"on")) + if (sameOk(log_proxy,"on")) verbose(1, "CONNECT %s:%d HTTP/1.0 via %s:%d\n", hostName, port, connectHost,connectPort); struct dyString *dy = newDyString(512); dyStringPrintf(dy, "CONNECT %s:%d HTTP/1.0\r\n", hostName, port); setAuthorization(pxy, "Proxy-Authorization", dy); dyStringAppend(dy, "\r\n"); mustWriteFd(fd, dy->string, dy->stringSize); dyStringFree(&dy); // verify response char *newUrl = NULL; boolean success = netSkipHttpHeaderLinesWithRedirect(fd, proxyUrl, &newUrl); if (!success) { warn("proxy server response failed"); goto cleanup2; }