Merge branch 'release-1.0GA' into develop

This commit is contained in:
Mark Riddoch
2014-12-08 10:24:19 +00:00
56 changed files with 1327 additions and 677 deletions

View File

@ -590,11 +590,12 @@ int error_count = 0;
}
if (obj->element && options)
{
char *s = strtok(options, ",");
char *lasts;
char *s = strtok_r(options, ",", &lasts);
while (s)
{
filterAddOption(obj->element, s);
s = strtok(NULL, ",");
s = strtok_r(NULL, ",", &lasts);
}
}
if (obj->element)
@ -640,7 +641,8 @@ int error_count = 0;
router = config_get_value(obj->parameters, "router");
if (servers && obj->element)
{
char *s = strtok(servers, ",");
char *lasts;
char *s = strtok_r(servers, ",", &lasts);
while (s)
{
CONFIG_CONTEXT *obj1 = context;
@ -667,7 +669,7 @@ int error_count = 0;
"service '%s'.",
s, obj->object)));
}
s = strtok(NULL, ",");
s = strtok_r(NULL, ",", &lasts);
}
}
else if (servers == NULL && internalService(router) == 0)
@ -681,11 +683,12 @@ int error_count = 0;
}
if (roptions && obj->element)
{
char *s = strtok(roptions, ",");
char *lasts;
char *s = strtok_r(roptions, ",", &lasts);
while (s)
{
serviceAddRouterOption(obj->element, s);
s = strtok(NULL, ",");
s = strtok_r(NULL, ",", &lasts);
}
}
if (filters && obj->element)
@ -818,7 +821,7 @@ int error_count = 0;
obj->element = monitor_alloc(obj->object, module);
if (servers && obj->element)
{
char *s;
char *s, *lasts;
/* if id is not set, compute it now with pid only */
if (gateway.id == 0) {
@ -853,7 +856,7 @@ int error_count = 0;
monitorSetNetworkTimeout(obj->element, MONITOR_WRITE_TIMEOUT, write_timeout);
/* get the servers to monitor */
s = strtok(servers, ",");
s = strtok_r(servers, ",", &lasts);
while (s)
{
CONFIG_CONTEXT *obj1 = context;
@ -880,7 +883,7 @@ int error_count = 0;
"monitor '%s'.",
s, obj->object)));
s = strtok(NULL, ",");
s = strtok_r(NULL, ",", &lasts);
}
}
if (obj->element && user && passwd)
@ -1529,7 +1532,8 @@ SERVER *server;
filters = config_get_value(obj->parameters, "filters");
if (servers && obj->element)
{
char *s = strtok(servers, ",");
char *lasts;
char *s = strtok_r(servers, ",", &lasts);
while (s)
{
CONFIG_CONTEXT *obj1 = context;
@ -1559,17 +1563,18 @@ SERVER *server;
"service '%s'.",
s, obj->object)));
}
s = strtok(NULL, ",");
s = strtok_r(NULL, ",", &lasts);
}
}
if (roptions && obj->element)
{
char *s = strtok(roptions, ",");
char *lasts;
char *s = strtok_r(roptions, ",", &lasts);
serviceClearRouterOptions(obj->element);
while (s)
{
serviceAddRouterOption(obj->element, s);
s = strtok(NULL, ",");
s = strtok_r(NULL, ",", &lasts);
}
}
if (filters && obj->element)
@ -1667,17 +1672,6 @@ static char *service_params[] =
NULL
};
static char *server_params[] =
{
"type",
"address",
"port",
"protocol",
"monitorpw",
"monitoruser",
NULL
};
static char *listener_params[] =
{
"type",

View File

@ -32,11 +32,13 @@
* x.y.z.%, x.y.%.%, x.%.%.%
* 03/10/14 Massimiliano Pinto Added netmask to user@host authentication for wildcard in IPv4 hosts
* 13/10/14 Massimiliano Pinto Added (user@host)@db authentication
* 04/12/14 Massimiliano Pinto Added support for IPv$ wildcard hosts: a.%, a.%.% and a.b.%
*
* @endverbatim
*/
#include <stdio.h>
#include <ctype.h>
#include <mysql.h>
#include <dcb.h>
@ -82,6 +84,7 @@ void resource_free(HASHTABLE *resource);
void *resource_fetch(HASHTABLE *, char *);
int resource_add(HASHTABLE *, char *, char *);
int resource_hash(char *);
static int normalize_hostname(char *input_host, char *output_host);
/**
* Load the user/passwd form mysql.user table into the service users' hashtable
@ -217,8 +220,6 @@ int add_mysql_users_with_host_ipv4(USERS *users, char *user, char *host, char *p
struct sockaddr_in serv_addr;
MYSQL_USER_HOST key;
char ret_ip[INET_ADDRSTRLEN + 1]="";
int found_range=0;
int found_any=0;
int ret = 0;
if (users == NULL || user == NULL || host == NULL) {
@ -255,42 +256,30 @@ int add_mysql_users_with_host_ipv4(USERS *users, char *user, char *host, char *p
/* ANY */
if (strcmp(host, "%") == 0) {
strcpy(ret_ip, "0.0.0.0");
found_any = 1;
key.netmask = 0;
} else {
char *tmp;
strncpy(ret_ip, host, INET_ADDRSTRLEN);
tmp = ret_ip+strlen(ret_ip)-1;
/* hostname without % wildcards has netmask = 32 */
key.netmask = normalize_hostname(host, ret_ip);
/* start from Class C */
while(tmp > ret_ip) {
if (*tmp == '%') {
/* set only the last IPv4 byte to 1
* avoiding setipadress() failure
* for Class C address
*/
found_range++;
if (found_range == 1)
*tmp = '1';
else
*tmp = '0';
}
tmp--;
if (key.netmask == -1) {
LOGIF(LE, (skygw_log_write_flush(
LOGFILE_ERROR,
"Error : strdup() failed in normalize_hostname for %s@%s",
user,
host)));
}
}
/* fill IPv4 data struct */
if (setipaddress(&serv_addr.sin_addr, ret_ip)) {
if (setipaddress(&serv_addr.sin_addr, ret_ip) && strlen(ret_ip)) {
/* copy IPv4 data into key.ipv4 */
memcpy(&key.ipv4, &serv_addr, sizeof(serv_addr));
if (found_range) {
/* let's zero the last IP byte: a.b.c.0 we set above to 1*/
/* if netmask < 32 there are % wildcards */
if (key.netmask < 32) {
/* let's zero the last IP byte: a.b.c.0 we may have set above to 1*/
key.ipv4.sin_addr.s_addr &= 0x00FFFFFF;
key.netmask = 32 - (found_range * 8);
} else {
key.netmask = 32 - (found_any * 32);
}
/* add user@host as key and passwd as value in the MySQL users hash table */
@ -362,10 +351,11 @@ getDatabases(SERVICE *service, MYSQL *con)
LOGIF(LE, (skygw_log_write_flush(
LOGFILE_ERROR,
"Warning: Loading DB names for service [%s] returned 0 rows."
" SHOW DATABASES grant to user [%s] is required for MaxScale DB Name Authentication",
service->name,
service_user)));
"%s: Unable to load database grant information, MaxScale "
"authentication will proceed without including database "
"permissions. To correct this GRANT select permission "
"on msql.db to the user %s.",
service->name, service_user)));
}
/* free resut set */
@ -622,7 +612,11 @@ getUsers(SERVICE *service, USERS *users)
LOGIF(LE, (skygw_log_write_flush(
LOGFILE_ERROR,
"Error: Loading DB grants failed: GRANT is required on [mysql.db] to user [%s]. Try loading DB users for service [%s] without DB name MaxScale Authentication", service_user, service->name)));
"%s: Unable to load database grant information, MaxScale "
"authentication will proceed without including database "
"permissions. To correct this GRANT select permission "
"on msql.db to the user %s.",
service->name, service_user)));
/* check for root user select */
if(service->enable_root) {
@ -649,8 +643,9 @@ getUsers(SERVICE *service, USERS *users)
LOGIF(LM, (skygw_log_write_flush(
LOGFILE_MESSAGE,
"Loading users from [mysql.user] without DB grants from [mysql.db] for service [%s]."
" MaxScale Authentication with DBname on connect will not work",
"Loading users from [mysql.user] without access to [mysql.db] for "
"service [%s]. MaxScale Authentication with DBname on connect "
"will not consider database grants.",
service->name)));
}
} else {
@ -715,7 +710,23 @@ getUsers(SERVICE *service, USERS *users)
int rc = 0;
char *password = NULL;
if (row[2] != NULL) {
/* detect mysql_old_password (pre 4.1 protocol) */
if (strlen(row[2]) == 16) {
LOGIF(LE, (skygw_log_write_flush(
LOGFILE_ERROR,
"%s: The user %s@%s has on old password in the "
"backend database. MaxScale does not support these "
"old passwords. This user will not be able to connect "
"via MaxScale. Update the users password to correct "
"this.",
service->name,
row[0],
row[1])));
continue;
}
if (strlen(row[2]) > 1)
password = row[2] +1;
else
@ -752,19 +763,20 @@ getUsers(SERVICE *service, USERS *users)
/* Log the user being added with its db grants */
LOGIF(LD, (skygw_log_write_flush(
LOGFILE_DEBUG,
"Added user %s@%s with DB grants on [%s], for service [%s]",
"%s: User %s@%s for database %s added to "
"service user table.",
service->name,
row[0],
row[1],
dbgrant,
service->name)));
dbgrant)));
} else {
/* Log the user being added (without db grants) */
LOGIF(LD, (skygw_log_write_flush(
LOGFILE_DEBUG,
"Added user %s@%s for service [%s]",
"%s: User %s@%s added to service user table.",
service->name,
row[0],
row[1],
service->name)));
row[1])));
}
/* Append data in the memory area for SHA1 digest */
@ -774,7 +786,8 @@ getUsers(SERVICE *service, USERS *users)
} else {
LOGIF(LE, (skygw_log_write_flush(
LOGFILE_ERROR,
"Warning: Failed adding user %s@%s for service [%s]",
"Warning: Failed to add user %s@%s for service [%s]. "
"This user will be unavailable via MaxScale.",
row[0],
row[1],
service->name)));
@ -1096,3 +1109,87 @@ resource_fetch(HASHTABLE *resources, char *key)
return hashtable_fetch(resources, key);
}
/**
* Normalize hostname with % wildcards to a valid IP string.
*
* Valid input values:
* a.b.c.d, a.b.c.%, a.b.%.%, a.%.%.%
* Short formats a.% and a.%.% are both converted to a.%.%.%
* Short format a.b.% is converted to a.b.%.%
*
* Last host byte is set to 1, avoiding setipadress() failure
*
* @param input_host The hostname with possible % wildcards
* @param output_host The normalized hostname (buffer must be preallocated)
* @return The calculated netmask or -1 on failure
*/
static int normalize_hostname(char *input_host, char *output_host)
{
int netmask, bytes, bits = 0, found_wildcard = 0;
char *p, *lasts, *tmp;
int useorig = 0;
output_host[0] = 0;
bytes = 0;
tmp = strdup(input_host);
if (tmp == NULL) {
return -1;
}
p = strtok_r(tmp, ".", &lasts);
while (p != NULL)
{
if (strcmp(p, "%"))
{
if (! isdigit(*p))
useorig = 1;
strcat(output_host, p);
bits += 8;
}
else if (bytes == 3)
{
found_wildcard = 1;
strcat(output_host, "1");
}
else
{
found_wildcard = 1;
strcat(output_host, "0");
}
bytes++;
p = strtok_r(NULL, ".", &lasts);
if (p)
strcat(output_host, ".");
}
if (found_wildcard)
{
netmask = bits;
while (bytes++ < 4)
{
if (bytes == 4)
{
strcat(output_host, ".1");
}
else
{
strcat(output_host, ".0");
}
}
}
else
netmask = 32;
if (useorig == 1)
{
netmask = 32;
strcpy(output_host, input_host);
}
free(tmp);
return netmask;
}

