Merge branch 'MXS-544' into develop-MXS-544-merge

This commit is contained in:
Markus Makela
2016-03-03 21:39:39 +02:00
42 changed files with 3075 additions and 2294 deletions

View File

@ -43,7 +43,8 @@
* 20/02/15 Markus Mäkelä Added connection_timeout parameter for services
* 05/03/15 Massimiliano Pinto Added notification_feedback support
* 20/04/15 Guillaume Lefranc Added available_when_donor parameter
* 22/04/15 Martin Brampton Added disable_master_role_setting parameter
* 22/04/15 Martin Brampton Added disable_master_role_setting parameter
* 26/01/16 Martin Brampton Transfer SSL processing to listener
*
* @endverbatim
*/
@ -90,6 +91,8 @@ static void global_defaults();
static void feedback_defaults();
static void check_config_objects(CONFIG_CONTEXT *context);
static int maxscale_getline(char** dest, int* size, FILE* file);
static SSL_LISTENER *make_ssl_structure(CONFIG_CONTEXT *obj, bool require_cert, int *error_count);
int config_truth_value(char *str);
int config_get_ifaddr(unsigned char *output);
int config_get_release_string(char* release);
@ -99,7 +102,7 @@ bool config_has_duplicate_sections(const char* config);
int create_new_service(CONFIG_CONTEXT *obj);
int create_new_server(CONFIG_CONTEXT *obj);
int create_new_monitor(CONFIG_CONTEXT *context, CONFIG_CONTEXT *obj, HASHTABLE* monitorhash);
int create_new_listener(CONFIG_CONTEXT *obj);
int create_new_listener(CONFIG_CONTEXT *obj, bool startnow);
int create_new_filter(CONFIG_CONTEXT *obj);
int configure_new_service(CONFIG_CONTEXT *context, CONFIG_CONTEXT *obj);
@ -130,12 +133,6 @@ static char *service_params[] =
"version_string",
"filters",
"weightby",
"ssl_cert",
"ssl_ca_cert",
"ssl",
"ssl_key",
"ssl_version",
"ssl_cert_verify_depth",
"ignore_databases",
"ignore_databases_regex",
"log_auth_warnings",
@ -150,6 +147,13 @@ static char *listener_params[] =
"port",
"address",
"socket",
"authenticator",
"ssl_cert",
"ssl_ca_cert",
"ssl",
"ssl_key",
"ssl_version",
"ssl_cert_verify_depth",
NULL
};
@ -186,6 +190,14 @@ static char *server_params[] =
"monitorpw",
"persistpoolmax",
"persistmaxtime",
/* The following, or something similar, will be needed for backend SSL
"ssl_cert",
"ssl_ca_cert",
"ssl",
"ssl_key",
"ssl_version",
"ssl_cert_verify_depth",
*/
NULL
};
@ -547,7 +559,7 @@ process_config_context(CONFIG_CONTEXT *context)
}
else if (!strcmp(type, "listener"))
{
error_count += create_new_listener(obj);
error_count += create_new_listener(obj, false);
}
else if (!strcmp(type, "monitor"))
{
@ -876,6 +888,7 @@ static struct
{ "log_info", LOG_INFO, NULL },
{ NULL, 0 }
};
/**
* Configuration handler for items in the global [MaxScale] section
*
@ -1005,6 +1018,127 @@ handle_global_item(const char *name, const char *value)
return 1;
}
/**
* Form an SSL structure from listener section parameters
*
* @param obj The configuration object for the item being created
* @param require_cert Whether a certificate and key are required
* @param *error_count An error count which may be incremented
* @return SSL_LISTENER structure or NULL
*/
static SSL_LISTENER *
make_ssl_structure (CONFIG_CONTEXT *obj, bool require_cert, int *error_count)
{
char *ssl, *ssl_version, *ssl_cert, *ssl_key, *ssl_ca_cert, *ssl_cert_verify_depth;
int local_errors = 0;
SSL_LISTENER *new_ssl;
ssl = config_get_value(obj->parameters, "ssl");
if (ssl && !strcmp(ssl, "required"))
{
if ((new_ssl = malloc(sizeof(SSL_LISTENER))) == NULL)
{
return NULL;
}
new_ssl->ssl_method_type = SERVICE_SSL_TLS_MAX;
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");
new_ssl->ssl_init_done = false;
if (ssl_version)
{
if (listener_set_ssl_version(new_ssl, ssl_version) != 0)
{
MXS_ERROR("Unknown parameter value for 'ssl_version' for"
" service '%s': %s", obj->object, ssl_version);
local_errors++;
}
}
if (ssl_cert_verify_depth)
{
new_ssl->ssl_cert_verify_depth = atoi(ssl_cert_verify_depth);
if (new_ssl->ssl_cert_verify_depth < 0)
{
MXS_ERROR("Invalid parameter value for 'ssl_cert_verify_depth"
" for service '%s': %s", obj->object, ssl_cert_verify_depth);
new_ssl->ssl_cert_verify_depth = 0;
local_errors++;
}
}
else
{
/**
* Default of 9 as per Linux man page
*/
new_ssl->ssl_cert_verify_depth = 9;
}
listener_set_certificates(new_ssl, ssl_cert, ssl_key, ssl_ca_cert);
if (require_cert && new_ssl->ssl_cert == NULL)
{
local_errors++;
MXS_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 (new_ssl->ssl_ca_cert == NULL)
{
local_errors++;
MXS_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 (require_cert && new_ssl->ssl_key == NULL)
{
local_errors++;
MXS_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(new_ssl->ssl_ca_cert, F_OK) != 0)
{
MXS_ERROR("Certificate authority file for service '%s' not found: %s",
obj->object,
new_ssl->ssl_ca_cert);
local_errors++;
}
if (require_cert && access(new_ssl->ssl_cert, F_OK) != 0)
{
MXS_ERROR("Server certificate file for service '%s' not found: %s",
obj->object,
new_ssl->ssl_cert);
local_errors++;
}
if (require_cert && access(new_ssl->ssl_key, F_OK) != 0)
{
MXS_ERROR("Server private key file for service '%s' not found: %s",
obj->object,
new_ssl->ssl_key);
local_errors++;
}
if (0 == local_errors)
{
return new_ssl;
}
*error_count += local_errors;
free(new_ssl);
}
return NULL;
}
/**
* Configuration handler for items in the feedback [feedback] section
*
@ -1375,52 +1509,7 @@ process_config_update(CONFIG_CONTEXT *context)
}
else if (!strcmp(type, "listener"))
{
char *service;
char *port;
char *protocol;
char *address;
char *socket;
service = config_get_value(obj->parameters, "service");
address = config_get_value(obj->parameters, "address");
port = config_get_value(obj->parameters, "port");
protocol = config_get_value(obj->parameters, "protocol");
socket = config_get_value(obj->parameters, "socket");
if (service && socket && protocol)
{
CONFIG_CONTEXT *ptr = context;
while (ptr && strcmp(ptr->object, service) != 0)
{
ptr = ptr->next;
}
if (ptr &&
ptr->element &&
serviceHasProtocol(ptr->element, protocol, 0) == 0)
{
serviceAddProtocol(ptr->element, protocol, socket, 0);
serviceStartProtocol(ptr->element, protocol, 0);
}
}
if (service && port && protocol)
{
CONFIG_CONTEXT *ptr = context;
while (ptr && strcmp(ptr->object, service) != 0)
{
ptr = ptr->next;
}
if (ptr &&
ptr->element &&
serviceHasProtocol(ptr->element, protocol, atoi(port)) == 0)
{
serviceAddProtocol(ptr->element, protocol, address, atoi(port));
serviceStartProtocol(ptr->element, protocol, atoi(port));
}
}
create_new_listener(obj, true);
}
else if (strcmp(type, "server") != 0 &&
strcmp(type, "monitor") != 0 &&
@ -2239,6 +2328,7 @@ int create_new_service(CONFIG_CONTEXT *obj)
}
}
/*
char *ssl = config_get_value(obj->parameters, "ssl");
if (ssl)
{
@ -2282,6 +2372,7 @@ int create_new_service(CONFIG_CONTEXT *obj)
}
}
}
*/
/** Parameters for rwsplit router only */
if (strcmp(router, "readwritesplit") == 0)
@ -2414,6 +2505,8 @@ int create_new_server(CONFIG_CONTEXT *obj)
CONFIG_PARAMETER *params = obj->parameters;
server->server_ssl = make_ssl_structure(obj, false, &error_count);
while (params)
{
if (!is_normal_server_parameter(params->name))
@ -2634,9 +2727,10 @@ int create_new_monitor(CONFIG_CONTEXT *context, CONFIG_CONTEXT *obj, HASHTABLE*
/**
* Create a new listener for a service
* @param obj Listener configuration context
* @param startnow If true, start the listener now
* @return Number of errors
*/
int create_new_listener(CONFIG_CONTEXT *obj)
int create_new_listener(CONFIG_CONTEXT *obj, bool startnow)
{
int error_count = 0;
char *service_name = config_get_value(obj->parameters, "service");
@ -2644,20 +2738,52 @@ int create_new_listener(CONFIG_CONTEXT *obj)
char *address = config_get_value(obj->parameters, "address");
char *protocol = config_get_value(obj->parameters, "protocol");
char *socket = config_get_value(obj->parameters, "socket");
char *authenticator = config_get_value(obj->parameters, "authenticator");
if (service_name && protocol && (socket || port))
{
SERVICE *service = service_find(service_name);
if (service)
{
SSL_LISTENER *ssl_info = make_ssl_structure(obj, true, &error_count);
if (socket)
{
serviceAddProtocol(service, protocol, socket, 0);
if (serviceHasProtocol(service, protocol, 0))
{
MXS_ERROR("Listener '%s', for service '%s', socket %s, already have socket.",
obj->object,
service_name,
socket);
error_count++;
}
else
{
serviceAddProtocol(service, protocol, socket, 0, authenticator, ssl_info);
if (startnow)
{
serviceStartProtocol(service, protocol, 0);
}
}
}
if (port)
{
serviceAddProtocol(service, protocol, address, atoi(port));
if (serviceHasProtocol(service, protocol, atoi(port)))
{
MXS_ERROR("Listener '%s', for service '%s', already have port %s.",
obj->object,
service_name,
port);
error_count++;
}
else
{
serviceAddProtocol(service, protocol, address, atoi(port), authenticator, ssl_info);
if (startnow)
{
serviceStartProtocol(service, protocol, atoi(port));
}
}
}
}
else