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

@ -1,20 +1,18 @@
add_library(atomic atomic.c)
if(BUILD_TESTS OR BUILD_TOOLS)
add_library(fullcore STATIC adminusers.c config.c buffer.c dbusers.c dcb.c filter.c gwbitmask.c gw_utils.c hashtable.c hint.c housekeeper.c load_utils.c memlog.c modutil.c monitor.c poll.c resultset.c secrets.c server.c service.c session.c spinlock.c thread.c users.c utils.c externcmd.c)
add_library(fullcore STATIC adminusers.c atomic.c config.c buffer.c dbusers.c dcb.c filter.c gwbitmask.c gw_utils.c hashtable.c hint.c housekeeper.c load_utils.c memlog.c modutil.c monitor.c poll.c resultset.c secrets.c server.c service.c session.c spinlock.c thread.c users.c utils.c gwdirs.c externcmd.c)
if(WITH_JEMALLOC)
target_link_libraries(fullcore ${JEMALLOC_LIBRARIES})
elseif(WITH_TCMALLOC)
target_link_libraries(fullcore ${TCMALLOC_LIBRARIES})
endif()
target_link_libraries(fullcore ${CURL_LIBRARIES} utils log_manager pthread ${EMBEDDED_LIB} ${PCRE_LINK_FLAGS} ssl aio rt crypt dl crypto inih z m stdc++ atomic)
target_link_libraries(fullcore ${CURL_LIBRARIES} utils log_manager pthread ${EMBEDDED_LIB} ${PCRE_LINK_FLAGS} ssl aio rt crypt dl crypto inih z m stdc++)
endif()
add_executable(maxscale buffer.c spinlock.c gateway.c
add_executable(maxscale atomic.c buffer.c spinlock.c gateway.c
gw_utils.c utils.c dcb.c load_utils.c session.c service.c server.c
poll.c config.c users.c hashtable.c dbusers.c thread.c gwbitmask.c
monitor.c adminusers.c secrets.c filter.c modutil.c hint.c
housekeeper.c memlog.c resultset.c externcmd.c)
housekeeper.c memlog.c resultset.c gwdirs.c externcmd.c)
if(WITH_JEMALLOC)
target_link_libraries(maxscale ${JEMALLOC_LIBRARIES})
@ -22,16 +20,16 @@ elseif(WITH_TCMALLOC)
target_link_libraries(maxscale ${TCMALLOC_LIBRARIES})
endif()
target_link_libraries(maxscale ${EMBEDDED_LIB} ${PCRE_LINK_FLAGS} ${CURL_LIBRARIES} log_manager utils ssl aio pthread crypt dl crypto inih z rt m stdc++ atomic)
install(TARGETS maxscale DESTINATION bin)
target_link_libraries(maxscale ${EMBEDDED_LIB} ${PCRE_LINK_FLAGS} ${CURL_LIBRARIES} log_manager utils ssl aio pthread crypt dl crypto inih z rt m stdc++)
install(TARGETS maxscale DESTINATION ${MAXSCALE_BINDIR})
add_executable(maxkeys maxkeys.c secrets.c utils.c)
add_executable(maxkeys maxkeys.c secrets.c utils.c gwdirs.c)
target_link_libraries(maxkeys log_manager utils pthread crypt crypto)
install(TARGETS maxkeys DESTINATION bin)
install(TARGETS maxkeys DESTINATION ${MAXSCALE_BINDIR})
add_executable(maxpasswd maxpasswd.c secrets.c utils.c)
add_executable(maxpasswd maxpasswd.c secrets.c utils.c gwdirs.c)
target_link_libraries(maxpasswd log_manager utils pthread crypt crypto)
install(TARGETS maxpasswd DESTINATION bin)
install(TARGETS maxpasswd DESTINATION ${MAXSCALE_BINDIR})
if(BUILD_TESTS)
add_subdirectory(test)

View File