View File

@ -332,8 +332,7 @@ DOWNSTREAM *me;
if ((filter->obj = load_module(filter->module,
MODULE_FILTER)) == NULL)
{
me = NULL;
goto retblock;
return NULL;
}
}
@ -342,8 +341,7 @@ DOWNSTREAM *me;
if ((filter->filter = (filter->obj->createInstance)(filter->options,
filter->parameters)) == NULL)
{
me = NULL;
goto retblock;
return NULL;
}
}
if ((me = (DOWNSTREAM *)calloc(1, sizeof(DOWNSTREAM))) == NULL)
@ -355,7 +353,7 @@ DOWNSTREAM *me;
errno,
strerror(errno))));
goto retblock;
return NULL;
}
me->instance = filter->filter;
me->routeQuery = (void *)(filter->obj->routeQuery);
@ -363,12 +361,10 @@ DOWNSTREAM *me;
if ((me->session=filter->obj->newSession(me->instance, session)) == NULL)
{
free(me);
me = NULL;
goto retblock;
return NULL;
}
filter->obj->setDownstream(me->instance, me->session, downstream);
retblock:
return me;
}

View File

@ -641,55 +641,63 @@ static bool resolve_maxscale_homedir(
}
check_home_dir:
if (*p_home_dir != NULL)
{
if (!file_is_readable(*p_home_dir))
{
char* tailstr = "MaxScale doesn't have read permission "
"to MAXSCALE_HOME.";
char* logstr = (char*)malloc(strlen(log_context)+
1+
strlen(tailstr)+
1);
snprintf(logstr,
strlen(log_context)+
1+
strlen(tailstr)+1,
"%s:%s",
log_context,
tailstr);
print_log_n_stderr(true, true, logstr, logstr, 0);
free(logstr);
goto return_succp;
}
#if WRITABLE_HOME
if (!file_is_writable(*p_home_dir))
{
char* tailstr = "MaxScale doesn't have write permission "
"to MAXSCALE_HOME. Exiting.";
char* logstr = (char*)malloc(strlen(log_context)+
1+
strlen(tailstr)+
1);
snprintf(logstr,
strlen(log_context)+
1+
strlen(tailstr)+1,
"%s:%s",
log_context,
tailstr);
print_log_n_stderr(true, true, logstr, logstr, 0);
free(logstr);
goto return_succp;
}
#endif
if (!daemon_mode)
{
fprintf(stderr,
"Using %s as MAXSCALE_HOME = %s\n",
log_context,
tmp);
}
succp = true;
goto return_succp;
}
return_succp:
free (tmp);
if (*p_home_dir != NULL)
{
char* errstr;
errstr = check_dir_access(*p_home_dir);
if (errstr != NULL)
{
char* logstr = (char*)malloc(strlen(log_context)+
1+
strlen(errstr)+
1);
snprintf(logstr,
strlen(log_context)+
1+
strlen(errstr)+1,
"%s: %s",
log_context,
errstr);
print_log_n_stderr(true, true, logstr, logstr, 0);
free(errstr);
free(logstr);
succp = false;
}
else
{
succp = true;
if (!daemon_mode)
{
fprintf(stderr,
"Using %s as MAXSCALE_HOME = %s\n",
log_context,
(tmp == NULL ? *p_home_dir : tmp));
}
}
}
else
{
succp = false;
}
if (tmp != NULL)
{
free(tmp);
}
if (log_context != NULL)
{

View File

@ -293,7 +293,7 @@ GWBUF *modutil_create_mysql_err_msg(
const char *msg)
{
uint8_t *outbuf = NULL;
uint8_t mysql_payload_size = 0;
uint32_t mysql_payload_size = 0;
uint8_t mysql_packet_header[4];
uint8_t *mysql_payload = NULL;
uint8_t field_count = 0;

View File

@ -344,8 +344,10 @@ SERVER_PARAM *param;
}
}
if (server->node_ts > 0) {
struct tm result;
char buf[40];
dcb_printf(dcb, "\tLast Repl Heartbeat:\t%s",
asctime(localtime(&server->node_ts)));
asctime_r(localtime_r((time_t *)(&server->node_ts), &result), buf));
}
if ((param = server->parameters) != NULL)
{

View File

@ -809,13 +809,16 @@ SERVICE *service;
void
printService(SERVICE *service)
{
SERVER *ptr = service->databases;
int i;
SERVER *ptr = service->databases;
struct tm result;
char time_buf[30];
int i;
printf("Service %p\n", service);
printf("\tService: %s\n", service->name);
printf("\tRouter: %s (%p)\n", service->routerModule, service->router);
printf("\tStarted: %s", asctime(localtime(&service->stats.started)));
printf("\tStarted: %s",
asctime_r(localtime_r(&service->stats.started, &result), time_buf));
printf("\tBackend databases\n");
while (ptr)
{
@ -887,8 +890,10 @@ SERVICE *ptr;
*/
void dprintService(DCB *dcb, SERVICE *service)
{
SERVER *server = service->databases;
int i;
SERVER *server = service->databases;
struct tm result;
char timebuf[30];
int i;
dcb_printf(dcb, "Service %p\n", service);
dcb_printf(dcb, "\tService: %s\n",
@ -898,7 +903,7 @@ int i;
if (service->router)
service->router->diagnostics(service->router_instance, dcb);
dcb_printf(dcb, "\tStarted: %s",
asctime(localtime(&service->stats.started)));
asctime_r(localtime_r(&service->stats.started, &result), timebuf));
dcb_printf(dcb, "\tRoot user access: %s\n",
service->enable_root ? "Enabled" : "Disabled");
if (service->n_filters)
@ -1232,19 +1237,18 @@ bool service_set_param_value (
/*
* Function to find a string in typelib_t
* (similar to find_type() of mysys/typelib.c)
*
* SYNOPSIS
* find_type()
* lib typelib_t
* find String to find
* length Length of string to find
* part_match Allow part matching of value
*
* RETURN
* 0 error
* > 0 position in TYPELIB->type_names +1
*
* SYNOPSIS
* find_type()
* lib typelib_t
* find String to find
* length Length of string to find
* part_match Allow part matching of value
*
* RETURN
* 0 error
* > 0 position in TYPELIB->type_names +1
*/
static int find_type(
typelib_t* tl,
const char* needle,

View File

@ -465,11 +465,15 @@ int rval = 0;
void
printSession(SESSION *session)
{
struct tm result;
char timebuf[40];
printf("Session %p\n", session);
printf("\tState: %s\n", session_state(session->state));
printf("\tService: %s (%p)\n", session->service->name, session->service);
printf("\tClient DCB: %p\n", session->client);
printf("\tConnected: %s", asctime(localtime(&session->stats.connect)));
printf("\tConnected: %s",
asctime_r(localtime_r(&session->stats.connect, &result), timebuf));
}
/**
@ -566,7 +570,9 @@ int norouter = 0;
void
dprintAllSessions(DCB *dcb)
{
SESSION *ptr;
struct tm result;
char timebuf[40];
SESSION *ptr;
spinlock_acquire(&session_spin);
ptr = allSessions;
@ -578,7 +584,8 @@ SESSION *ptr;
dcb_printf(dcb, "\tClient DCB: %p\n", ptr->client);
if (ptr->client && ptr->client->remote)
dcb_printf(dcb, "\tClient Address: %s\n", ptr->client->remote);
dcb_printf(dcb, "\tConnected: %s", asctime(localtime(&ptr->stats.connect)));
dcb_printf(dcb, "\tConnected: %s",
asctime_r(localtime_r(&ptr->stats.connect, &result), timebuf));
ptr = ptr->next;
}
spinlock_release(&session_spin);
@ -596,7 +603,9 @@ SESSION *ptr;
void
dprintSession(DCB *dcb, SESSION *ptr)
{
int i;
struct tm result;
char buf[30];
int i;
dcb_printf(dcb, "Session %d (%p)\n",ptr->ses_id, ptr);
dcb_printf(dcb, "\tState: %s\n", session_state(ptr->state));
@ -604,7 +613,8 @@ int i;
dcb_printf(dcb, "\tClient DCB: %p\n", ptr->client);
if (ptr->client && ptr->client->remote)
dcb_printf(dcb, "\tClient Address: %s\n", ptr->client->remote);
dcb_printf(dcb, "\tConnected: %s", asctime(localtime(&ptr->stats.connect)));
dcb_printf(dcb, "\tConnected: %s",
asctime_r(localtime_r(&ptr->stats.connect, &result), buf));
if (ptr->n_filters)
{
for (i = 0; i < ptr->n_filters; i++)

View File

@ -231,9 +231,9 @@ int set_and_get_mysql_users_wildcards(char *username, char *hostname, char *pass
service->users = mysql_users;
if (db_from != NULL)
strcpy(data->db, db_from);
strncpy(data->db, db_from,MYSQL_DATABASE_MAXLEN);
else
strcpy(data->db, "");
strncpy(data->db, "",MYSQL_DATABASE_MAXLEN);
/* freed by dcb_free(dcb) */
dcb->data = data;
@ -392,6 +392,22 @@ int main() {
if (!ret) fprintf(stderr, "\t-- Expecting ok\n");
assert(ret == 0);
ret = set_and_get_mysql_users_wildcards("pippo", "192.%", "foo", "192.254.254.242", NULL, NULL, NULL);
if (!ret) fprintf(stderr, "\t-- Expecting ok\n");
assert(ret == 0);
ret = set_and_get_mysql_users_wildcards("pippo", "192.%.%", "foo", "192.254.254.242", NULL, NULL, NULL);
if (!ret) fprintf(stderr, "\t-- Expecting ok\n");
assert(ret == 0);
ret = set_and_get_mysql_users_wildcards("pippo", "192.254.%", "foo", "192.254.254.242", NULL, NULL, NULL);
if (!ret) fprintf(stderr, "\t-- Expecting ok\n");
assert(ret == 0);
ret = set_and_get_mysql_users_wildcards("pippo", "192.254.%", "foo", "192.254.0.242", NULL, NULL, NULL);
if (!ret) fprintf(stderr, "\t-- Expecting ok\n");
assert(ret == 0);
ret = set_and_get_mysql_users_wildcards("riccio", "192.0.0.%", "foo", "192.134.0.2", NULL, NULL, NULL);
if (ret) fprintf(stderr, "\t-- Expecting no match\n");
assert(ret == 1);