Merge branch 'develop' into 1.2.1-binlog_router_trx
This commit is contained in:
commit
a591b47b9f
@ -92,7 +92,7 @@ static void global_defaults();
|
||||
static void feedback_defaults();
|
||||
static void check_config_objects(CONFIG_CONTEXT *context);
|
||||
int config_truth_value(char *str);
|
||||
static int internalService(char *router);
|
||||
bool isInternalService(char *router);
|
||||
int config_get_ifaddr(unsigned char *output);
|
||||
int config_get_release_string(char* release);
|
||||
FEEDBACK_CONF * config_get_feedback_data();
|
||||
@ -898,7 +898,7 @@ process_config_context(CONFIG_CONTEXT *context)
|
||||
s = strtok_r(NULL, ",", &lasts);
|
||||
}
|
||||
}
|
||||
else if (servers == NULL && internalService(router) == 0)
|
||||
else if (servers == NULL && !isInternalService(router))
|
||||
{
|
||||
LOGIF(LE, (skygw_log_write_flush(
|
||||
LOGFILE_ERROR,
|
||||
@ -1107,6 +1107,7 @@ process_config_context(CONFIG_CONTEXT *context)
|
||||
monitorAddUser(obj->element,
|
||||
user,
|
||||
passwd);
|
||||
check_monitor_permissions(obj->element);
|
||||
}
|
||||
else if (obj->element && user)
|
||||
{
|
||||
@ -2229,18 +2230,16 @@ static char *InternalRouters[] = {
|
||||
* @param router The router name
|
||||
* @return Non-zero if the router is in the InternalRouters table
|
||||
*/
|
||||
static int
|
||||
internalService(char *router)
|
||||
bool
|
||||
isInternalService(char *router)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (router)
|
||||
{
|
||||
for (i = 0; InternalRouters[i]; i++)
|
||||
for (int i = 0; InternalRouters[i]; i++)
|
||||
if (strcmp(router, InternalRouters[i]) == 0)
|
||||
return 1;
|
||||
return true;
|
||||
}
|
||||
return 0;
|
||||
return false;
|
||||
}
|
||||
/**
|
||||
* Get the MAC address of first network interface
|
||||
|
@ -82,7 +82,7 @@
|
||||
#define MYSQL_USERS_COUNT "SELECT COUNT(1) AS nusers FROM mysql.user"
|
||||
|
||||
#define MYSQL_USERS_WITH_DB_ORDER " ORDER BY host DESC"
|
||||
#define LOAD_MYSQL_USERS_WITH_DB_QUERY "SELECT user.user AS user,user.host AS host,user.password AS password,concat(user.user,user.host,user.password,user.Select_priv,IFNULL(db,'')) AS userdata, user.Select_priv AS anydb,db.db AS db FROM mysql.user LEFT JOIN mysql.db ON user.user=db.user AND user.host=db.host WHERE user.user IS NOT NULL AND user.user <> ''" MYSQL_USERS_WITH_DB_ORDER
|
||||
#define LOAD_MYSQL_USERS_WITH_DB_QUERY "SELECT user.user AS user,user.host AS host,user.password AS password,concat(user.user,user.host,user.password,user.Select_priv,IFNULL(db,'')) AS userdata, user.Select_priv AS anydb,db.db AS db FROM mysql.user LEFT JOIN mysql.db ON user.user=db.user AND user.host=db.host WHERE user.user IS NOT NULL" MYSQL_USERS_WITH_DB_ORDER
|
||||
|
||||
#define MYSQL_USERS_WITH_DB_COUNT "SELECT COUNT(1) AS nusers_db FROM (" LOAD_MYSQL_USERS_WITH_DB_QUERY ") AS tbl_count"
|
||||
|
||||
@ -584,7 +584,8 @@ getAllUsers(SERVICE *service, USERS *users)
|
||||
MYSQL_DATABASE_MAXLEN;
|
||||
int dbnames = 0;
|
||||
int db_grants = 0;
|
||||
|
||||
bool anon_user = false;
|
||||
|
||||
if (serviceGetUser(service, &service_user, &service_passwd) == 0)
|
||||
{
|
||||
ss_dassert(service_passwd == NULL || service_user == NULL);
|
||||
@ -928,7 +929,16 @@ getAllUsers(SERVICE *service, USERS *users)
|
||||
|
||||
int rc = 0;
|
||||
char *password = NULL;
|
||||
|
||||
|
||||
/** If the username is empty, the backend server still has anonymous
|
||||
* user in it. This will mean that localhost addresses do not match
|
||||
* the wildcard host '%' */
|
||||
if(strlen(row[0]) == 0)
|
||||
{
|
||||
anon_user = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (row[2] != NULL) {
|
||||
/* detect mysql_old_password (pre 4.1 protocol) */
|
||||
if (strlen(row[2]) == 16) {
|
||||
@ -1077,7 +1087,10 @@ getAllUsers(SERVICE *service, USERS *users)
|
||||
SHA1((const unsigned char *) final_data, strlen(final_data), hash);
|
||||
|
||||
memcpy(users->cksum, hash, SHA_DIGEST_LENGTH);
|
||||
|
||||
|
||||
/** Set the parameter if it is not configured by the user */
|
||||
if(service->localhost_match_wildcard_host == SERVICE_PARAM_UNINIT)
|
||||
service->localhost_match_wildcard_host = anon_user ? 0 : 1;
|
||||
cleanup:
|
||||
|
||||
free(dpwd);
|
||||
@ -1119,6 +1132,7 @@ getUsers(SERVICE *service, USERS *users)
|
||||
int dbnames = 0;
|
||||
int db_grants = 0;
|
||||
char dbnm[MYSQL_DATABASE_MAXLEN+1];
|
||||
bool anon_user = false;
|
||||
|
||||
if (serviceGetUser(service, &service_user, &service_passwd) == 0)
|
||||
{
|
||||
@ -1448,6 +1462,15 @@ getUsers(SERVICE *service, USERS *users)
|
||||
int rc = 0;
|
||||
char *password = NULL;
|
||||
|
||||
/** If the username is empty, the backend server still has anonymous
|
||||
* user in it. This will mean that localhost addresses do not match
|
||||
* the wildcard host '%' */
|
||||
if(strlen(row[0]) == 0)
|
||||
{
|
||||
anon_user = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (row[2] != NULL) {
|
||||
/* detect mysql_old_password (pre 4.1 protocol) */
|
||||
if (strlen(row[2]) == 16) {
|
||||
@ -1578,6 +1601,10 @@ getUsers(SERVICE *service, USERS *users)
|
||||
|
||||
memcpy(users->cksum, hash, SHA_DIGEST_LENGTH);
|
||||
|
||||
/** Set the parameter if it is not configured by the user */
|
||||
if(service->localhost_match_wildcard_host == SERVICE_PARAM_UNINIT)
|
||||
service->localhost_match_wildcard_host = anon_user ? 0 : 1;
|
||||
|
||||
free(users_data);
|
||||
mysql_free_result(result);
|
||||
mysql_close(con);
|
||||
@ -2325,3 +2352,129 @@ int add_wildcard_users(USERS *users, char* name, char* host, char* password, cha
|
||||
|
||||
return rval;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the service user has all required permissions to operate properly.
|
||||
* this checks for SELECT permissions on mysql.user and mysql.db tables and for
|
||||
* SHOW DATABASES permissions. If permissions are not adequate, an error message
|
||||
* is logged.
|
||||
* @param service Service to inspect
|
||||
* @return True if service permissions are correct. False if one or more permissions
|
||||
* are missing or if an error occurred.
|
||||
*/
|
||||
bool check_service_permissions(SERVICE* service)
|
||||
{
|
||||
MYSQL* mysql;
|
||||
MYSQL_RES* res;
|
||||
char *user,*password,*dpasswd;
|
||||
SERVER_REF* server;
|
||||
int conn_timeout = 1;
|
||||
bool rval = true;
|
||||
|
||||
if(isInternalService(service->routerModule))
|
||||
return true;
|
||||
|
||||
if(service->dbref == NULL)
|
||||
{
|
||||
skygw_log_write(LE,"%s: Error: Service is missing the servers parameter.",service->name);
|
||||
return false;
|
||||
}
|
||||
|
||||
server = service->dbref;
|
||||
|
||||
if (serviceGetUser(service, &user, &password) == 0)
|
||||
{
|
||||
skygw_log_write(LE,
|
||||
"%s: Error: Service is missing the user credentials for authentication.",
|
||||
service->name);
|
||||
return false;
|
||||
}
|
||||
|
||||
dpasswd = decryptPassword(password);
|
||||
|
||||
if((mysql = mysql_init(NULL)) == NULL)
|
||||
{
|
||||
skygw_log_write(LE,"[%s] Error: MySQL connection initialization failed.",__FUNCTION__);
|
||||
free(dpasswd);
|
||||
return false;
|
||||
}
|
||||
|
||||
mysql_options(mysql,MYSQL_OPT_USE_REMOTE_CONNECTION,NULL);
|
||||
mysql_options(mysql,MYSQL_OPT_CONNECT_TIMEOUT,&conn_timeout);
|
||||
/** Connect to the first server. This assumes all servers have identical
|
||||
* user permissions. */
|
||||
|
||||
if(mysql_real_connect(mysql,server->server->name,user,dpasswd,NULL,server->server->port,NULL,0) == NULL)
|
||||
{
|
||||
skygw_log_write(LE,"%s: Error: Failed to connect to server %s(%s:%d) when"
|
||||
" checking authentication user credentials and permissions.",
|
||||
service->name,
|
||||
server->server->unique_name,
|
||||
server->server->name,
|
||||
server->server->port);
|
||||
mysql_close(mysql);
|
||||
free(dpasswd);
|
||||
return false;
|
||||
}
|
||||
|
||||
if(mysql_query(mysql,"SELECT user, host, password,Select_priv FROM mysql.user limit 1") != 0)
|
||||
{
|
||||
if(mysql_errno(mysql) == ER_TABLEACCESS_DENIED_ERROR)
|
||||
{
|
||||
skygw_log_write(LE,"%s: Error: User '%s' is missing SELECT privileges"
|
||||
" on mysql.user table. MySQL error message: %s",
|
||||
service->name,user,mysql_error(mysql));
|
||||
}
|
||||
else
|
||||
{
|
||||
skygw_log_write(LE,"%s: Error: Failed to query from mysql.user table."
|
||||
" MySQL error message: %s",
|
||||
service->name,mysql_error(mysql));
|
||||
}
|
||||
rval = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
if((res = mysql_use_result(mysql)) == NULL)
|
||||
{
|
||||
skygw_log_write(LE,"%s: Error: Result retrieval failed when checking for"
|
||||
" permissions to the mysql.user table: %s",
|
||||
service->name,mysql_error(mysql));
|
||||
mysql_close(mysql);
|
||||
free(dpasswd);
|
||||
return false;
|
||||
}
|
||||
|
||||
mysql_free_result(res);
|
||||
}
|
||||
if(mysql_query(mysql,"SELECT user, host, db FROM mysql.db limit 1") != 0)
|
||||
{
|
||||
if(mysql_errno(mysql) == ER_TABLEACCESS_DENIED_ERROR)
|
||||
{
|
||||
skygw_log_write(LE,"%s: Error: User '%s' is missing SELECT privileges on mysql.db table. MySQL error message: %s",
|
||||
service->name,user,mysql_error(mysql));
|
||||
}
|
||||
else
|
||||
{
|
||||
skygw_log_write(LE,"%s: Error: Failed to query from mysql.db table. MySQL error message: %s",
|
||||
service->name,mysql_error(mysql));
|
||||
}
|
||||
rval = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
if((res = mysql_use_result(mysql)) == NULL)
|
||||
{
|
||||
skygw_log_write(LE,"%s: Error: Result retrieval failed when checking for permissions to the mysql.db table: %s",
|
||||
service->name,mysql_error(mysql));
|
||||
rval = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
mysql_free_result(res);
|
||||
}
|
||||
}
|
||||
mysql_close(mysql);
|
||||
free(dpasswd);
|
||||
return rval;
|
||||
}
|
@ -40,6 +40,8 @@
|
||||
#include <modules.h>
|
||||
#include <skygw_utils.h>
|
||||
#include <log_manager.h>
|
||||
#include <secrets.h>
|
||||
#include <mysql/mysqld_error.h>
|
||||
|
||||
/** Defined in log_manager.cc */
|
||||
extern int lm_enabled_logfiles_bitmask;
|
||||
@ -448,3 +450,80 @@ int *data;
|
||||
|
||||
return set;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the monitor user has all required permissions to operate properly.
|
||||
* this checks for REPLICATION CLIENT permissions
|
||||
* @param service Monitor to inspect
|
||||
* @return False if an error with monitor permissions was detected or if an
|
||||
* error occurred. True if permissions are correct.
|
||||
*/
|
||||
bool check_monitor_permissions(MONITOR* monitor)
|
||||
{
|
||||
MYSQL* mysql;
|
||||
MYSQL_RES* res;
|
||||
char *user,*dpasswd;
|
||||
SERVER* server;
|
||||
int conn_timeout = 1;
|
||||
bool rval = true;
|
||||
|
||||
user = monitor->user;
|
||||
dpasswd = decryptPassword(monitor->password);
|
||||
|
||||
if((mysql = mysql_init(NULL)) == NULL)
|
||||
{
|
||||
skygw_log_write(LE,"[%s] Error: MySQL connection initialization failed.",__FUNCTION__);
|
||||
free(dpasswd);
|
||||
return false;
|
||||
}
|
||||
|
||||
server = monitor->databases->server;
|
||||
mysql_options(mysql,MYSQL_OPT_USE_REMOTE_CONNECTION,NULL);
|
||||
mysql_options(mysql,MYSQL_OPT_CONNECT_TIMEOUT,&conn_timeout);
|
||||
|
||||
/** Connect to the first server. This assumes all servers have identical
|
||||
* user permissions. */
|
||||
if(mysql_real_connect(mysql,server->name,user,dpasswd,NULL,server->port,NULL,0) == NULL)
|
||||
{
|
||||
skygw_log_write(LE,"%s: Error: Failed to connect to server %s(%s:%d) when"
|
||||
" checking monitor user credentials and permissions.",
|
||||
monitor->name,
|
||||
server->unique_name,
|
||||
server->name,
|
||||
server->port);
|
||||
mysql_close(mysql);
|
||||
free(dpasswd);
|
||||
return false;
|
||||
}
|
||||
|
||||
if(mysql_query(mysql,"show slave status") != 0)
|
||||
{
|
||||
if(mysql_errno(mysql) == ER_SPECIFIC_ACCESS_DENIED_ERROR)
|
||||
{
|
||||
skygw_log_write(LE,"%s: Error: User '%s' is missing REPLICATION CLIENT privileges. MySQL error message: %s",
|
||||
monitor->name,user,mysql_error(mysql));
|
||||
}
|
||||
else
|
||||
{
|
||||
skygw_log_write(LE,"%s: Error: Monitor failed to query for slave status. MySQL error message: %s",
|
||||
monitor->name,mysql_error(mysql));
|
||||
}
|
||||
rval = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
if((res = mysql_use_result(mysql)) == NULL)
|
||||
{
|
||||
skygw_log_write(LE,"%s: Error: Result retrieval failed when checking for REPLICATION CLIENT permissions: %s",
|
||||
monitor->name,mysql_error(mysql));
|
||||
rval = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
mysql_free_result(res);
|
||||
}
|
||||
}
|
||||
mysql_close(mysql);
|
||||
free(dpasswd);
|
||||
return rval;
|
||||
}
|
@ -140,6 +140,7 @@ SERVICE *service;
|
||||
service->routerModule = strdup(router);
|
||||
service->users_from_all = false;
|
||||
service->resources = NULL;
|
||||
service->localhost_match_wildcard_host = SERVICE_PARAM_UNINIT;
|
||||
service->ssl_mode = SSL_DISABLED;
|
||||
service->ssl_init_done = false;
|
||||
service->ssl_ca_cert = NULL;
|
||||
@ -417,6 +418,16 @@ serviceStart(SERVICE *service)
|
||||
SERV_PROTOCOL *port;
|
||||
int listeners = 0;
|
||||
|
||||
|
||||
if(!check_service_permissions(service))
|
||||
{
|
||||
skygw_log_write_flush(LE,
|
||||
"%s: Error: Inadequate user permissions for service. Service not started.",
|
||||
service->name);
|
||||
service->state = SERVICE_STATE_FAILED;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if(service->ssl_mode != SSL_DISABLED)
|
||||
{
|
||||
if(serviceInitSSL(service) != 0)
|
||||
|
@ -68,4 +68,5 @@ extern char *mysql_users_fetch(USERS *users, MYSQL_USER_HOST *key);
|
||||
extern int replace_mysql_users(SERVICE *service);
|
||||
extern int dbusers_save(USERS *, char *);
|
||||
extern int dbusers_load(USERS *, char *);
|
||||
bool check_service_permissions(SERVICE* service);
|
||||
#endif
|
||||
|
@ -146,4 +146,5 @@ void config_enable_feedback_task(void);
|
||||
void config_disable_feedback_task(void);
|
||||
unsigned long config_get_gateway_id(void);
|
||||
GATEWAY_CONF* config_get_global_options();
|
||||
bool isInternalService(char *router);
|
||||
#endif
|
||||
|
@ -169,4 +169,5 @@ extern void monitorList(DCB *);
|
||||
extern void monitorSetInterval (MONITOR *, unsigned long);
|
||||
extern void monitorSetNetworkTimeout(MONITOR *, int, int);
|
||||
extern RESULTSET *monitorGetList();
|
||||
bool check_monitor_permissions(MONITOR* monitor);
|
||||
#endif
|
||||
|
@ -128,6 +128,12 @@ enum{
|
||||
|
||||
#define DEFAULT_SSL_CERT_VERIFY_DEPTH 100 /*< The default certificate verification depth */
|
||||
|
||||
/**
|
||||
* Parameters that are automatically detected but can also be configured by the
|
||||
* user are initially set to this value.
|
||||
*/
|
||||
#define SERVICE_PARAM_UNINIT -1
|
||||
|
||||
/**
|
||||
* Defines a service within the gateway.
|
||||
*
|
||||
|
@ -2586,8 +2586,8 @@ static bool route_single_stmt(
|
||||
rses_end_locked_router_action(rses);
|
||||
goto retblock;
|
||||
}
|
||||
GWBUF* wbuf = gwbuf_clone(querybuf);
|
||||
if ((ret = target_dcb->func.write(target_dcb, wbuf)) == 1)
|
||||
|
||||
if ((ret = target_dcb->func.write(target_dcb, gwbuf_clone(querybuf))) == 1)
|
||||
{
|
||||
backend_ref_t* bref;
|
||||
|
||||
@ -2601,7 +2601,6 @@ static bool route_single_stmt(
|
||||
}
|
||||
else
|
||||
{
|
||||
gwbuf_free(wbuf);
|
||||
LOGIF((LE|LT), (skygw_log_write_flush(
|
||||
LOGFILE_ERROR,
|
||||
"Error : Routing query failed.")));
|
||||
|
Loading…
x
Reference in New Issue
Block a user