@ -26,6 +26,7 @@
#include <adminusers.h>
#include <skygw_utils.h>
#include <log_manager.h>
#include <gwdirs.h>
/** Defined in log_manager.cc */
extern int lm_enabled_logfiles_bitmask;
@ -119,12 +120,7 @@ char fname[1024], *home;
char uname[80], passwd[80];
initialise();
if ((home = getenv("MAXSCALE_HOME")) != NULL && strlen(home) < 1024){
sprintf(fname, "%s/etc/passwd", home);
}
else{
sprintf(fname, "/usr/local/mariadb-maxscale/etc/passwd");
}
sprintf(fname, "%s/passwd", get_datadir());
if ((fp = fopen(fname, "r")) == NULL)
return NULL;
if ((rval = users_alloc()) == NULL)
@ -155,12 +151,7 @@ FILE *fp;
char fname[1024], *home, *cpasswd;
initialise();
if ((home = getenv("MAXSCALE_HOME")) != NULL && strlen(home) < 1024){
sprintf(fname, "%s/etc/passwd", home);
}
else{
sprintf(fname, "/usr/local/mariadb-maxscale/etc/passwd");
}
sprintf(fname, "%s/passwd", get_datadir());
if (users == NULL)
{
@ -253,15 +244,8 @@ char* admin_remove_user(
/**
* Open passwd file and remove user from the file.
*/
if ((home = getenv("MAXSCALE_HOME")) != NULL &&
strnlen(home,PATH_MAX) < PATH_MAX &&
strnlen(home,PATH_MAX) > 0) {
sprintf(fname, "%s/etc/passwd", home);
sprintf(fname_tmp, "%s/etc/passwd_tmp", home);
} else {
sprintf(fname, "/usr/local/mariadb-maxscale/etc/passwd");
sprintf(fname_tmp, "/usr/local/mariadb-maxscale/etc/passwd_tmp");
}
sprintf(fname, "%s/passwd", get_datadir());
sprintf(fname_tmp, "%s/passwd_tmp", get_datadir());
/**
* Rewrite passwd file from memory.
*/

View File

@ -232,7 +232,7 @@ int rval;
strcpy(version_string,tmp);
}
ptr = strstr(tmp, "-embedded");
ptr = strstr(version_string, "-embedded");
if (ptr) {
*ptr = '\0';
}
@ -346,6 +346,8 @@ hashtable_memory_fns(monitorhash,strdup,NULL,free,NULL);
char *weightby;
char *version_string;
char *subservices;
char *ssl,*ssl_cert,*ssl_key,*ssl_ca_cert,*ssl_version;
char* ssl_cert_verify_depth;
bool is_rwsplit = false;
bool is_schemarouter = false;
char *allow_localhost_match_wildcard_host;
@ -354,6 +356,12 @@ hashtable_memory_fns(monitorhash,strdup,NULL,free,NULL);
user = config_get_value(obj->parameters, "user");
auth = config_get_value(obj->parameters, "passwd");
subservices = config_get_value(obj->parameters, "subservices");
ssl = config_get_value(obj->parameters, "ssl");
ssl_cert = config_get_value(obj->parameters, "ssl_cert");
ssl_key = config_get_value(obj->parameters, "ssl_key");
ssl_ca_cert = config_get_value(obj->parameters, "ssl_ca_cert");
ssl_version = config_get_value(obj->parameters, "ssl_version");
ssl_cert_verify_depth = config_get_value(obj->parameters, "ssl_cert_verify_depth");
enable_root_user = config_get_value(
obj->parameters,
"enable_root_user");
@ -418,7 +426,21 @@ hashtable_memory_fns(monitorhash,strdup,NULL,free,NULL);
}
if (version_string) {
/** Add the 5.5.5- string to the start of the version string if
* the version string starts with "10.".
* This mimics MariaDB 10.0 behavior which adds 5.5.5- for backwards compatibility. */
if(strncmp(version_string,"10.",3) == 0)
{
((SERVICE *)(obj->element))->version_string = malloc((strlen(version_string) +
strlen("5.5.5-") + 1) * sizeof(char));
strcpy(((SERVICE *)(obj->element))->version_string,"5.5.5-");
strcat(((SERVICE *)(obj->element))->version_string,version_string);
}
else
{
((SERVICE *)(obj->element))->version_string = strdup(version_string);
}
} else {
if (gateway.version_string)
((SERVICE *)(obj->element))->version_string = strdup(gateway.version_string);
@ -430,7 +452,84 @@ hashtable_memory_fns(monitorhash,strdup,NULL,free,NULL);
max_slave_rlag_str =
config_get_value(obj->parameters,
"max_slave_replication_lag");
if(ssl)
{
if(ssl_cert == NULL)
{
error_count++;
skygw_log_write(LE,"Error: Server certificate missing for service '%s'."
"Please provide the path to the server certificate by adding the ssl_cert=<path> parameter",
obj->object);
}
if(ssl_ca_cert == NULL)
{
error_count++;
skygw_log_write(LE,"Error: CA Certificate missing for service '%s'."
"Please provide the path to the certificate authority certificate by adding the ssl_ca_cert=<path> parameter",
obj->object);
}
if(ssl_key == NULL)
{
error_count++;
skygw_log_write(LE,"Error: Server private key missing for service '%s'. "
"Please provide the path to the server certificate key by adding the ssl_key=<path> parameter"
,obj->object);
}
if(access(ssl_ca_cert,F_OK) != 0)
{
skygw_log_write(LE,"Error: Certificate authority file for service '%s' not found: %s",
obj->object,
ssl_ca_cert);
error_count++;
}
if(access(ssl_cert,F_OK) != 0)
{
skygw_log_write(LE,"Error: Server certificate file for service '%s' not found: %s",
obj->object,
ssl_cert);
error_count++;
}
if(access(ssl_key,F_OK) != 0)
{
skygw_log_write(LE,"Error: Server private key file for service '%s' not found: %s",
obj->object,
ssl_key);
error_count++;
}
if(error_count == 0)
{
if(serviceSetSSL(obj->element,ssl) != 0)
{
skygw_log_write(LE,"Error: Unknown parameter for service '%s': %s",obj->object,ssl);
error_count++;
}
else
{
serviceSetCertificates(obj->element,ssl_cert,ssl_key,ssl_ca_cert);
if(ssl_version)
{
if(serviceSetSSLVersion(obj->element,ssl_version) != 0)
{
skygw_log_write(LE,"Error: Unknown parameter value for 'ssl_version' for service '%s': %s",obj->object,ssl_version);
error_count++;
}
}
if(ssl_cert_verify_depth)
{
if(serviceSetSSLVerifyDepth(obj->element,atoi(ssl_cert_verify_depth)) != 0)
{
skygw_log_write(LE,"Error: Invalid parameter value for 'ssl_cert_verify_depth' for service '%s': %s",obj->object,ssl_cert_verify_depth);
error_count++;
}
}
}
}
}
if (enable_root_user)
serviceEnableRootUser(
obj->element,
@ -1352,7 +1451,7 @@ int i;
}
else if (strcmp(name, "ms_timestamp") == 0)
{
skygw_set_highp(config_truth_value(value));
skygw_set_highp(config_truth_value((char*)value));
}
else
{
@ -1360,7 +1459,7 @@ int i;
{
if (strcasecmp(name, lognames[i].logname) == 0)
{
if (config_truth_value(value))
if (config_truth_value((char*)value))
skygw_log_enable(lognames[i].logfile);
else
skygw_log_disable(lognames[i].logfile);
@ -1938,6 +2037,12 @@ static char *service_params[] =
"version_string",
"filters",
"weightby",
"ssl_cert",
"ssl_ca_cert",
"ssl",
"ssl_key",
"ssl_version",
"ssl_cert_verify_depth",
NULL
};

View File

@ -974,19 +974,27 @@ getAllUsers(SERVICE *service, USERS *users)
}
}
if(service->optimize_wildcard && havedb && wildcard_db_grant(dbnm))
if(havedb && wildcard_db_grant(dbnm))
{
rc = add_wildcard_users(users, row[0], row[1], password, row[4], dbnm, service->resources);
skygw_log_write(LOGFILE_DEBUG|LOGFILE_TRACE,"%s: Converted '%s' to %d individual database grants.",service->name,dbnm,rc);
if(service->optimize_wildcard)
{
rc = add_wildcard_users(users, row[0], row[1], password, row[4], dbnm, service->resources);
skygw_log_write(LOGFILE_DEBUG|LOGFILE_TRACE,"%s: Converted '%s' to %d individual database grants.",service->name,dbnm,rc);
}
else
{
/** Use ANYDB for wildcard grants */
rc = add_mysql_users_with_host_ipv4(users, row[0], row[1], password, "Y", NULL);
}
}
else
{
rc = add_mysql_users_with_host_ipv4(users, row[0], row[1], password, row[4], havedb ? dbnm : NULL);
}
skygw_log_write(LOGFILE_DEBUG,"%s: Adding user:%s host:%s anydb:%s db:%s.",
LOGIF(LD,(skygw_log_write(LOGFILE_DEBUG,"%s: Adding user:%s host:%s anydb:%s db:%s.",
service->name,row[0],row[1],row[4],
havedb ? dbnm : NULL);
havedb ? dbnm : NULL)));
} else {
/* we don't have dbgrants, simply set ANY DB for the user */
rc = add_mysql_users_with_host_ipv4(users, row[0], row[1], password, "Y", NULL);
@ -1483,10 +1491,18 @@ getUsers(SERVICE *service, USERS *users)
}
}
if(service->optimize_wildcard && havedb && wildcard_db_grant(row[5]))
if(havedb && wildcard_db_grant(row[5]))
{
rc = add_wildcard_users(users, row[0], row[1], password, row[4], dbnm, service->resources);
skygw_log_write(LOGFILE_DEBUG|LOGFILE_TRACE,"%s: Converted '%s' to %d individual database grants.",service->name,row[5],rc);
if(service->optimize_wildcard)
{
rc = add_wildcard_users(users, row[0], row[1], password, row[4], dbnm, service->resources);
skygw_log_write(LOGFILE_DEBUG|LOGFILE_TRACE,"%s: Converted '%s' to %d individual database grants.",service->name,row[5],rc);
}
else
{
/** Use ANYDB for wildcard grants */
rc = add_mysql_users_with_host_ipv4(users, row[0], row[1], password, "Y", NULL);
}
}
else
{

File diff suppressed because it is too large Load Diff

29
server/core/gwdirs.c Normal file
View File

@ -0,0 +1,29 @@
#include <gwdirs.h>
/**
* Get the directory with all the modules.
* @return The module directory
*/
char* get_libdir()
{
return libdir?libdir:(char*)default_libdir;
}
/**
* Get the service cache directory
* @return The path to the cache directory
*/
char* get_cachedir()
{
return cachedir?cachedir:(char*)default_cachedir;
}
/**
* Get the service cache directory
* @return The path to the cache directory
*/
char* get_datadir()
{
return maxscaledatadir?maxscaledatadir:(char*)default_datadir;
}

View File

@ -48,6 +48,8 @@
#include <curl/curl.h>
#include <sys/utsname.h>
#include <openssl/sha.h>
#include <gw.h>
#include <gwdirs.h>
/** Defined in log_manager.cc */
extern int lm_enabled_logfiles_bitmask;
@ -104,21 +106,10 @@ WriteMemoryCallback(void *contents, size_t size, size_t nmemb, void *userp)
return realsize;
}
char* get_maxscale_home(void)
{
char* home = getenv("MAXSCALE_HOME");
if (home == NULL)
{
home = "/usr/local/mariadb-maxscale";
}
return home;
}
/**
* Load the dynamic library related to a gateway module. The routine
* will look for library files in the current directory,
* $MAXSCALE_HOME/modules and /usr/local/mariadb-maxscale/modules.
* the configured folder and /usr/lib64/maxscale.
*
* @param module Name of the module to load
* @param type Type of module, used purely for registration
@ -142,22 +133,17 @@ MODULE_INFO *mod_info = NULL;
*
* Search of the shared object.
*/
snprintf(fname,MAXPATHLEN+1, "./lib%s.so", module);
snprintf(fname, MAXPATHLEN+1,"%s/lib%s.so", get_libdir(), module);
if (access(fname, F_OK) == -1)
{
home = get_maxscale_home ();
snprintf(fname, MAXPATHLEN+1,"%s/modules/lib%s.so", home, module);
if (access(fname, F_OK) == -1)
{
LOGIF(LE, (skygw_log_write_flush(
LOGFILE_ERROR,
"Error : Unable to find library for "
"module: %s.",
module)));
return NULL;
}
LOGIF(LE, (skygw_log_write_flush(
LOGFILE_ERROR,
"Error : Unable to find library for "
"module: %s. Module dir: %s",
module, get_libdir())));
return NULL;
}
if ((dlhandle = dlopen(fname, RTLD_NOW|RTLD_LOCAL)) == NULL)

