Added service and monitor permission checks.
This commit is contained in:
@ -1107,6 +1107,7 @@ process_config_context(CONFIG_CONTEXT *context)
|
|||||||
monitorAddUser(obj->element,
|
monitorAddUser(obj->element,
|
||||||
user,
|
user,
|
||||||
passwd);
|
passwd);
|
||||||
|
valid_monitor_permissions(obj->element);
|
||||||
}
|
}
|
||||||
else if (obj->element && user)
|
else if (obj->element && user)
|
||||||
{
|
{
|
||||||
|
@ -2315,3 +2315,107 @@ int add_wildcard_users(USERS *users, char* name, char* host, char* password, cha
|
|||||||
|
|
||||||
return rval;
|
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
|
||||||
|
*/
|
||||||
|
void valid_service_permissions(SERVICE* service)
|
||||||
|
{
|
||||||
|
MYSQL* mysql;
|
||||||
|
MYSQL_RES* res;
|
||||||
|
char *user,*password,*dpasswd;
|
||||||
|
SERVER_REF* server;
|
||||||
|
int conn_timeout = 1;
|
||||||
|
|
||||||
|
if(service_is_internal(service))
|
||||||
|
return;
|
||||||
|
|
||||||
|
if(service->dbref == NULL)
|
||||||
|
{
|
||||||
|
skygw_log_write(LE,"[%s] Error: Service is missing the servers parameter.",service->name);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
server = service->dbref;
|
||||||
|
|
||||||
|
if (serviceGetUser(service, &user, &password) == 0)
|
||||||
|
{
|
||||||
|
skygw_log_write(LE,"[%s] Error: Service %s is missing the user credentials for authentication.",
|
||||||
|
__FUNCTION__,service->name);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
dpasswd = decryptPassword(password);
|
||||||
|
|
||||||
|
if((mysql = mysql_init(NULL)) == NULL)
|
||||||
|
{
|
||||||
|
skygw_log_write(LE,"[%s] Error: MySQL connection initialization failed.",__FUNCTION__);
|
||||||
|
free(dpasswd);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(mysql_query(mysql,"select * from mysql.user limit 1") != 0)
|
||||||
|
{
|
||||||
|
skygw_log_write(LE,"[%s] Error: Failed to query from mysql.user table. MySQL error message: %s",service->name,mysql_error(mysql));
|
||||||
|
mysql_close(mysql);
|
||||||
|
free(dpasswd);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
mysql_free_result(mysql_use_result(mysql));
|
||||||
|
|
||||||
|
if(mysql_query(mysql,"select * from mysql.db limit 1") != 0)
|
||||||
|
{
|
||||||
|
skygw_log_write(LM|LE,"The user '%s' for service '%s' does not have"
|
||||||
|
" SELECT permissions on the mysql.db table. MaxScale will not use the database in authentication. MySQL error message: %s",
|
||||||
|
user,service->name,mysql_error(mysql));
|
||||||
|
mysql_close(mysql);
|
||||||
|
free(dpasswd);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
mysql_free_result(mysql_use_result(mysql));
|
||||||
|
}
|
||||||
|
|
||||||
|
if(mysql_query(mysql,LOAD_MYSQL_DATABASE_NAMES) != 0)
|
||||||
|
{
|
||||||
|
skygw_log_write(LE,"[%s] Error: Failed to query for SHOW DATABASES permissions. MySQL error message: %s.",service->name,mysql_error(mysql));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
res = mysql_use_result(mysql);
|
||||||
|
if(mysql_num_rows(res) == 0)
|
||||||
|
{
|
||||||
|
skygw_log_write(LM|LE,"The user '%s' for service '%s' does not have"
|
||||||
|
" SHOW DATABASES permissions. MaxScale will not use the database in authentication.",
|
||||||
|
user,service->name);
|
||||||
|
}
|
||||||
|
mysql_free_result(res);
|
||||||
|
}
|
||||||
|
|
||||||
|
mysql_close(mysql);
|
||||||
|
free(dpasswd);
|
||||||
|
}
|
@ -40,6 +40,7 @@
|
|||||||
#include <modules.h>
|
#include <modules.h>
|
||||||
#include <skygw_utils.h>
|
#include <skygw_utils.h>
|
||||||
#include <log_manager.h>
|
#include <log_manager.h>
|
||||||
|
#include <secrets.h>
|
||||||
|
|
||||||
/** Defined in log_manager.cc */
|
/** Defined in log_manager.cc */
|
||||||
extern int lm_enabled_logfiles_bitmask;
|
extern int lm_enabled_logfiles_bitmask;
|
||||||
@ -49,6 +50,8 @@ extern __thread log_info_t tls_log_info;
|
|||||||
static MONITOR *allMonitors = NULL;
|
static MONITOR *allMonitors = NULL;
|
||||||
static SPINLOCK monLock = SPINLOCK_INIT;
|
static SPINLOCK monLock = SPINLOCK_INIT;
|
||||||
|
|
||||||
|
void valid_monitor_permissions(MONITOR* monitor);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Allocate a new monitor, load the associated module for the monitor
|
* Allocate a new monitor, load the associated module for the monitor
|
||||||
* and start execution on the monitor.
|
* and start execution on the monitor.
|
||||||
@ -448,3 +451,58 @@ int *data;
|
|||||||
|
|
||||||
return set;
|
return set;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if the monitor user has all required permissions to operate properly.
|
||||||
|
* this checks for ...
|
||||||
|
* @param service Monitor to inspect
|
||||||
|
*/
|
||||||
|
void valid_monitor_permissions(MONITOR* monitor)
|
||||||
|
{
|
||||||
|
MYSQL* mysql;
|
||||||
|
MYSQL_RES* res;
|
||||||
|
char *user,*dpasswd;
|
||||||
|
SERVER* server;
|
||||||
|
int conn_timeout = 1;
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(mysql_query(mysql,"show slave status") != 0)
|
||||||
|
{
|
||||||
|
skygw_log_write(LE,"[%s] Error: Monitor failed to query for slave status. MySQL error message: %s",monitor->name,mysql_error(mysql));
|
||||||
|
mysql_close(mysql);
|
||||||
|
free(dpasswd);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
mysql_free_result(mysql_use_result(mysql));
|
||||||
|
mysql_close(mysql);
|
||||||
|
free(dpasswd);
|
||||||
|
}
|
@ -438,6 +438,8 @@ if(service->ssl_mode != SSL_DISABLED)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
valid_service_permissions(service);
|
||||||
|
|
||||||
port = service->ports;
|
port = service->ports;
|
||||||
while (!service->svc_do_shutdown && port)
|
while (!service->svc_do_shutdown && port)
|
||||||
{
|
{
|
||||||
@ -456,7 +458,7 @@ if(service->ssl_mode != SSL_DISABLED)
|
|||||||
hktask_add("connection_timeout",session_close_timeouts,NULL,5);
|
hktask_add("connection_timeout",session_close_timeouts,NULL,5);
|
||||||
}
|
}
|
||||||
|
|
||||||
return listeners;
|
return listeners;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -2042,3 +2044,14 @@ int serviceInitSSL(SERVICE* service)
|
|||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if the service is an internal service. Internal services are special
|
||||||
|
* services which do not require the servers parameter.
|
||||||
|
* @param service Service to check
|
||||||
|
* @return True if this service is used only internally
|
||||||
|
*/
|
||||||
|
bool service_is_internal(SERVICE* service)
|
||||||
|
{
|
||||||
|
return strcmp(service->routerModule,"cli") == 0 || strcmp(service->routerModule,"debugcli") == 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 replace_mysql_users(SERVICE *service);
|
||||||
extern int dbusers_save(USERS *, char *);
|
extern int dbusers_save(USERS *, char *);
|
||||||
extern int dbusers_load(USERS *, char *);
|
extern int dbusers_load(USERS *, char *);
|
||||||
|
void valid_service_permissions(SERVICE* service);
|
||||||
#endif
|
#endif
|
||||||
|
@ -169,4 +169,5 @@ extern void monitorList(DCB *);
|
|||||||
extern void monitorSetInterval (MONITOR *, unsigned long);
|
extern void monitorSetInterval (MONITOR *, unsigned long);
|
||||||
extern void monitorSetNetworkTimeout(MONITOR *, int, int);
|
extern void monitorSetNetworkTimeout(MONITOR *, int, int);
|
||||||
extern RESULTSET *monitorGetList();
|
extern RESULTSET *monitorGetList();
|
||||||
|
void valid_monitor_permissions(MONITOR* monitor);
|
||||||
#endif
|
#endif
|
||||||
|
@ -246,4 +246,5 @@ void service_shutdown();
|
|||||||
extern int serviceSessionCountAll();
|
extern int serviceSessionCountAll();
|
||||||
extern RESULTSET *serviceGetList();
|
extern RESULTSET *serviceGetList();
|
||||||
extern RESULTSET *serviceGetListenerList();
|
extern RESULTSET *serviceGetListenerList();
|
||||||
|
bool service_is_internal(SERVICE* service);
|
||||||
#endif
|
#endif
|
||||||
|
Reference in New Issue
Block a user