Allow routers to control when users are loaded

The binlogrouter requires that users are not loaded at startup. This
allows it to inject the service user into the list of valid MySQL users so
that the binlogrouter can be controlled via the listeners.
This commit is contained in:
Markus Makela
2016-08-30 16:47:58 +03:00
parent 9a3da88e63
commit 099263709e
6 changed files with 60 additions and 45 deletions

View File

@ -277,9 +277,18 @@ replace_mysql_users(SERV_LISTENER *listener)
if (i <= 0)
{
/** Failed to load users */
if (listener->users)
{
/* Restore old users and resources */
users_free(newusers);
/* Failed to load users, restore old users and resources */
listener->resources = oldresources;
}
else
{
/* No users allocated, use the empty new one */
listener->users = newusers;
}
spinlock_release(&listener->lock);
return i;
}

View File

@ -295,6 +295,7 @@ serviceStartPort(SERVICE *service, SERV_LISTENER *port)
/** Load the authentication users before before starting the listener */
if (port->listener->authfunc.loadusers &&
(service->router->getCapabilities() & RCAP_TYPE_NO_USERS_INIT) == 0 &&
port->listener->authfunc.loadusers(port) != AUTH_LOADUSERS_OK)
{
MXS_ERROR("[%s] Failed to load users for listener '%s', authentication might not work.",

View File

@ -93,9 +93,11 @@ typedef struct router_object
typedef enum router_capability_t
{
RCAP_TYPE_UNDEFINED = 0x00,
RCAP_TYPE_STMT_INPUT = 0x01, /*< statement per buffer */
RCAP_TYPE_PACKET_INPUT = 0x02, /*< data as it was read from DCB */
RCAP_TYPE_NO_RSESSION = 0x04 /*< router does not use router sessions */
RCAP_TYPE_STMT_INPUT = 0x01, /**< Statement per buffer */
RCAP_TYPE_PACKET_INPUT = 0x02, /**< Data as it was read from DCB */
RCAP_TYPE_NO_RSESSION = 0x04, /**< Router does not use router sessions */
RCAP_TYPE_NO_USERS_INIT = 0x08 /**< Prevent the loading of authenticator
users when the service is started */
} router_capability_t;

View File

@ -132,6 +132,8 @@ GWAUTHENTICATOR* GetModuleObject()
*/
static int cdc_auth_check(DCB *dcb, CDC_protocol *protocol, char *username, uint8_t *auth_data,
unsigned int *flags)
{
if (dcb->listener->users)
{
char *user_password = users_fetch(dcb->listener->users, username);
@ -144,13 +146,8 @@ static int cdc_auth_check(DCB *dcb, CDC_protocol *protocol, char *username, uint
gw_sha1_str(auth_data, SHA_DIGEST_LENGTH, sha1_step1);
gw_bin2hex(hex_step1, sha1_step1, SHA_DIGEST_LENGTH);
if (memcmp(user_password, hex_step1, SHA_DIGEST_LENGTH) == 0)
{
return CDC_STATE_AUTH_OK;
}
else
{
return CDC_STATE_AUTH_FAILED;
return memcmp(user_password, hex_step1, SHA_DIGEST_LENGTH) == 0 ?
CDC_STATE_AUTH_OK : CDC_STATE_AUTH_FAILED;
}
}
@ -485,7 +482,7 @@ cdc_read_users(USERS *users, char *usersfile)
*/
int cdc_replace_users(SERV_LISTENER *listener)
{
int rc = AUTH_LOADUSERS_OK;
int rc = AUTH_LOADUSERS_ERROR;
USERS *newusers = users_alloc();
if (newusers)
@ -494,23 +491,29 @@ int cdc_replace_users(SERV_LISTENER *listener)
snprintf(path, PATH_MAX, "%s/%s/cdcusers", get_datadir(), listener->service->name);
int i = cdc_read_users(newusers, path);
USERS *oldusers = NULL;
if (i <= 0)
{
/** Failed to read users or no users loaded */
users_free(newusers);
spinlock_acquire(&listener->lock);
if (i < 0)
if (i > 0)
{
rc = AUTH_LOADUSERS_ERROR;
/** Successfully loaded at least one user */
oldusers = listener->users;
listener->users = newusers;
rc = AUTH_LOADUSERS_OK;
}
else if (listener->users)
{
/** Failed to load users, use the old users table */
users_free(newusers);
}
else
{
spinlock_acquire(&listener->lock);
USERS *oldusers = listener->users;
/** No existing users, use the new empty users table */
listener->users = newusers;
}
cdc_set_service_user(listener);
spinlock_release(&listener->lock);
@ -519,6 +522,5 @@ int cdc_replace_users(SERV_LISTENER *listener)
users_free(oldusers);
}
}
}
return rc;
}

View File

@ -845,9 +845,7 @@ static int mysql_auth_load_users(SERV_LISTENER *port)
if ((loaded = dbusers_load(port->users, path)) == -1)
{
MXS_ERROR("[%s] Failed to load cached users from '%s'.", service->name, path);
users_free(port->users);
port->users = NULL;
MXS_ERROR("[%s] Failed to load cached users from '%s'.", service->name, path);;
rc = AUTH_LOADUSERS_ERROR;
}
else
@ -870,10 +868,13 @@ static int mysql_auth_load_users(SERV_LISTENER *port)
if (loaded == 0)
{
MXS_ERROR("[%s]: failed to load any user information. Authentication"
MXS_WARNING("[%s]: failed to load any user information. Authentication"
" will probably fail as a result.", service->name);
}
else if (loaded > 0)
{
MXS_NOTICE("[%s] Loaded %d MySQL users for listener %s.", service->name, loaded, port->name);
}
return rc;
}

View File

@ -1793,7 +1793,7 @@ static void rses_end_locked_router_action(ROUTER_SLAVE *rses)
static int getCapabilities()
{
return (int)RCAP_TYPE_NO_RSESSION;
return (int)(RCAP_TYPE_NO_RSESSION | RCAP_TYPE_NO_USERS_INIT);
}
/**