View File

@ -31,19 +31,25 @@
#include <secrets.h>
#include <skygw_utils.h>
#include <log_manager.h>
#include <gwdirs.h>
int main(int argc, char **argv)
{
int arg_count = 6;
int arg_count = 4;
char *home;
char *keyfile;
char** arg_vector;
int rval = 0;
if (argc != 2)
if (argc < 2)
{
fprintf(stderr, "Usage: %s <filename>\n", argv[0]);
return 1;
keyfile = "/var/lib/maxscale/";
fprintf(stderr, "Generating .secrets file in /var/lib/maxscale/ ...\n");
}
else
{
keyfile = argv[1];
}
arg_vector = malloc(sizeof(char*)*(arg_count + 1));
if(arg_vector == NULL)
@ -54,26 +60,14 @@ int main(int argc, char **argv)
arg_vector[0] = "logmanager";
arg_vector[1] = "-j";
if ((home = getenv("MAXSCALE_HOME")) != NULL)
{
arg_vector[2] = (char*)malloc((strlen(home) + strlen("/log"))*sizeof(char));
sprintf(arg_vector[2],"%s/log",home);
}
else
{
arg_vector[2] = strdup("/usr/local/mariadb-maxscale/log");
}
arg_vector[3] = "-o";
arg_vector[4] = "-l";
arg_vector[5] = "LOGFILE_ERROR";
arg_vector[6] = NULL;
arg_vector[2] = "/var/log/maxscale/maxkeys";
arg_vector[3] = "-o";
arg_vector[4] = NULL;
skygw_logmanager_init(arg_count,arg_vector);
free(arg_vector[2]);
free(arg_vector);
if (secrets_writeKeys(argv[1]))
if (secrets_writeKeys(keyfile))
{
fprintf(stderr, "Failed to encode the password\n");
rval = 1;

View File

@ -46,9 +46,9 @@ main(int argc, char **argv)
char** arg_vector;
int rval = 0;
if (argc != 2)
if (argc != 3)
{
fprintf(stderr, "Usage: %s <password>\n", argv[0]);
fprintf(stderr, "Usage: %s <file> <password>\n", argv[0]);
return 1;
}
@ -60,18 +60,9 @@ main(int argc, char **argv)
return 1;
}
arg_vector[0] = "logmanager";
arg_vector[1] = "-j";
if ((home = getenv("MAXSCALE_HOME")) != NULL)
{
arg_vector[2] = (char*)malloc((strlen(home) + strlen("/log"))*sizeof(char));
sprintf(arg_vector[2],"%s/log",home);
}
else
{
arg_vector[2] = strdup("/usr/local/mariadb-maxscale/log");
}
arg_vector[0] = strdup("logmanager");
arg_vector[1] = strdup("-j");
arg_vector[2] = strdup("/var/log/maxscale");
arg_vector[3] = "-o";
arg_vector[4] = "-l";
@ -88,9 +79,9 @@ main(int argc, char **argv)
return 1;
}
strncpy(pw,argv[1],80);
strncpy(pw,argv[2],80);
if ((enc = encryptPassword(pw)) != NULL){
if ((enc = encryptPassword(argv[1],pw)) != NULL){
printf("%s\n", enc);
}else{
fprintf(stderr, "Failed to encode the password\n");

View File

@ -841,4 +841,4 @@ int modutil_count_statements(GWBUF* buffer)
}
return num;
}
}

