Merge remote-tracking branch 'origin/develop' into MXS-122

Conflicts:
	server/core/CMakeLists.txt
	server/core/dcb.c
	server/include/dcb.h
	server/include/server.h
	server/modules/protocol/mysql_backend.c
This commit is contained in:
Martin Brampton
2015-06-19 23:12:54 +01:00
112 changed files with 3003 additions and 1188 deletions

View File

@ -61,12 +61,17 @@
#include <sys/types.h>
#include <housekeeper.h>
#include <resultset.h>
#include <gw.h>
#include <gwdirs.h>
/** Defined in log_manager.cc */
extern int lm_enabled_logfiles_bitmask;
extern size_t log_ses_count[];
extern __thread log_info_t tls_log_info;
static RSA *rsa_512 = NULL;
static RSA *rsa_1024 = NULL;
/** To be used with configuration type checks */
typedef struct typelib_st {
int tl_nelems;
@ -112,7 +117,7 @@ SERVICE *service;
return NULL;
if ((service->router = load_module(router, MODULE_ROUTER)) == NULL)
{
char* home = get_maxscale_home();
char* home = get_libdir();
char* ldpath = getenv("LD_LIBRARY_PATH");
LOGIF(LE, (skygw_log_write_flush(
@ -120,12 +125,13 @@ SERVICE *service;
"Error : Unable to load %s module \"%s\".\n\t\t\t"
" Ensure that lib%s.so exists in one of the "
"following directories :\n\t\t\t "
"- %s/modules\n\t\t\t - %s",
"- %s/modules\n%s%s",
MODULE_ROUTER,
router,
router,
home,
ldpath)));
ldpath?"\t\t\t - ":"",
ldpath?ldpath:"")));
free(service);
return NULL;
}
@ -133,7 +139,14 @@ SERVICE *service;
service->routerModule = strdup(router);
service->users_from_all = false;
service->resources = NULL;
service->ssl_mode = SSL_DISABLED;
service->ssl_init_done = false;
service->ssl_ca_cert = NULL;
service->ssl_cert = NULL;
service->ssl_key = NULL;
service->ssl_cert_verify_depth = DEFAULT_SSL_CERT_VERIFY_DEPTH;
/** Support the highest possible SSL/TLS methods available as the default */
service->ssl_method_type = SERVICE_SSL_TLS_MAX;
if (service->name == NULL || service->routerModule == NULL)
{
if (service->name)
@ -229,11 +242,7 @@ GWPROTOCOL *funcs;
{
/* Try loading authentication data from file cache */
char *ptr, path[4097];
strcpy(path, "/usr/local/mariadb-maxscale");
if ((ptr = getenv("MAXSCALE_HOME")) != NULL)
{
strncpy(path, ptr, 4096);
}
strcpy(path, get_cachedir());
strncat(path, "/", 4096);
strncat(path, service->name, 4096);
strncat(path, "/.cache/dbusers", 4096);
@ -257,15 +266,11 @@ GWPROTOCOL *funcs;
else
{
/* Save authentication data to file cache */
char *ptr, path[4097];
char *ptr, path[PATH_MAX + 1];
int mkdir_rval = 0;
strcpy(path, "/usr/local/mariadb-maxscale");
if ((ptr = getenv("MAXSCALE_HOME")) != NULL)
{
strncpy(path, ptr, 4096);
}
strcpy(path, get_cachedir());
strncat(path, "/", 4096);
strncat(path, service->name, 4096);
strncat(path, service->name, PATH_MAX);
if (access(path, R_OK) == -1)
{
mkdir_rval = mkdir(path, 0777);
@ -280,7 +285,7 @@ GWPROTOCOL *funcs;
mkdir_rval = 0;
}
strncat(path, "/.cache", 4096);
strncat(path, "/.cache", PATH_MAX);
if (access(path, R_OK) == -1)
{
mkdir_rval = mkdir(path, 0777);
@ -294,7 +299,7 @@ GWPROTOCOL *funcs;
strerror(errno));
mkdir_rval = 0;
}
strncat(path, "/dbusers", 4096);
strncat(path, "/dbusers", PATH_MAX);
dbusers_save(service->users, path);
}
if (loaded == 0)
@ -417,6 +422,17 @@ serviceStart(SERVICE *service)
SERV_PROTOCOL *port;
int listeners = 0;
if(service->ssl_mode != SSL_DISABLED)
{
if(serviceInitSSL(service) != 0)
{
LOGIF(LE, (skygw_log_write_flush(LOGFILE_ERROR,
"%s: SSL initialization failed. Service not started.",
service->name)));
service->state = SERVICE_STATE_FAILED;
return 0;
}
}
if ((service->router_instance = service->router->createInstance(service,
service->routerOptions)) == NULL)
{
@ -860,6 +876,97 @@ serviceOptimizeWildcard(SERVICE *service, int action)
return 1;
}
/**
* Set the locations of the server's SSL certificate, server's private key and the CA
* certificate which both the client and the server should trust.
* @param service Service to configure
* @param cert SSL certificate
* @param key SSL private key
* @param ca_cert SSL CA certificate
*/
void
serviceSetCertificates(SERVICE *service, char* cert,char* key, char* ca_cert)
{
if(service->ssl_cert)
free(service->ssl_cert);
service->ssl_cert = strdup(cert);
if(service->ssl_key)
free(service->ssl_key);
service->ssl_key = strdup(key);
if(service->ssl_ca_cert)
free(service->ssl_ca_cert);
service->ssl_ca_cert = strdup(ca_cert);
}
/**
* Set the maximum SSL/TLS version the service will support
* @param service Service to configure
* @param version SSL/TLS version string
* @return 0 on success, -1 on invalid version string
*/
int
serviceSetSSLVersion(SERVICE *service, char* version)
{
if(strcasecmp(version,"SSLV3") == 0)
service->ssl_method_type = SERVICE_SSLV3;
else if(strcasecmp(version,"TLSV10") == 0)
service->ssl_method_type = SERVICE_TLS10;
else if(strcasecmp(version,"TLSV11") == 0)
service->ssl_method_type = SERVICE_TLS11;
else if(strcasecmp(version,"TLSV12") == 0)
service->ssl_method_type = SERVICE_TLS12;
else if(strcasecmp(version,"MAX") == 0)
service->ssl_method_type = SERVICE_SSL_TLS_MAX;
else return -1;
return 0;
}
/**
* Set the service's SSL certificate verification depth. Depth of 0 means the peer
* certificate, 1 is the CA and 2 is a higher CA and so on.
* @param service Service to configure
* @param depth Certificate verification depth
* @return 0 on success, -1 on incorrect depth value
*/
int serviceSetSSLVerifyDepth(SERVICE* service, int depth)
{
if(depth < 0)
return -1;
service->ssl_cert_verify_depth = depth;
return 0;
}
/**
* Enable or disable the service SSL capability of a service.
* The SSL mode string passed as a parameter should be one of required, enabled
* or disabled. Required requires all connections to use SSL encryption, enabled
* allows both SSL and non-SSL connections and disabled does not use SSL encryption.
* If the service SSL mode is set to enabled, then the client will decide whether
* SSL encryption is used.
* @param service Service to configure
* @param action Mode string. One of required, enabled or disabled.
* @return 0 on success, -1 on error
*/
int
serviceSetSSL(SERVICE *service, char* action)
{
int rval = 0;
if(strcasecmp(action,"required") == 0)
service->ssl_mode = SSL_REQUIRED;
else if(strcasecmp(action,"enabled") == 0)
service->ssl_mode = SSL_ENABLED;
else if(strcasecmp(action,"disabled") == 0)
service->ssl_mode = SSL_DISABLED;
else
rval = -1;
return rval;
}
/**
* Whether to strip escape characters from the name of the database the client
* is connecting to.
@ -1023,6 +1130,8 @@ int i;
printf("\tUsers data: %p\n", (void *)service->users);
printf("\tTotal connections: %d\n", service->stats.n_sessions);
printf("\tCurrently connected: %d\n", service->stats.n_current);
printf("\tSSL: %s\n", service->ssl_mode == SSL_DISABLED ? "Disabled":
(service->ssl_mode == SSL_ENABLED ? "Enabled":"Required"));
}
/**
@ -1132,6 +1241,8 @@ int i;
service->stats.n_sessions);
dcb_printf(dcb, "\tCurrently connected: %d\n",
service->stats.n_current);
dcb_printf(dcb,"\tSSL: %s\n", service->ssl_mode == SSL_DISABLED ? "Disabled":
(service->ssl_mode == SSL_ENABLED ? "Enabled":"Required"));
}
/**
@ -1260,7 +1371,14 @@ void *router_obj;
}
}
/**
* Refresh the database users for the service
* This function replaces the MySQL users used by the service with the latest
* version found on the backend servers. There is a limit on how often the users
* can be reloaded and if this limit is exceeded, the reload will fail.
* @param service Service to reload
* @return 0 on success and 1 on error
*/
int service_refresh_users(SERVICE *service) {
int ret = 1;
/* check for another running getUsers request */
@ -1780,3 +1898,139 @@ int *data;
return set;
}
/**
* The RSA ket generation callback function for OpenSSL.
* @param s SSL structure
* @param is_export Not used
* @param keylength Length of the key
* @return Pointer to RSA structure
*/
RSA *tmp_rsa_callback(SSL *s, int is_export, int keylength)
{
RSA *rsa_tmp=NULL;
switch (keylength) {
case 512:
if (rsa_512)
rsa_tmp = rsa_512;
else { /* generate on the fly, should not happen in this example */
rsa_tmp = RSA_generate_key(keylength,RSA_F4,NULL,NULL);
rsa_512 = rsa_tmp; /* Remember for later reuse */
}
break;
case 1024:
if (rsa_1024)
rsa_tmp=rsa_1024;
break;
default:
/* Generating a key on the fly is very costly, so use what is there */
if (rsa_1024)
rsa_tmp=rsa_1024;
else
rsa_tmp=rsa_512; /* Use at least a shorter key */
}
return(rsa_tmp);
}
/**
* Initialize the servce's SSL context. This sets up the generated RSA
* encryption keys, chooses the server encryption level and configures the server
* certificate, private key and certificate authority file.
* @param service
* @return
*/
int serviceInitSSL(SERVICE* service)
{
DH* dh;
RSA* rsa;
if(!service->ssl_init_done)
{
switch(service->ssl_method_type)
{
case SERVICE_SSLV3:
service->method = (SSL_METHOD*)SSLv3_server_method();
break;
case SERVICE_TLS10:
service->method = (SSL_METHOD*)TLSv1_server_method();
break;
case SERVICE_TLS11:
service->method = (SSL_METHOD*)TLSv1_1_server_method();
break;
case SERVICE_TLS12:
service->method = (SSL_METHOD*)TLSv1_2_server_method();
break;
/** Rest of these use the maximum available SSL/TLS methods */
case SERVICE_SSL_MAX:
service->method = (SSL_METHOD*)SSLv23_server_method();
break;
case SERVICE_TLS_MAX:
service->method = (SSL_METHOD*)SSLv23_server_method();
break;
case SERVICE_SSL_TLS_MAX:
service->method = (SSL_METHOD*)SSLv23_server_method();
break;
default:
service->method = (SSL_METHOD*)SSLv23_server_method();
break;
}
service->ctx = SSL_CTX_new(service->method);
/** Enable all OpenSSL bug fixes */
SSL_CTX_set_options(service->ctx,SSL_OP_ALL);
/** Generate the 512-bit and 1024-bit RSA keys */
if(rsa_512 == NULL)
{
rsa_512 = RSA_generate_key(512,RSA_F4,NULL,NULL);
if (rsa_512 == NULL)
skygw_log_write(LE,"Error: 512-bit RSA key generation failed.");
}
if(rsa_1024 == NULL)
{
rsa_1024 = RSA_generate_key(1024,RSA_F4,NULL,NULL);
if (rsa_1024 == NULL)
skygw_log_write(LE,"Error: 1024-bit RSA key generation failed.");
}
if(rsa_512 != NULL && rsa_1024 != NULL)
SSL_CTX_set_tmp_rsa_callback(service->ctx,tmp_rsa_callback);
/** Load the server sertificate */
if (SSL_CTX_use_certificate_file(service->ctx, service->ssl_cert, SSL_FILETYPE_PEM) <= 0) {
skygw_log_write(LE,"Error: Failed to set server SSL certificate.");
return -1;
}
/* Load the private-key corresponding to the server certificate */
if (SSL_CTX_use_PrivateKey_file(service->ctx, service->ssl_key, SSL_FILETYPE_PEM) <= 0) {
skygw_log_write(LE,"Error: Failed to set server SSL key.");
return -1;
}
/* Check if the server certificate and private-key matches */
if (!SSL_CTX_check_private_key(service->ctx)) {
skygw_log_write(LE,"Error: Server SSL certificate and key do not match.");
return -1;
}
/* Load the RSA CA certificate into the SSL_CTX structure */
if (!SSL_CTX_load_verify_locations(service->ctx, service->ssl_ca_cert, NULL)) {
skygw_log_write(LE,"Error: Failed to set Certificate Authority file.");
return -1;
}
/* Set to require peer (client) certificate verification */
SSL_CTX_set_verify(service->ctx,SSL_VERIFY_PEER,NULL);
/* Set the verification depth */
SSL_CTX_set_verify_depth(service->ctx,service->ssl_cert_verify_depth);
service->ssl_init_done = true;
}
return 0;
}