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:
@ -277,9 +277,18 @@ replace_mysql_users(SERV_LISTENER *listener)
|
|||||||
|
|
||||||
if (i <= 0)
|
if (i <= 0)
|
||||||
{
|
{
|
||||||
users_free(newusers);
|
/** Failed to load users */
|
||||||
/* Failed to load users, restore old users and resources */
|
if (listener->users)
|
||||||
listener->resources = oldresources;
|
{
|
||||||
|
/* Restore old users and resources */
|
||||||
|
users_free(newusers);
|
||||||
|
listener->resources = oldresources;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* No users allocated, use the empty new one */
|
||||||
|
listener->users = newusers;
|
||||||
|
}
|
||||||
spinlock_release(&listener->lock);
|
spinlock_release(&listener->lock);
|
||||||
return i;
|
return i;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -295,6 +295,7 @@ serviceStartPort(SERVICE *service, SERV_LISTENER *port)
|
|||||||
|
|
||||||
/** Load the authentication users before before starting the listener */
|
/** Load the authentication users before before starting the listener */
|
||||||
if (port->listener->authfunc.loadusers &&
|
if (port->listener->authfunc.loadusers &&
|
||||||
|
(service->router->getCapabilities() & RCAP_TYPE_NO_USERS_INIT) == 0 &&
|
||||||
port->listener->authfunc.loadusers(port) != AUTH_LOADUSERS_OK)
|
port->listener->authfunc.loadusers(port) != AUTH_LOADUSERS_OK)
|
||||||
{
|
{
|
||||||
MXS_ERROR("[%s] Failed to load users for listener '%s', authentication might not work.",
|
MXS_ERROR("[%s] Failed to load users for listener '%s', authentication might not work.",
|
||||||
|
|||||||
@ -92,10 +92,12 @@ typedef struct router_object
|
|||||||
*/
|
*/
|
||||||
typedef enum router_capability_t
|
typedef enum router_capability_t
|
||||||
{
|
{
|
||||||
RCAP_TYPE_UNDEFINED = 0x00,
|
RCAP_TYPE_UNDEFINED = 0x00,
|
||||||
RCAP_TYPE_STMT_INPUT = 0x01, /*< statement per buffer */
|
RCAP_TYPE_STMT_INPUT = 0x01, /**< Statement per buffer */
|
||||||
RCAP_TYPE_PACKET_INPUT = 0x02, /*< data as it was read from DCB */
|
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_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;
|
} router_capability_t;
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -133,24 +133,21 @@ GWAUTHENTICATOR* GetModuleObject()
|
|||||||
static int cdc_auth_check(DCB *dcb, CDC_protocol *protocol, char *username, uint8_t *auth_data,
|
static int cdc_auth_check(DCB *dcb, CDC_protocol *protocol, char *username, uint8_t *auth_data,
|
||||||
unsigned int *flags)
|
unsigned int *flags)
|
||||||
{
|
{
|
||||||
char *user_password = users_fetch(dcb->listener->users, username);
|
if (dcb->listener->users)
|
||||||
|
|
||||||
if (user_password)
|
|
||||||
{
|
{
|
||||||
/* compute SHA1 of auth_data */
|
char *user_password = users_fetch(dcb->listener->users, username);
|
||||||
uint8_t sha1_step1[SHA_DIGEST_LENGTH] = "";
|
|
||||||
char hex_step1[2 * SHA_DIGEST_LENGTH + 1] = "";
|
|
||||||
|
|
||||||
gw_sha1_str(auth_data, SHA_DIGEST_LENGTH, sha1_step1);
|
if (user_password)
|
||||||
gw_bin2hex(hex_step1, sha1_step1, SHA_DIGEST_LENGTH);
|
{
|
||||||
|
/* compute SHA1 of auth_data */
|
||||||
|
uint8_t sha1_step1[SHA_DIGEST_LENGTH] = "";
|
||||||
|
char hex_step1[2 * SHA_DIGEST_LENGTH + 1] = "";
|
||||||
|
|
||||||
if (memcmp(user_password, hex_step1, SHA_DIGEST_LENGTH) == 0)
|
gw_sha1_str(auth_data, SHA_DIGEST_LENGTH, sha1_step1);
|
||||||
{
|
gw_bin2hex(hex_step1, sha1_step1, SHA_DIGEST_LENGTH);
|
||||||
return CDC_STATE_AUTH_OK;
|
|
||||||
}
|
return memcmp(user_password, hex_step1, SHA_DIGEST_LENGTH) == 0 ?
|
||||||
else
|
CDC_STATE_AUTH_OK : CDC_STATE_AUTH_FAILED;
|
||||||
{
|
|
||||||
return CDC_STATE_AUTH_FAILED;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -485,7 +482,7 @@ cdc_read_users(USERS *users, char *usersfile)
|
|||||||
*/
|
*/
|
||||||
int cdc_replace_users(SERV_LISTENER *listener)
|
int cdc_replace_users(SERV_LISTENER *listener)
|
||||||
{
|
{
|
||||||
int rc = AUTH_LOADUSERS_OK;
|
int rc = AUTH_LOADUSERS_ERROR;
|
||||||
USERS *newusers = users_alloc();
|
USERS *newusers = users_alloc();
|
||||||
|
|
||||||
if (newusers)
|
if (newusers)
|
||||||
@ -494,30 +491,35 @@ int cdc_replace_users(SERV_LISTENER *listener)
|
|||||||
snprintf(path, PATH_MAX, "%s/%s/cdcusers", get_datadir(), listener->service->name);
|
snprintf(path, PATH_MAX, "%s/%s/cdcusers", get_datadir(), listener->service->name);
|
||||||
|
|
||||||
int i = cdc_read_users(newusers, path);
|
int i = cdc_read_users(newusers, path);
|
||||||
|
USERS *oldusers = NULL;
|
||||||
|
|
||||||
if (i <= 0)
|
spinlock_acquire(&listener->lock);
|
||||||
|
|
||||||
|
if (i > 0)
|
||||||
{
|
{
|
||||||
/** Failed to read users or no users loaded */
|
/** 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);
|
users_free(newusers);
|
||||||
|
|
||||||
if (i < 0)
|
|
||||||
{
|
|
||||||
rc = AUTH_LOADUSERS_ERROR;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
spinlock_acquire(&listener->lock);
|
/** No existing users, use the new empty users table */
|
||||||
|
|
||||||
USERS *oldusers = listener->users;
|
|
||||||
listener->users = newusers;
|
listener->users = newusers;
|
||||||
|
}
|
||||||
|
|
||||||
spinlock_release(&listener->lock);
|
cdc_set_service_user(listener);
|
||||||
|
|
||||||
if (oldusers)
|
spinlock_release(&listener->lock);
|
||||||
{
|
|
||||||
users_free(oldusers);
|
if (oldusers)
|
||||||
}
|
{
|
||||||
|
users_free(oldusers);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return rc;
|
return rc;
|
||||||
|
|||||||
@ -845,9 +845,7 @@ static int mysql_auth_load_users(SERV_LISTENER *port)
|
|||||||
|
|
||||||
if ((loaded = dbusers_load(port->users, path)) == -1)
|
if ((loaded = dbusers_load(port->users, path)) == -1)
|
||||||
{
|
{
|
||||||
MXS_ERROR("[%s] Failed to load cached users from '%s'.", service->name, path);
|
MXS_ERROR("[%s] Failed to load cached users from '%s'.", service->name, path);;
|
||||||
users_free(port->users);
|
|
||||||
port->users = NULL;
|
|
||||||
rc = AUTH_LOADUSERS_ERROR;
|
rc = AUTH_LOADUSERS_ERROR;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -870,10 +868,13 @@ static int mysql_auth_load_users(SERV_LISTENER *port)
|
|||||||
|
|
||||||
if (loaded == 0)
|
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);
|
" 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);
|
||||||
}
|
}
|
||||||
|
|
||||||
MXS_NOTICE("[%s] Loaded %d MySQL users for listener %s.", service->name, loaded, port->name);
|
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1793,7 +1793,7 @@ static void rses_end_locked_router_action(ROUTER_SLAVE *rses)
|
|||||||
|
|
||||||
static int getCapabilities()
|
static int getCapabilities()
|
||||||
{
|
{
|
||||||
return (int)RCAP_TYPE_NO_RSESSION;
|
return (int)(RCAP_TYPE_NO_RSESSION | RCAP_TYPE_NO_USERS_INIT);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
Reference in New Issue
Block a user