View File

@ -81,6 +81,8 @@ MONITOR *mon;
mon->handle = NULL;
mon->databases = NULL;
mon->password = NULL;
mon->user = NULL;
mon->password = NULL;
mon->read_timeout = DEFAULT_READ_TIMEOUT;
mon->write_timeout = DEFAULT_WRITE_TIMEOUT;
mon->connect_timeout = DEFAULT_CONNECT_TIMEOUT;

View File

@ -22,6 +22,7 @@
#include <log_manager.h>
#include <ctype.h>
#include <mysql_client_server_protocol.h>
#include <gwdirs.h>
/** Defined in log_manager.cc */
extern int lm_enabled_logfiles_bitmask;
@ -52,31 +53,26 @@ int i;
}
/**
* secrets_readKeys
*
* This routine reads data from a binary file and extracts the AES encryption key
* and the AES Init Vector
*
* This routine reads data from a binary file named ".secrets" and extracts the AES encryption key
* and the AES Init Vector.
* If the path parameter is not null the custom path is interpreted as a folder
* containing the .secrets file. Otherwise the default location is used.
* @return The keys structure or NULL on error
*/
static MAXKEYS *
secrets_readKeys()
secrets_readKeys(char* path)
{
char secret_file[255];
char secret_file[PATH_MAX+1];
char *home;
MAXKEYS *keys;
struct stat secret_stats;
int fd;
int len;
static int reported = 0;
home = getenv("MAXSCALE_HOME");
if (home == NULL) {
home = "/usr/local/mariadb-maxscale";
}
snprintf(secret_file, 255, "%s/etc/.secrets", home);
if(path != NULL)
snprintf(secret_file, PATH_MAX, "%s/.secrets", path);
else
snprintf(secret_file, PATH_MAX, "%s/.secrets", get_datadir());
/* Try to access secrets file */
if (access(secret_file, R_OK) == -1)
{
@ -225,11 +221,14 @@ static int reported = 0;
* @param secret_file The file with secret keys
* @return 0 on success and 1 on failure
*/
int secrets_writeKeys(char *secret_file)
int secrets_writeKeys(char *path)
{
int fd,randfd;
unsigned int randval;
MAXKEYS key;
char secret_file[PATH_MAX + 10];
sprintf(secret_file,"%s/.secrets",path);
/* Open for writing | Create | Truncate the file for writing */
if ((fd = open(secret_file, O_CREAT | O_WRONLY | O_TRUNC, S_IRUSR)) < 0)
@ -332,7 +331,7 @@ char *ptr;
unsigned char encrypted[80];
int enlen;
keys = secrets_readKeys();
keys = secrets_readKeys(NULL);
if (!keys)
return strdup(crypt);
/*
@ -369,12 +368,12 @@ int enlen;
* Encrypt a password that can be stored in the MaxScale configuration file.
*
* Note the return is always a malloc'd string that the caller must free
*
* @param path Path the the .secrets file
* @param password The password to encrypt
* @return The encrypted password
*/
char *
encryptPassword(char *password)
encryptPassword(char* path, char *password)
{
MAXKEYS *keys;
AES_KEY aeskey;
@ -383,7 +382,7 @@ char *hex_output;
unsigned char padded_passwd[80];
unsigned char encrypted[80];
if ((keys = secrets_readKeys()) == NULL)
if ((keys = secrets_readKeys(path)) == NULL)
return NULL;
memset(padded_passwd, 0, 80);

View File

@ -32,6 +32,7 @@
* 26/06/14 Mark Riddoch Addition of server parameters
* 30/08/14 Massimiliano Pinto Addition of new service status description
* 30/10/14 Massimiliano Pinto Addition of SERVER_MASTER_STICKINESS description
* 01/06/15 Massimiliano Pinto Addition of server_update_address/port
*
* @endverbatim
*/
@ -844,3 +845,41 @@ int *data;
return set;
}
/*
* Update the address value of a specific server
*
* @param server The server to update
* @param address The new address
*
*/
void
server_update_address(SERVER *server, char *address)
{
spinlock_acquire(&server_spin);
if (server && address) {
if (server->name) {
free(server->name);
}
server->name = strdup(address);
}
spinlock_release(&server_spin);
}
/*
* Update the port value of a specific server
*
* @param server The server to update
* @param port The new port value
*
*/
void
server_update_port(SERVER *server, unsigned short port)
{
spinlock_acquire(&server_spin);
if (server && port > 0) {
server->port = port;
}
spinlock_release(&server_spin);
}

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;
}

View File

@ -44,19 +44,4 @@ add_test(Internal-TestUsers test_users)
add_test(Internal-TestAdminUsers test_adminusers)
add_test(Internal-TestMemlog testmemlog)
add_test(TestFeedback testfeedback)
set_tests_properties(Internal-TestMySQLUsers
Internal-TestHash
Internal-TestHint
Internal-TestSpinlock
Internal-TestFilter
Internal-TestBuffer
Internal-TestDCB
Internal-TestModutil
Internal-TestPoll
Internal-TestService
Internal-TestServer
Internal-TestUsers
Internal-TestAdminUsers
Internal-TestMemlog
TestFeedback PROPERTIES ENVIRONMENT MAXSCALE_HOME=${CMAKE_BINARY_DIR}/)
set_tests_properties(TestFeedback PROPERTIES TIMEOUT 30)

View File

@ -30,7 +30,7 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <gwdirs.h>
#include <adminusers.h>
@ -40,7 +40,7 @@
* Test that the username password admin/mariadb is accepted if no users
* have been created and that no other users are accepted
*
* WARNING: $MAXSCALE_HOME/etc/passwd must be removed before this test is run
* WARNING: The passwd file must be removed before this test is run
*/
static int
test1()
@ -269,9 +269,8 @@ int result = 0;
char *home, buf[1024];
/* Unlink any existing password file before running this test */
if ((home = getenv("MAXSCALE_HOME")) == NULL || strlen(home) >= 1024)
home = "/usr/local/mariadb-maxscale";
sprintf(buf, "%s/etc/passwd", home);
sprintf(buf, "%s/passwd", default_cachedir);
if(!is_valid_posix_path(buf))
exit(1);
if (strcmp(buf, "/etc/passwd") != 0)

View File

@ -73,17 +73,8 @@ int main(int argc, char** argv)
char* cnf;
hkinit();
home = getenv("MAXSCALE_HOME");
if(home == NULL)
{
FAILTEST("MAXSCALE_HOME was not defined.");
}
printf("Home: %s\n",home);
cnf = malloc(strlen(home) + strlen("/etc/MaxScale.cnf") + 1);
strcpy(cnf,home);
strcat(cnf,"/etc/MaxScale.cnf");
cnf = strdup("/etc/MaxScale.cnf");
printf("Config: %s\n",cnf);
@ -116,4 +107,4 @@ int main(int argc, char** argv)
}
mysql_library_end();
return 0;
}
}