Repository: ignite Updated Branches: refs/heads/master a824ba8e1 -> 394019eef
http://git-wip-us.apache.org/repos/asf/ignite/blob/394019ee/modules/platforms/cpp/odbc/src/connection.cpp ---------------------------------------------------------------------- diff --git a/modules/platforms/cpp/odbc/src/connection.cpp b/modules/platforms/cpp/odbc/src/connection.cpp index 4e8f4ab..11105b6 100644 --- a/modules/platforms/cpp/odbc/src/connection.cpp +++ b/modules/platforms/cpp/odbc/src/connection.cpp @@ -28,6 +28,10 @@ #include "ignite/odbc/connection.h" #include "ignite/odbc/message.h" #include "ignite/odbc/config/configuration.h" +#include "ignite/odbc/ssl/ssl_mode.h" +#include "ignite/odbc/ssl/ssl_gateway.h" +#include "ignite/odbc/ssl/secure_socket_client.h" +#include "ignite/odbc/system/tcp_socket_client.h" // Uncomment for per-byte debug. //#define PER_BYTE_DEBUG @@ -49,7 +53,6 @@ namespace ignite { Connection::Connection() : socket(), - connected(false), timeout(0), parser(), config(), @@ -122,21 +125,44 @@ namespace ignite SqlResult::Type Connection::InternalEstablish(const config::Configuration cfg) { + using ssl::SslMode; + config = cfg; - if (connected) + if (socket.get() != 0) { AddStatusRecord(SqlState::S08002_ALREADY_CONNECTED, "Already connected."); return SqlResult::AI_ERROR; } - connected = socket.Connect(cfg.GetHost().c_str(), cfg.GetTcpPort(), *this); + SslMode::T sslMode = SslMode::FromString(cfg.GetSslMode(), SslMode::DISABLE); + + if (sslMode != SslMode::DISABLE) + { + bool loaded = ssl::SslGateway::GetInstance().LoadAll(); + + if (!loaded) + { + AddStatusRecord(SqlState::SHY000_GENERAL_ERROR, + "Can not load OpenSSL library (did you set OPENSSL_HOME environment variable?)."); + + return SqlResult::AI_ERROR; + } + + socket.reset(new ssl::SecureSocketClient(cfg.GetSslCertFile(), cfg.GetSslKeyFile(), cfg.GetSslCaFile())); + } + else + socket.reset(new system::TcpSocketClient()); + + bool connected = socket->Connect(cfg.GetHost().c_str(), cfg.GetTcpPort(), *this); if (!connected) { AddStatusRecord(SqlState::S08001_CANNOT_CONNECT, "Failed to establish connection with the host."); + Close(); + return SqlResult::AI_ERROR; } @@ -157,7 +183,7 @@ namespace ignite SqlResult::Type Connection::InternalRelease() { - if (!connected) + if (socket.get() == 0) { AddStatusRecord(SqlState::S08003_NOT_CONNECTED, "Connection is not open."); @@ -171,9 +197,12 @@ namespace ignite void Connection::Close() { - socket.Close(); + if (socket.get() != 0) + { + socket->Close(); - connected = false; + socket.reset(); + } } Statement* Connection::CreateStatement() @@ -201,7 +230,7 @@ namespace ignite bool Connection::Send(const int8_t* data, size_t len, int32_t timeout) { - if (!connected) + if (socket.get() == 0) throw OdbcError(SqlState::S08003_NOT_CONNECTED, "Connection is not established"); int32_t newLen = static_cast<int32_t>(len + sizeof(OdbcProtocolHeader)); @@ -235,11 +264,11 @@ namespace ignite while (sent != static_cast<int64_t>(len)) { - int res = socket.Send(data + sent, len - sent, timeout); + int res = socket->Send(data + sent, len - sent, timeout); LOG_MSG("Sent: " << res); - if (res < 0 || res == tcp::SocketClient::WaitResult::TIMEOUT) + if (res < 0 || res == SocketClient::WaitResult::TIMEOUT) { Close(); @@ -256,7 +285,7 @@ namespace ignite bool Connection::Receive(std::vector<int8_t>& msg, int32_t timeout) { - if (!connected) + if (socket.get() == 0) throw OdbcError(SqlState::S08003_NOT_CONNECTED, "Connection is not established"); msg.clear(); @@ -307,10 +336,10 @@ namespace ignite { size_t received = len - remain; - int res = socket.Receive(buffer + received, remain, timeout); + int res = socket->Receive(buffer + received, remain, timeout); LOG_MSG("Receive res: " << res << " remain: " << remain); - if (res < 0 || res == tcp::SocketClient::WaitResult::TIMEOUT) + if (res < 0 || res == SocketClient::WaitResult::TIMEOUT) { Close(); @@ -382,7 +411,7 @@ namespace ignite { SQLUINTEGER *val = reinterpret_cast<SQLUINTEGER*>(buf); - *val = connected ? SQL_CD_FALSE : SQL_CD_TRUE; + *val = socket.get() != 0 ? SQL_CD_FALSE : SQL_CD_TRUE; if (valueLen) *valueLen = SQL_IS_INTEGER; @@ -441,7 +470,7 @@ namespace ignite { SQLUINTEGER uTimeout = static_cast<SQLUINTEGER>(reinterpret_cast<ptrdiff_t>(value)); - if (uTimeout != 0 && connected && socket.IsBlocking()) + if (uTimeout != 0 && socket.get() != 0 && socket->IsBlocking()) { timeout = 0; @@ -524,12 +553,13 @@ namespace ignite try { // Workaround for some Linux systems that report connection on non-blocking - // sockets as successfull but fail to establish real connection. - bool sent = SyncMessage(req, rsp, tcp::SocketClient::CONNECT_TIMEOUT); + // sockets as successful but fail to establish real connection. + bool sent = SyncMessage(req, rsp, SocketClient::CONNECT_TIMEOUT); if (!sent) { - AddStatusRecord(SqlState::S08001_CANNOT_CONNECT, "Failed to establish connection with the host."); + AddStatusRecord(SqlState::S08001_CANNOT_CONNECT, + "Failed to get handshake response (Did you forget to enable SSL?)."); return SqlResult::AI_ERROR; } @@ -549,7 +579,7 @@ namespace ignite if (!rsp.IsAccepted()) { - LOG_MSG("Hanshake message has been rejected."); + LOG_MSG("Handshake message has been rejected."); std::stringstream constructor; http://git-wip-us.apache.org/repos/asf/ignite/blob/394019ee/modules/platforms/cpp/odbc/src/dsn_config.cpp ---------------------------------------------------------------------- diff --git a/modules/platforms/cpp/odbc/src/dsn_config.cpp b/modules/platforms/cpp/odbc/src/dsn_config.cpp index 536f679..845c8bd 100644 --- a/modules/platforms/cpp/odbc/src/dsn_config.cpp +++ b/modules/platforms/cpp/odbc/src/dsn_config.cpp @@ -51,13 +51,13 @@ namespace ignite ThrowLastSetupError(); } - std::string ReadDsnString(const char* dsn, const std::string& key, const char* dflt) + std::string ReadDsnString(const char* dsn, const std::string& key, const std::string& dflt) { char buf[BUFFER_SIZE]; memset(buf, 0, sizeof(buf)); - SQLGetPrivateProfileString(dsn, key.c_str(), dflt, buf, sizeof(buf), CONFIG_FILE); + SQLGetPrivateProfileString(dsn, key.c_str(), dflt.c_str(), buf, sizeof(buf), CONFIG_FILE); return std::string(buf); } @@ -90,13 +90,13 @@ namespace ignite void ReadDsnConfiguration(const char* dsn, Configuration& config) { - std::string address = ReadDsnString(dsn, Configuration::Key::address, config.GetAddress().c_str()); + std::string address = ReadDsnString(dsn, Configuration::Key::address, config.GetAddress()); - std::string server = ReadDsnString(dsn, Configuration::Key::server, config.GetHost().c_str()); + std::string server = ReadDsnString(dsn, Configuration::Key::server, config.GetHost()); uint16_t port = ReadDsnInt(dsn, Configuration::Key::port, config.GetTcpPort()); - std::string schema = ReadDsnString(dsn, Configuration::Key::schema, config.GetSchema().c_str()); + std::string schema = ReadDsnString(dsn, Configuration::Key::schema, config.GetSchema()); bool distributedJoins = ReadDsnBool(dsn, Configuration::Key::distributedJoins, config.IsDistributedJoins()); @@ -112,13 +112,21 @@ namespace ignite ReadDsnBool(dsn, Configuration::Key::skipReducerOnUpdate, config.IsSkipReducerOnUpdate()); std::string version = ReadDsnString(dsn, Configuration::Key::protocolVersion, - config.GetProtocolVersion().ToString().c_str()); + config.GetProtocolVersion().ToString()); int32_t pageSize = ReadDsnInt(dsn, Configuration::Key::pageSize, config.GetPageSize()); if (pageSize <= 0) pageSize = config.GetPageSize(); + std::string sslMode = ReadDsnString(dsn, Configuration::Key::sslMode, config.GetSslMode()); + + std::string sslKeyFile = ReadDsnString(dsn, Configuration::Key::sslKeyFile, config.GetSslKeyFile()); + + std::string sslCertFile = ReadDsnString(dsn, Configuration::Key::sslCertFile, config.GetSslCertFile()); + + std::string sslCaFile = ReadDsnString(dsn, Configuration::Key::sslCaFile, config.GetSslCaFile()); + config.SetAddress(address); config.SetHost(server); config.SetTcpPort(port); @@ -131,6 +139,10 @@ namespace ignite config.SetSkipReducerOnUpdate(skipReducerOnUpdate); config.SetProtocolVersion(version); config.SetPageSize(pageSize); + config.SetSslMode(sslMode); + config.SetSslKeyFile(sslKeyFile); + config.SetSslCertFile(sslCertFile); + config.SetSslCaFile(sslCaFile); } } } \ No newline at end of file http://git-wip-us.apache.org/repos/asf/ignite/blob/394019ee/modules/platforms/cpp/odbc/src/odbc.cpp ---------------------------------------------------------------------- diff --git a/modules/platforms/cpp/odbc/src/odbc.cpp b/modules/platforms/cpp/odbc/src/odbc.cpp index 1480d0b..e4b47b9 100644 --- a/modules/platforms/cpp/odbc/src/odbc.cpp +++ b/modules/platforms/cpp/odbc/src/odbc.cpp @@ -180,7 +180,7 @@ namespace ignite { using odbc::Environment; - LOG_MSG("SQLFreeEnv called"); + LOG_MSG("SQLFreeEnv called: " << env); Environment *environment = reinterpret_cast<Environment*>(env); http://git-wip-us.apache.org/repos/asf/ignite/blob/394019ee/modules/platforms/cpp/odbc/src/ssl/secure_socket_client.cpp ---------------------------------------------------------------------- diff --git a/modules/platforms/cpp/odbc/src/ssl/secure_socket_client.cpp b/modules/platforms/cpp/odbc/src/ssl/secure_socket_client.cpp new file mode 100644 index 0000000..c305b87 --- /dev/null +++ b/modules/platforms/cpp/odbc/src/ssl/secure_socket_client.cpp @@ -0,0 +1,419 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <sstream> +#include <cstdio> + +#include "ignite/odbc/log.h" +#include "ignite/common/concurrent.h" +#include "ignite/odbc/system/tcp_socket_client.h" +#include "ignite/odbc/ssl/secure_socket_client.h" +#include "ignite/odbc/ssl/ssl_bindings.h" + +#ifndef SOCKET_ERROR +# define SOCKET_ERROR (-1) +#endif // SOCKET_ERROR + +namespace ignite +{ + namespace odbc + { + namespace ssl + { + SecureSocketClient::SecureSocketClient(const std::string& certPath, const std::string& keyPath, + const std::string& caPath): + certPath(certPath), + keyPath(keyPath), + caPath(caPath), + context(0), + sslBio(0), + blocking(true) + { + // No-op. + } + + SecureSocketClient::~SecureSocketClient() + { + CloseInteral(); + + if (context) + ssl::SSL_CTX_free(reinterpret_cast<SSL_CTX*>(context)); + } + + bool SecureSocketClient::Connect(const char* hostname, uint16_t port, diagnostic::Diagnosable& diag) + { + assert(SslGateway::GetInstance().Loaded()); + + if (!context) + { + context = MakeContext(certPath, keyPath, caPath, diag); + + if (!context) + { + diag.AddStatusRecord(SqlState::SHY000_GENERAL_ERROR, + "Can not create SSL context. Aborting connect."); + + return false; + } + } + + BIO* bio = ssl::BIO_new_ssl_connect(reinterpret_cast<SSL_CTX*>(context)); + if (!bio) + { + diag.AddStatusRecord(SqlState::SHY000_GENERAL_ERROR, "Can not create SSL connection."); + + return false; + } + + blocking = false; + long res = ssl::BIO_set_nbio_(bio, 1); + if (res != OPERATION_SUCCESS) + { + blocking = true; + + diag.AddStatusRecord(SqlState::S01S02_OPTION_VALUE_CHANGED, + "Can not set up non-blocking mode. Timeouts are not available."); + } + + std::stringstream stream; + stream << hostname << ":" << port; + + std::string address = stream.str(); + + res = ssl::BIO_set_conn_hostname_(bio, address.c_str()); + if (res != OPERATION_SUCCESS) + { + diag.AddStatusRecord(SqlState::SHY000_GENERAL_ERROR, "Can not set SSL connection hostname."); + + ssl::BIO_free_all(bio); + + return false; + } + + SSL* ssl = 0; + ssl::BIO_get_ssl_(bio, &ssl); + if (!ssl) + { + diag.AddStatusRecord(SqlState::SHY000_GENERAL_ERROR, "Can not get SSL instance from BIO."); + + ssl::BIO_free_all(bio); + + return false; + } + + res = ssl::SSL_set_tlsext_host_name_(ssl, hostname); + if (res != OPERATION_SUCCESS) + { + diag.AddStatusRecord(SqlState::SHY000_GENERAL_ERROR, "Can not set host name for secure connection"); + + ssl::BIO_free_all(bio); + + return false; + } + + do + { + res = ssl::BIO_do_connect_(bio); + } while (ssl::BIO_should_retry_(bio)); + + if (res != OPERATION_SUCCESS) + { + diag.AddStatusRecord(SqlState::S08001_CANNOT_CONNECT, + "Failed to establish secure connection with the host."); + + ssl::BIO_free_all(bio); + + return false; + } + + do + { + res = ssl::BIO_do_handshake_(bio); + } while (ssl::BIO_should_retry_(bio)); + + if (res != OPERATION_SUCCESS) + { + diag.AddStatusRecord(SqlState::S08001_CANNOT_CONNECT, "SSL handshake failed."); + + ssl::BIO_free_all(bio); + + return false; + } + + // Verify a server certificate was presented during the negotiation + X509* cert = ssl::SSL_get_peer_certificate(ssl); + if (cert) + ssl::X509_free(cert); + else + { + diag.AddStatusRecord(SqlState::SHY000_GENERAL_ERROR, "Remote host did not provide certificate."); + + ssl::BIO_free_all(bio); + + return false; + } + + // Verify the result of chain verification + // Verification performed according to RFC 4158 + res = ssl::SSL_get_verify_result(ssl); + if (X509_V_OK != res) + { + diag.AddStatusRecord(SqlState::SHY000_GENERAL_ERROR, "Certificate chain verification failed."); + + ssl::BIO_free_all(bio); + + return false; + } + + sslBio = reinterpret_cast<void*>(bio); + + return true; + } + + void SecureSocketClient::Close() + { + CloseInteral(); + } + + int SecureSocketClient::Send(const int8_t* data, size_t size, int32_t timeout) + { + assert(SslGateway::GetInstance().Loaded()); + + if (!sslBio) + { + LOG_MSG("Trying to send data using closed connection"); + + return -1; + } + + BIO* sslBio0 = reinterpret_cast<BIO*>(sslBio); + + int res = 0; + + do + { + res = ssl::BIO_write(sslBio0, data, static_cast<int>(size)); + } + while (ssl::BIO_should_retry_(sslBio0)); + + return res; + } + + int SecureSocketClient::Receive(int8_t* buffer, size_t size, int32_t timeout) + { + assert(SslGateway::GetInstance().Loaded()); + + if (!sslBio) + { + LOG_MSG("Trying to receive data using closed connection"); + + return -1; + } + + BIO* sslBio0 = reinterpret_cast<BIO*>(sslBio); + + int res = 0; + + if (!blocking && BIO_pending_(sslBio0) == 0) + { + res = WaitOnSocket(timeout, true); + + if (res < 0 || res == WaitResult::TIMEOUT) + return res; + } + + do + { + res = ssl::BIO_read(sslBio0, buffer, static_cast<int>(size)); + } + while (ssl::BIO_should_retry_(sslBio0)); + + return res; + } + + bool SecureSocketClient::IsBlocking() const + { + return blocking; + } + + void* SecureSocketClient::MakeContext(const std::string& certPath, const std::string& keyPath, + const std::string& caPath, diagnostic::Diagnosable& diag) + { + assert(SslGateway::GetInstance().Loaded()); + + static bool sslLibInited = false; + static common::concurrent::CriticalSection sslCs; + + if (!sslLibInited) + { + common::concurrent::CsLockGuard lock(sslCs); + + if (!sslLibInited) + { + LOG_MSG("Initializing SSL library"); + + (void)SSL_library_init(); + + SSL_load_error_strings(); + + OPENSSL_config(0); + + sslLibInited = true; + } + } + + const SSL_METHOD* method = SSLv23_method(); + if (!method) + { + diag.AddStatusRecord(SqlState::SHY000_GENERAL_ERROR, "Can not create new SSL method."); + + return 0; + } + + SSL_CTX* ctx = ssl::SSL_CTX_new(method); + if (!ctx) + { + diag.AddStatusRecord(SqlState::SHY000_GENERAL_ERROR, "Can not create new SSL context."); + + return 0; + } + + ssl::SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER, 0); + + ssl::SSL_CTX_set_verify_depth(ctx, 8); + + const long flags = SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3 | SSL_OP_NO_COMPRESSION; + ssl::SSL_CTX_ctrl(ctx, SSL_CTRL_OPTIONS, flags, NULL); + + const char* cCaPath = caPath.empty() ? 0 : caPath.c_str(); + + long res = ssl::SSL_CTX_load_verify_locations(ctx, cCaPath, 0); + if (res != OPERATION_SUCCESS) + { + diag.AddStatusRecord(SqlState::SHY000_GENERAL_ERROR, + "Can not set Certificate Authority path for secure connection."); + + ssl::SSL_CTX_free(ctx); + + return 0; + } + + res = ssl::SSL_CTX_use_certificate_chain_file(ctx, certPath.c_str()); + if (res != OPERATION_SUCCESS) + { + diag.AddStatusRecord(SqlState::SHY000_GENERAL_ERROR, + "Can not set client certificate file for secure connection."); + + ssl::SSL_CTX_free(ctx); + + return 0; + } + + res = ssl::SSL_CTX_use_RSAPrivateKey_file(ctx, keyPath.c_str(), SSL_FILETYPE_PEM); + if (res != OPERATION_SUCCESS) + { + diag.AddStatusRecord(SqlState::SHY000_GENERAL_ERROR, + "Can not set private key file for secure connection."); + + ssl::SSL_CTX_free(ctx); + + return 0; + } + + const char* const PREFERRED_CIPHERS = "HIGH:!aNULL:!kRSA:!PSK:!SRP:!MD5:!RC4"; + res = ssl::SSL_CTX_set_cipher_list(ctx, PREFERRED_CIPHERS); + if (res != OPERATION_SUCCESS) + { + diag.AddStatusRecord(SqlState::SHY000_GENERAL_ERROR, + "Can not set ciphers list for secure connection."); + + ssl::SSL_CTX_free(ctx); + + return 0; + } + + return ctx; + } + + void SecureSocketClient::CloseInteral() + { + assert(SslGateway::GetInstance().Loaded()); + + if (sslBio) + { + ssl::BIO_free_all(reinterpret_cast<BIO*>(sslBio)); + + sslBio = 0; + } + } + + int SecureSocketClient::WaitOnSocket(int32_t timeout, bool rd) + { + int ready = 0; + int lastError = 0; + int fdSocket = 0; + BIO* sslBio0 = reinterpret_cast<BIO*>(sslBio); + + fd_set fds; + + long res = ssl::BIO_get_fd_(sslBio0, &fdSocket); + + if (res < 0) + { + LOG_MSG("Can not get file descriptor from the SSL socket: " << res); + + return res; + } + + do { + struct timeval tv = { 0 }; + tv.tv_sec = timeout; + + FD_ZERO(&fds); + FD_SET(static_cast<long>(fdSocket), &fds); + + fd_set* readFds = 0; + fd_set* writeFds = 0; + + if (rd) + readFds = &fds; + else + writeFds = &fds; + + ready = select(fdSocket + 1, readFds, writeFds, NULL, (timeout == 0 ? NULL : &tv)); + + if (ready == SOCKET_ERROR) + lastError = system::TcpSocketClient::GetLastSocketError(); + + } while (ready == SOCKET_ERROR && system::TcpSocketClient::IsSocketOperationInterrupted(lastError)); + + if (ready == SOCKET_ERROR) + return -lastError; + + lastError = system::TcpSocketClient::GetLastSocketError(fdSocket); + + if (lastError != 0) + return -lastError; + + if (ready == 0) + return WaitResult::TIMEOUT; + + return WaitResult::SUCCESS; + } + } + } +} http://git-wip-us.apache.org/repos/asf/ignite/blob/394019ee/modules/platforms/cpp/odbc/src/ssl/ssl_gateway.cpp ---------------------------------------------------------------------- diff --git a/modules/platforms/cpp/odbc/src/ssl/ssl_gateway.cpp b/modules/platforms/cpp/odbc/src/ssl/ssl_gateway.cpp new file mode 100644 index 0000000..c91d44e --- /dev/null +++ b/modules/platforms/cpp/odbc/src/ssl/ssl_gateway.cpp @@ -0,0 +1,210 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <sstream> + +#include <openssl/ssl.h> +#include <openssl/conf.h> + +#include "ignite/common/utils.h" + +#include "ignite/odbc/ssl/ssl_gateway.h" +#include "ignite/odbc/log.h" + +namespace ignite +{ + namespace odbc + { + namespace ssl + { + SslGateway::SslGateway() : + inited(false), + functions() + { + // No-op. + } + + SslGateway::~SslGateway() + { + // No-op. + } + + common::dynamic::Module SslGateway::LoadSslLibrary(const char* name) + { + using namespace common; + using namespace dynamic; + + std::string fullName = GetDynamicLibraryName(name); + + Module libModule = LoadModule(fullName); + + if (libModule.IsLoaded()) + return libModule; + + std::string home = GetEnv("OPEN_SSL_HOME"); + + if (home.empty()) + home = GetEnv("OPENSSL_HOME"); + + if (home.empty()) + return libModule; + + std::stringstream constructor; + + constructor << home << Fs << "bin" << Fs << fullName; + + std::string fullPath = constructor.str(); + + return LoadModule(fullPath); + } + + bool SslGateway::LoadSslLibraries() + { + libeay32 = LoadSslLibrary("libeay32"); + ssleay32 = LoadSslLibrary("ssleay32"); + libssl = LoadSslLibrary("libssl"); + + if (!libssl.IsLoaded() && (!libeay32.IsLoaded() || !ssleay32.IsLoaded())) + { + if (!libeay32.IsLoaded()) + LOG_MSG("Can not load libeay32."); + + if (!ssleay32.IsLoaded()) + LOG_MSG("Can not load ssleay32."); + + if (!libssl.IsLoaded()) + LOG_MSG("Can not load libssl."); + + libeay32.Unload(); + ssleay32.Unload(); + libssl.Unload(); + + return false; + } + + return true; + } + + SslGateway& SslGateway::GetInstance() + { + static SslGateway self; + + return self; + } + + bool SslGateway::LoadAll() + { + using namespace common::dynamic; + + if (inited) + return true; + + common::concurrent::CsLockGuard lock(initCs); + + if (inited) + return true; + + if (!LoadSslLibraries()) + { + LOG_MSG("Can not load neccessary OpenSSL libraries."); + + return false; + } + + functions.fpSSL_CTX_new = LoadSslMethod("SSL_CTX_new"); + functions.fpSSL_CTX_free = LoadSslMethod("SSL_CTX_free"); + functions.fpSSL_CTX_set_verify = LoadSslMethod("SSL_CTX_set_verify"); + functions.fpSSL_CTX_set_verify_depth = LoadSslMethod("SSL_CTX_set_verify_depth"); + functions.fpSSL_CTX_load_verify_locations = LoadSslMethod("SSL_CTX_load_verify_locations"); + functions.fpSSL_CTX_use_certificate_chain_file = LoadSslMethod("SSL_CTX_use_certificate_chain_file"); + functions.fpSSL_CTX_use_RSAPrivateKey_file = LoadSslMethod("SSL_CTX_use_RSAPrivateKey_file"); + functions.fpSSL_CTX_set_cipher_list = LoadSslMethod("SSL_CTX_set_cipher_list"); + + functions.fpSSL_get_verify_result = LoadSslMethod("SSL_get_verify_result"); + functions.fpSSL_library_init = LoadSslMethod("SSL_library_init"); + functions.fpSSL_load_error_strings = LoadSslMethod("SSL_load_error_strings"); + functions.fpSSL_get_peer_certificate = LoadSslMethod("SSL_get_peer_certificate"); + functions.fpSSL_ctrl = LoadSslMethod("SSL_ctrl"); + functions.fpSSL_CTX_ctrl = LoadSslMethod("SSL_CTX_ctrl"); + + functions.fpSSLv23_method = LoadSslMethod("SSLv23_method"); + functions.fpBIO_new_ssl_connect = LoadSslMethod("BIO_new_ssl_connect"); + + functions.fpOPENSSL_config = LoadSslMethod("OPENSSL_config"); + functions.fpX509_free = LoadSslMethod("X509_free"); + + functions.fpBIO_write = LoadSslMethod("BIO_write"); + functions.fpBIO_read = LoadSslMethod("BIO_read"); + functions.fpBIO_free_all = LoadSslMethod("BIO_free_all"); + functions.fpBIO_test_flags = LoadSslMethod("BIO_test_flags"); + functions.fpBIO_ctrl = LoadSslMethod("BIO_ctrl"); + + bool allLoaded = + functions.fpSSL_CTX_new != 0 && + functions.fpSSL_CTX_free != 0 && + functions.fpSSL_CTX_set_verify != 0 && + functions.fpSSL_CTX_set_verify_depth != 0 && + functions.fpSSL_CTX_load_verify_locations != 0 && + functions.fpSSL_CTX_use_certificate_chain_file != 0 && + functions.fpSSL_CTX_use_RSAPrivateKey_file != 0 && + functions.fpSSL_CTX_set_cipher_list != 0 && + functions.fpSSL_get_verify_result != 0 && + functions.fpSSL_library_init != 0 && + functions.fpSSL_load_error_strings != 0 && + functions.fpSSL_get_peer_certificate != 0 && + functions.fpSSL_ctrl != 0 && + functions.fpSSL_CTX_ctrl != 0 && + functions.fpSSLv23_method != 0 && + functions.fpBIO_new_ssl_connect != 0 && + functions.fpOPENSSL_config != 0 && + functions.fpX509_free != 0 && + functions.fpBIO_write != 0 && + functions.fpBIO_read != 0 && + functions.fpBIO_free_all != 0 && + functions.fpBIO_test_flags != 0 && + functions.fpBIO_ctrl != 0; + + if (!allLoaded) + { + libeay32.Unload(); + ssleay32.Unload(); + libssl.Unload(); + } + + inited = allLoaded; + + return inited; + } + + void* SslGateway::LoadSslMethod(const char* name) + { + void* fp = libeay32.FindSymbol(name); + + if (!fp) + fp = ssleay32.FindSymbol(name); + + if (!fp) + fp = libssl.FindSymbol(name); + + if (!fp) + LOG_MSG("Can not load function " << name); + + return fp; + } + } + } +} http://git-wip-us.apache.org/repos/asf/ignite/blob/394019ee/modules/platforms/cpp/odbc/src/ssl/ssl_mode.cpp ---------------------------------------------------------------------- diff --git a/modules/platforms/cpp/odbc/src/ssl/ssl_mode.cpp b/modules/platforms/cpp/odbc/src/ssl/ssl_mode.cpp new file mode 100644 index 0000000..0bdbc60 --- /dev/null +++ b/modules/platforms/cpp/odbc/src/ssl/ssl_mode.cpp @@ -0,0 +1,43 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "ignite/common/utils.h" +#include "ignite/odbc/ssl/ssl_mode.h" + +namespace ignite +{ + namespace odbc + { + namespace ssl + { + SslMode::T SslMode::FromString(const std::string& val, T dflt) + { + std::string lowerVal = common::ToLower(val); + + common::StripSurroundingWhitespaces(lowerVal); + + if (lowerVal == "disable") + return SslMode::DISABLE; + + if (lowerVal == "require") + return SslMode::REQUIRE; + + return dflt; + } + } + } +}
