Uncrustify maxscale

See script directory for method. The script to run in the top level
MaxScale directory is called maxscale-uncrustify.sh, which uses
another script, list-src, from the same directory (so you need to set
your PATH). The uncrustify version was 0.66.
This commit is contained in:
Niclas Antti
2018-09-09 22:26:19 +03:00
parent fa7ec95069
commit c447e5cf15
849 changed files with 35002 additions and 27238 deletions

View File

@ -47,28 +47,26 @@
const char CDC_USERS_FILENAME[] = "cdcusers";
static bool cdc_auth_set_protocol_data(DCB *dcb, GWBUF *buf);
static bool cdc_auth_is_client_ssl_capable(DCB *dcb);
static int cdc_auth_authenticate(DCB *dcb);
static void cdc_auth_free_client_data(DCB *dcb);
static bool cdc_auth_set_protocol_data(DCB* dcb, GWBUF* buf);
static bool cdc_auth_is_client_ssl_capable(DCB* dcb);
static int cdc_auth_authenticate(DCB* dcb);
static void cdc_auth_free_client_data(DCB* dcb);
static int cdc_set_service_user(SERV_LISTENER *listener);
static int cdc_replace_users(SERV_LISTENER *listener);
static int cdc_set_service_user(SERV_LISTENER* listener);
static int cdc_replace_users(SERV_LISTENER* listener);
static int cdc_auth_check(
DCB *dcb,
CDC_protocol *protocol,
char *username,
uint8_t *auth_data,
unsigned int *flags
);
static int cdc_auth_check(DCB* dcb,
CDC_protocol* protocol,
char* username,
uint8_t* auth_data,
unsigned int* flags
);
static bool cdc_auth_set_client_data(
CDC_session *client_data,
CDC_protocol *protocol,
uint8_t *client_auth_packet,
int client_auth_packet_size
);
static bool cdc_auth_set_client_data(CDC_session* client_data,
CDC_protocol* protocol,
uint8_t* client_auth_packet,
int client_auth_packet_size
);
/**
* @brief Add a new CDC user
@ -79,24 +77,24 @@ static bool cdc_auth_set_client_data(
* @param args Arguments for this command
* @return True if user was successfully added
*/
static bool cdc_add_new_user(const MODULECMD_ARG *args, json_t** output)
static bool cdc_add_new_user(const MODULECMD_ARG* args, json_t** output)
{
const char *user = args->argv[1].value.string;
const char* user = args->argv[1].value.string;
size_t userlen = strlen(user);
const char *password = args->argv[2].value.string;
const char* password = args->argv[2].value.string;
uint8_t phase1[SHA_DIGEST_LENGTH];
uint8_t phase2[SHA_DIGEST_LENGTH];
SHA1((uint8_t*)password, strlen(password), phase1);
SHA1(phase1, sizeof(phase1), phase2);
size_t data_size = userlen + 2 + SHA_DIGEST_LENGTH * 2; // Extra for the : and newline
size_t data_size = userlen + 2 + SHA_DIGEST_LENGTH * 2; // Extra for the : and newline
char final_data[data_size];
strcpy(final_data, user);
strcat(final_data, ":");
gw_bin2hex(final_data + userlen + 1, phase2, sizeof(phase2));
final_data[data_size - 1] = '\n';
SERVICE *service = args->argv[0].value.service;
SERVICE* service = args->argv[0].value.service;
char path[PATH_MAX + 1];
snprintf(path, PATH_MAX, "%s/%s/", get_datadir(), service->name);
bool rval = false;
@ -115,7 +113,7 @@ static bool cdc_add_new_user(const MODULECMD_ARG *args, json_t** output)
}
else
{
const char *real_err = mxs_strerror(errno);
const char* real_err = mxs_strerror(errno);
MXS_NOTICE("Failed to write to file '%s': %s", path, real_err);
modulecmd_set_error("Failed to write to file '%s': %s", path, real_err);
}
@ -124,7 +122,7 @@ static bool cdc_add_new_user(const MODULECMD_ARG *args, json_t** output)
}
else
{
const char *real_err = mxs_strerror(errno);
const char* real_err = mxs_strerror(errno);
MXS_NOTICE("Failed to open file '%s': %s", path, real_err);
modulecmd_set_error("Failed to open file '%s': %s", path, real_err);
}
@ -132,7 +130,8 @@ static bool cdc_add_new_user(const MODULECMD_ARG *args, json_t** output)
else
{
modulecmd_set_error("Failed to create directory '%s'. Read the MaxScale "
"log for more details.", path);
"log for more details.",
path);
}
return rval;
@ -148,53 +147,56 @@ extern "C"
*
* @return The module object
*/
MXS_MODULE* MXS_CREATE_MODULE()
{
static modulecmd_arg_type_t args[] =
MXS_MODULE* MXS_CREATE_MODULE()
{
{ MODULECMD_ARG_SERVICE, "Service where the user is added"},
{ MODULECMD_ARG_STRING, "User to add"},
{ MODULECMD_ARG_STRING, "Password of the user"}
};
static modulecmd_arg_type_t args[] =
{
{MODULECMD_ARG_SERVICE, "Service where the user is added" },
{MODULECMD_ARG_STRING, "User to add" },
{MODULECMD_ARG_STRING, "Password of the user" }
};
modulecmd_register_command("cdc", "add_user", MODULECMD_TYPE_ACTIVE,
cdc_add_new_user, 3, args,
"Add a new CDC user");
modulecmd_register_command("cdc",
"add_user",
MODULECMD_TYPE_ACTIVE,
cdc_add_new_user,
3,
args,
"Add a new CDC user");
static MXS_AUTHENTICATOR MyObject =
{
NULL, /* No initialize entry point */
NULL, /* No create entry point */
cdc_auth_set_protocol_data, /* Extract data into structure */
cdc_auth_is_client_ssl_capable, /* Check if client supports SSL */
cdc_auth_authenticate, /* Authenticate user credentials */
cdc_auth_free_client_data, /* Free the client data held in DCB */
NULL, /* No destroy entry point */
cdc_replace_users, /* Load CDC users */
users_default_diagnostic, /* Default diagnostic */
users_default_diagnostic_json, /* Default diagnostic */
NULL /* No user reauthentication */
};
static MXS_AUTHENTICATOR MyObject =
{
NULL, /* No initialize entry point */
NULL, /* No create entry point */
cdc_auth_set_protocol_data, /* Extract data into structure */
cdc_auth_is_client_ssl_capable, /* Check if client supports SSL */
cdc_auth_authenticate, /* Authenticate user credentials */
cdc_auth_free_client_data, /* Free the client data held in DCB */
NULL, /* No destroy entry point */
cdc_replace_users, /* Load CDC users */
users_default_diagnostic, /* Default diagnostic */
users_default_diagnostic_json, /* Default diagnostic */
NULL /* No user reauthentication */
};
static MXS_MODULE info =
{
MXS_MODULE_API_AUTHENTICATOR,
MXS_MODULE_GA,
MXS_AUTHENTICATOR_VERSION,
"The CDC client to MaxScale authenticator implementation",
"V1.1.0",
MXS_NO_MODULE_CAPABILITIES,
&MyObject,
NULL, /* Process init. */
NULL, /* Process finish. */
NULL, /* Thread init. */
NULL, /* Thread finish. */
{ { MXS_END_MODULE_PARAMS} }
};
return &info;
}
static MXS_MODULE info =
{
MXS_MODULE_API_AUTHENTICATOR,
MXS_MODULE_GA,
MXS_AUTHENTICATOR_VERSION,
"The CDC client to MaxScale authenticator implementation",
"V1.1.0",
MXS_NO_MODULE_CAPABILITIES,
&MyObject,
NULL, /* Process init. */
NULL, /* Process finish. */
NULL, /* Thread init. */
NULL, /* Thread finish. */
{{MXS_END_MODULE_PARAMS}}
};
return &info;
}
}
/**
@ -207,8 +209,11 @@ MXS_MODULE* MXS_CREATE_MODULE()
* @return Authentication status
* @note Authentication status codes are defined in cdc.h
*/
static int cdc_auth_check(DCB *dcb, CDC_protocol *protocol, char *username,
uint8_t *auth_data, unsigned int *flags)
static int cdc_auth_check(DCB* dcb,
CDC_protocol* protocol,
char* username,
uint8_t* auth_data,
unsigned int* flags)
{
int rval = CDC_STATE_AUTH_FAILED;
@ -237,11 +242,10 @@ static int cdc_auth_check(DCB *dcb, CDC_protocol *protocol, char *username,
* @return Authentication status
* @note Authentication status codes are defined in cdc.h
*/
static int
cdc_auth_authenticate(DCB *dcb)
static int cdc_auth_authenticate(DCB* dcb)
{
CDC_protocol *protocol = DCB_PROTOCOL(dcb, CDC_protocol);
CDC_session *client_data = (CDC_session *)dcb->data;
CDC_protocol* protocol = DCB_PROTOCOL(dcb, CDC_protocol);
CDC_session* client_data = (CDC_session*)dcb->data;
int auth_ret;
if (0 == strlen(client_data->user))
@ -253,12 +257,17 @@ cdc_auth_authenticate(DCB *dcb)
MXS_DEBUG("Receiving connection from '%s'",
client_data->user);
auth_ret = cdc_auth_check(dcb, protocol, client_data->user, client_data->auth_data, client_data->flags);
auth_ret
= cdc_auth_check(dcb, protocol, client_data->user, client_data->auth_data, client_data->flags);
/* On failed authentication try to reload users and authenticate again */
if (CDC_STATE_AUTH_OK != auth_ret && cdc_replace_users(dcb->listener) == MXS_AUTH_LOADUSERS_OK)
{
auth_ret = cdc_auth_check(dcb, protocol, client_data->user, client_data->auth_data, client_data->flags);
auth_ret = cdc_auth_check(dcb,
protocol,
client_data->user,
client_data->auth_data,
client_data->flags);
}
/* on successful authentication, set user into dcb field */
@ -270,7 +279,8 @@ cdc_auth_authenticate(DCB *dcb)
{
MXS_LOG_EVENT(maxscale::event::AUTHENTICATION_FAILURE,
"%s: login attempt for user '%s', authentication failed.",
dcb->service->name, client_data->user);
dcb->service->name,
client_data->user);
}
}
@ -291,18 +301,17 @@ cdc_auth_authenticate(DCB *dcb)
* @param buffer Pointer to pointer to buffer containing data from client
* @return True on success, false on error
*/
static bool
cdc_auth_set_protocol_data(DCB *dcb, GWBUF *buf)
static bool cdc_auth_set_protocol_data(DCB* dcb, GWBUF* buf)
{
uint8_t *client_auth_packet = GWBUF_DATA(buf);
CDC_protocol *protocol = NULL;
CDC_session *client_data = NULL;
uint8_t* client_auth_packet = GWBUF_DATA(buf);
CDC_protocol* protocol = NULL;
CDC_session* client_data = NULL;
int client_auth_packet_size = 0;
protocol = DCB_PROTOCOL(dcb, CDC_protocol);
if (dcb->data == NULL)
{
if (NULL == (client_data = (CDC_session *)MXS_CALLOC(1, sizeof(CDC_session))))
if (NULL == (client_data = (CDC_session*)MXS_CALLOC(1, sizeof(CDC_session))))
{
return false;
}
@ -310,12 +319,14 @@ cdc_auth_set_protocol_data(DCB *dcb, GWBUF *buf)
}
else
{
client_data = (CDC_session *)dcb->data;
client_data = (CDC_session*)dcb->data;
}
client_auth_packet_size = gwbuf_length(buf);
return cdc_auth_set_client_data(client_data, protocol, client_auth_packet,
return cdc_auth_set_client_data(client_data,
protocol,
client_auth_packet,
client_auth_packet_size);
}
@ -332,11 +343,10 @@ cdc_auth_set_protocol_data(DCB *dcb, GWBUF *buf)
* @param client_auth_packet size An integer giving the size of the data
* @return True on success, false on error
*/
static bool
cdc_auth_set_client_data(CDC_session *client_data,
CDC_protocol *protocol,
uint8_t *client_auth_packet,
int client_auth_packet_size)
static bool cdc_auth_set_client_data(CDC_session* client_data,
CDC_protocol* protocol,
uint8_t* client_auth_packet,
int client_auth_packet_size)
{
if (client_auth_packet_size % 2 != 0)
{
@ -346,15 +356,16 @@ cdc_auth_set_client_data(CDC_session *client_data,
bool rval = false;
int decoded_size = client_auth_packet_size / 2;
char decoded_buffer[decoded_size + 1]; // Extra for terminating null
char decoded_buffer[decoded_size + 1]; // Extra for terminating null
/* decode input data */
if (client_auth_packet_size <= CDC_USER_MAXLEN)
{
gw_hex2bin((uint8_t*)decoded_buffer, (const char *)client_auth_packet,
gw_hex2bin((uint8_t*)decoded_buffer,
(const char*)client_auth_packet,
client_auth_packet_size);
decoded_buffer[decoded_size] = '\0';
char *tmp_ptr = strchr(decoded_buffer, ':');
char* tmp_ptr = strchr(decoded_buffer, ':');
if (tmp_ptr)
{
@ -378,7 +389,8 @@ cdc_auth_set_client_data(CDC_session *client_data,
else
{
MXS_ERROR("Authentication failed, client authentication packet length "
"exceeds the maximum allowed length of %d bytes.", CDC_USER_MAXLEN);
"exceeds the maximum allowed length of %d bytes.",
CDC_USER_MAXLEN);
}
return rval;
@ -394,8 +406,7 @@ cdc_auth_set_client_data(CDC_session *client_data,
* @param dcb Request handler DCB connected to the client
* @return Boolean indicating whether client is SSL capable
*/
static bool
cdc_auth_is_client_ssl_capable(DCB *dcb)
static bool cdc_auth_is_client_ssl_capable(DCB* dcb)
{
return false;
}
@ -412,8 +423,7 @@ cdc_auth_is_client_ssl_capable(DCB *dcb)
*
* @param dcb Request handler DCB connected to the client
*/
static void
cdc_auth_free_client_data(DCB *dcb)
static void cdc_auth_free_client_data(DCB* dcb)
{
MXS_FREE(dcb->data);
}
@ -425,14 +435,13 @@ cdc_auth_free_client_data(DCB *dcb)
* @param service The current service
* @return 0 on success, 1 on failure
*/
static int
cdc_set_service_user(SERV_LISTENER *listener)
static int cdc_set_service_user(SERV_LISTENER* listener)
{
SERVICE *service = listener->service;
char *dpwd = NULL;
char *newpasswd = NULL;
const char *service_user = NULL;
const char *service_passwd = NULL;
SERVICE* service = listener->service;
char* dpwd = NULL;
char* newpasswd = NULL;
const char* service_user = NULL;
const char* service_passwd = NULL;
serviceGetUser(service, &service_user, &service_passwd);
dpwd = decrypt_password(service_passwd);
@ -477,13 +486,12 @@ cdc_set_service_user(SERV_LISTENER *listener)
* @return -1 on error or users loaded (including 0)
*/
static int
cdc_read_users(USERS *users, char *usersfile)
static int cdc_read_users(USERS* users, char* usersfile)
{
FILE *fp;
FILE* fp;
int loaded = 0;
char *avro_user;
char *user_passwd;
char* avro_user;
char* user_passwd;
/* user maxlen ':' password hash '\n' '\0' */
char read_buffer[CDC_USER_MAXLEN + 1 + SHA_DIGEST_LENGTH + 1 + 1];
@ -498,7 +506,7 @@ cdc_read_users(USERS *users, char *usersfile)
{
if (fgets(read_buffer, max_line_size, fp) != NULL)
{
char *tmp_ptr = read_buffer;
char* tmp_ptr = read_buffer;
if ((tmp_ptr = strchr(read_buffer, ':')) != NULL)
{
@ -528,19 +536,23 @@ cdc_read_users(USERS *users, char *usersfile)
*
* @param service The current service
*/
int cdc_replace_users(SERV_LISTENER *listener)
int cdc_replace_users(SERV_LISTENER* listener)
{
int rc = MXS_AUTH_LOADUSERS_ERROR;
USERS *newusers = users_alloc();
USERS* newusers = users_alloc();
if (newusers)
{
char path[PATH_MAX + 1];
snprintf(path, PATH_MAX, "%s/%s/%s", get_datadir(), listener->service->name,
snprintf(path,
PATH_MAX,
"%s/%s/%s",
get_datadir(),
listener->service->name,
CDC_USERS_FILENAME);
int i = cdc_read_users(newusers, path);
USERS *oldusers = NULL;
USERS* oldusers = NULL;
spinlock_acquire(&listener->lock);

View File

@ -33,15 +33,15 @@
*/
/** Query that gets all users that authenticate via the gssapi plugin */
const char *gssapi_users_query =
"SELECT u.user, u.host, d.db, u.select_priv, u.authentication_string FROM "
"mysql.user AS u LEFT JOIN mysql.db AS d "
"ON (u.user = d.user AND u.host = d.host) WHERE u.plugin = 'gssapi' "
"UNION "
"SELECT u.user, u.host, t.db, u.select_priv, u.authentication_string FROM "
"mysql.user AS u LEFT JOIN mysql.tables_priv AS t "
"ON (u.user = t.user AND u.host = t.host) WHERE u.plugin = 'gssapi' "
"ORDER BY user";
const char* gssapi_users_query
= "SELECT u.user, u.host, d.db, u.select_priv, u.authentication_string FROM "
"mysql.user AS u LEFT JOIN mysql.db AS d "
"ON (u.user = d.user AND u.host = d.host) WHERE u.plugin = 'gssapi' "
"UNION "
"SELECT u.user, u.host, t.db, u.select_priv, u.authentication_string FROM "
"mysql.user AS u LEFT JOIN mysql.tables_priv AS t "
"ON (u.user = t.user AND u.host = t.host) WHERE u.plugin = 'gssapi' "
"ORDER BY user";
#define GSSAPI_USERS_QUERY_NUM_FIELDS 5
@ -53,18 +53,18 @@ const char *gssapi_users_query =
#define GSSAPI_DATABASE_NAME "file:gssapi.db?mode=memory&cache=shared"
/** The table name where we store the users */
#define GSSAPI_TABLE_NAME "gssapi_users"
#define GSSAPI_TABLE_NAME "gssapi_users"
/** CREATE TABLE statement for the in-memory table */
const char create_sql[] =
"CREATE TABLE IF NOT EXISTS " GSSAPI_TABLE_NAME
"(user varchar(255), host varchar(255), db varchar(255), anydb boolean, princ text)";
const char create_sql[]
= "CREATE TABLE IF NOT EXISTS " GSSAPI_TABLE_NAME
"(user varchar(255), host varchar(255), db varchar(255), anydb boolean, princ text)";
/** The query that is executed when a user is authenticated */
static const char gssapi_auth_query[] =
"SELECT * FROM " GSSAPI_TABLE_NAME
" WHERE user = '%s' AND '%s' LIKE host AND (anydb = '1' OR '%s' = '' OR '%s' LIKE db)"
" AND ('%s' = '%s' OR princ = '%s') LIMIT 1";
static const char gssapi_auth_query[]
= "SELECT * FROM " GSSAPI_TABLE_NAME
" WHERE user = '%s' AND '%s' LIKE host AND (anydb = '1' OR '%s' = '' OR '%s' LIKE db)"
" AND ('%s' = '%s' OR princ = '%s') LIMIT 1";
/** Delete query used to clean up the database before loading new users */
static const char delete_query[] = "DELETE FROM " GSSAPI_TABLE_NAME;
@ -75,24 +75,24 @@ static const char delete_query[] = "DELETE FROM " GSSAPI_TABLE_NAME;
* Note that the last two values are strings that can be NULL and thus they have
* no quoted around them. The quotes for strings are added in add_gssapi_user().
*/
static const char insert_sql_pattern[] =
"INSERT INTO " GSSAPI_TABLE_NAME " VALUES ('%s', '%s', %s, %s, %s)";
static const char insert_sql_pattern[]
= "INSERT INTO " GSSAPI_TABLE_NAME " VALUES ('%s', '%s', %s, %s, %s)";
/** Used for NULL value creation in the INSERT query */
static const char null_token[] = "NULL";
/** Flags for sqlite3_open_v2() */
static int db_flags = SQLITE_OPEN_READWRITE |
SQLITE_OPEN_CREATE |
SQLITE_OPEN_URI |
SQLITE_OPEN_SHAREDCACHE;
static int db_flags = SQLITE_OPEN_READWRITE
| SQLITE_OPEN_CREATE
| SQLITE_OPEN_URI
| SQLITE_OPEN_SHAREDCACHE;
/** The instance structure for the client side GSSAPI authenticator, created in
* gssapi_auth_init() */
typedef struct gssapi_instance
{
char *principal_name; /**< Service principal name given to the client */
sqlite3 *handle; /**< SQLite3 database handle */
char* principal_name;/**< Service principal name given to the client */
sqlite3* handle; /**< SQLite3 database handle */
} GSSAPI_INSTANCE;
/**
@ -104,9 +104,9 @@ typedef struct gssapi_instance
* @param options Listener options
* @return Authenticator instance
*/
void* gssapi_auth_init(char **options)
void* gssapi_auth_init(char** options)
{
GSSAPI_INSTANCE *instance = static_cast<GSSAPI_INSTANCE*>(MXS_MALLOC(sizeof(GSSAPI_INSTANCE)));
GSSAPI_INSTANCE* instance = static_cast<GSSAPI_INSTANCE*>(MXS_MALLOC(sizeof(GSSAPI_INSTANCE)));
if (instance)
{
@ -119,7 +119,7 @@ void* gssapi_auth_init(char **options)
return NULL;
}
char *err;
char* err;
if (sqlite3_exec(instance->handle, create_sql, NULL, NULL, &err) != SQLITE_OK)
{
@ -134,7 +134,7 @@ void* gssapi_auth_init(char **options)
{
if (strstr(options[i], "principal_name"))
{
char *ptr = strchr(options[i], '=');
char* ptr = strchr(options[i], '=');
if (ptr)
{
ptr++;
@ -160,7 +160,7 @@ void* gssapi_auth_init(char **options)
return instance;
}
void* gssapi_auth_alloc(void *instance)
void* gssapi_auth_alloc(void* instance)
{
gssapi_auth_t* rval = static_cast<gssapi_auth_t*>(MXS_MALLOC(sizeof(gssapi_auth_t)));
@ -186,11 +186,11 @@ void* gssapi_auth_alloc(void *instance)
return rval;
}
void gssapi_auth_free(void *data)
void gssapi_auth_free(void* data)
{
if (data)
{
gssapi_auth_t *auth = (gssapi_auth_t*)data;
gssapi_auth_t* auth = (gssapi_auth_t*)data;
sqlite3_close_v2(auth->handle);
MXS_FREE(auth->principal_name);
MXS_FREE(auth);
@ -206,25 +206,26 @@ void gssapi_auth_free(void *data)
* GSSAPI server in order for the client to be able to request a token.
*
* @return Allocated packet or NULL if memory allocation failed
* @see https://dev.mysql.com/doc/internals/en/connection-phase-packets.html#packet-Protocol::AuthSwitchRequest
* @see
*https://dev.mysql.com/doc/internals/en/connection-phase-packets.html#packet-Protocol::AuthSwitchRequest
* @see https://web.mit.edu/kerberos/krb5-1.5/krb5-1.5.4/doc/krb5-user/What-is-a-Kerberos-Principal_003f.html
*/
static GWBUF* create_auth_change_packet(GSSAPI_INSTANCE *instance, gssapi_auth_t *auth)
static GWBUF* create_auth_change_packet(GSSAPI_INSTANCE* instance, gssapi_auth_t* auth)
{
size_t principal_name_len = strlen(instance->principal_name);
size_t plen = sizeof(auth_plugin_name) + 1 + principal_name_len;
GWBUF *buffer = gwbuf_alloc(plen + MYSQL_HEADER_LEN);
GWBUF* buffer = gwbuf_alloc(plen + MYSQL_HEADER_LEN);
if (buffer)
{
uint8_t *data = (uint8_t*)GWBUF_DATA(buffer);
uint8_t* data = (uint8_t*)GWBUF_DATA(buffer);
gw_mysql_set_byte3(data, plen);
data += 3;
*data++ = ++auth->sequence; // Second packet
*data++ = 0xfe; // AuthSwitchRequest command
memcpy(data, auth_plugin_name, sizeof(auth_plugin_name)); // Plugin name
*data++ = ++auth->sequence; // Second packet
*data++ = 0xfe; // AuthSwitchRequest command
memcpy(data, auth_plugin_name, sizeof(auth_plugin_name)); // Plugin name
data += sizeof(auth_plugin_name);
memcpy(data, instance->principal_name, principal_name_len); // Plugin data
memcpy(data, instance->principal_name, principal_name_len); // Plugin data
}
return buffer;
@ -240,7 +241,7 @@ static GWBUF* create_auth_change_packet(GSSAPI_INSTANCE *instance, gssapi_auth_t
* @param buffer Buffer containing the key
* @return True on success, false if memory allocation failed
*/
bool store_client_token(DCB *dcb, GWBUF *buffer)
bool store_client_token(DCB* dcb, GWBUF* buffer)
{
bool rval = false;
uint8_t hdr[MYSQL_HEADER_LEN];
@ -248,7 +249,7 @@ bool store_client_token(DCB *dcb, GWBUF *buffer)
if (gwbuf_copy_data(buffer, 0, MYSQL_HEADER_LEN, hdr) == MYSQL_HEADER_LEN)
{
size_t plen = gw_mysql_get_byte3(hdr);
MYSQL_session *ses = (MYSQL_session*)dcb->data;
MYSQL_session* ses = (MYSQL_session*)dcb->data;
if ((ses->auth_token = static_cast<uint8_t*>(MXS_MALLOC(plen))))
{
@ -266,9 +267,9 @@ bool store_client_token(DCB *dcb, GWBUF *buffer)
* @param dcb Client DCB
* @param buffer Buffer containing the first authentication response
*/
static void copy_client_information(DCB *dcb, GWBUF *buffer)
static void copy_client_information(DCB* dcb, GWBUF* buffer)
{
gssapi_auth_t *auth = (gssapi_auth_t*)dcb->authenticator_data;
gssapi_auth_t* auth = (gssapi_auth_t*)dcb->authenticator_data;
gwbuf_copy_data(buffer, MYSQL_SEQ_OFFSET, 1, &auth->sequence);
}
@ -279,10 +280,10 @@ static void copy_client_information(DCB *dcb, GWBUF *buffer)
* @param read_buffer Buffer containing the client's response
* @return True if authentication can continue, false if not
*/
static bool gssapi_auth_extract(DCB *dcb, GWBUF *read_buffer)
static bool gssapi_auth_extract(DCB* dcb, GWBUF* read_buffer)
{
int rval = false;
gssapi_auth_t *auth = (gssapi_auth_t*)dcb->authenticator_data;
gssapi_auth_t* auth = (gssapi_auth_t*)dcb->authenticator_data;
switch (auth->state)
{
@ -311,9 +312,9 @@ static bool gssapi_auth_extract(DCB *dcb, GWBUF *read_buffer)
* @param dcb Client DCB
* @return True if client supports SSL
*/
bool gssapi_auth_connectssl(DCB *dcb)
bool gssapi_auth_connectssl(DCB* dcb)
{
MySQLProtocol *protocol = (MySQLProtocol*)dcb->protocol;
MySQLProtocol* protocol = (MySQLProtocol*)dcb->protocol;
return protocol->client_capabilities & GW_MYSQL_CAPABILITIES_SSL;
}
@ -327,7 +328,7 @@ static gss_name_t server_name = GSS_C_NO_NAME;
* @param output Pointer where the client principal name is stored
* @return True if client token is valid
*/
static bool validate_gssapi_token(char* principal, uint8_t* token, size_t len, char **output)
static bool validate_gssapi_token(char* principal, uint8_t* token, size_t len, char** output)
{
OM_uint32 major = 0, minor = 0;
gss_buffer_desc server_buf = {0, 0};
@ -344,9 +345,14 @@ static bool validate_gssapi_token(char* principal, uint8_t* token, size_t len, c
return false;
}
major = gss_acquire_cred(&minor, server_name, GSS_C_INDEFINITE,
GSS_C_NO_OID_SET, GSS_C_ACCEPT,
&credentials, NULL, NULL);
major = gss_acquire_cred(&minor,
server_name,
GSS_C_INDEFINITE,
GSS_C_NO_OID_SET,
GSS_C_ACCEPT,
&credentials,
NULL,
NULL);
if (GSS_ERROR(major))
{
report_error(major, minor);
@ -360,16 +366,23 @@ static bool validate_gssapi_token(char* principal, uint8_t* token, size_t len, c
gss_buffer_desc in = {0, 0};
gss_buffer_desc out = {0, 0};
gss_buffer_desc client_name = {0, 0};
gss_OID_desc *oid;
gss_OID_desc* oid;
gss_name_t client;
in.value = token;
in.length = len;
major = gss_accept_sec_context(&minor, &handle, GSS_C_NO_CREDENTIAL,
&in, GSS_C_NO_CHANNEL_BINDINGS,
&client, &oid, &out,
0, 0, NULL);
major = gss_accept_sec_context(&minor,
&handle,
GSS_C_NO_CREDENTIAL,
&in,
GSS_C_NO_CHANNEL_BINDINGS,
&client,
&oid,
&out,
0,
0,
NULL);
if (GSS_ERROR(major))
{
report_error(major, minor);
@ -384,7 +397,7 @@ static bool validate_gssapi_token(char* principal, uint8_t* token, size_t len, c
return false;
}
char *princ_name = static_cast<char*>(MXS_MALLOC(client_name.length + 1));
char* princ_name = static_cast<char*>(MXS_MALLOC(client_name.length + 1));
if (!princ_name)
{
@ -401,9 +414,9 @@ static bool validate_gssapi_token(char* principal, uint8_t* token, size_t len, c
}
/** @brief Callback for sqlite3_exec() */
static int auth_cb(void *data, int columns, char** rows, char** row_names)
static int auth_cb(void* data, int columns, char** rows, char** row_names)
{
bool *rv = (bool*)data;
bool* rv = (bool*)data;
*rv = true;
return 0;
}
@ -417,25 +430,32 @@ static int auth_cb(void *data, int columns, char** rows, char** row_names)
* @param princ Client principal name
* @return True if the user has access to the database
*/
static bool validate_user(gssapi_auth_t *auth, DCB *dcb, MYSQL_session *session, const char *princ)
static bool validate_user(gssapi_auth_t* auth, DCB* dcb, MYSQL_session* session, const char* princ)
{
mxb_assert(princ);
size_t len = sizeof(gssapi_auth_query) + strlen(session->user) * 2 +
strlen(session->db) * 2 + strlen(dcb->remote) + strlen(princ) * 2;
size_t len = sizeof(gssapi_auth_query) + strlen(session->user) * 2
+ strlen(session->db) * 2 + strlen(dcb->remote) + strlen(princ) * 2;
char sql[len + 1];
bool rval = false;
char *err;
char* err;
char princ_user[strlen(princ) + 1];
strcpy(princ_user, princ);
char *at = strchr(princ_user, '@');
char* at = strchr(princ_user, '@');
if (at)
{
*at = '\0';
}
sprintf(sql, gssapi_auth_query, session->user, dcb->remote, session->db,
session->db, princ_user, session->user, princ);
sprintf(sql,
gssapi_auth_query,
session->user,
dcb->remote,
session->db,
session->db,
princ_user,
session->user,
princ);
/**
* Try authentication twice; first time with the current users, second
@ -467,18 +487,18 @@ static bool validate_user(gssapi_auth_t *auth, DCB *dcb, MYSQL_session *session,
* if authentication was successfully completed or MXS_AUTH_FAILED if authentication
* has failed.
*/
int gssapi_auth_authenticate(DCB *dcb)
int gssapi_auth_authenticate(DCB* dcb)
{
int rval = MXS_AUTH_FAILED;
gssapi_auth_t *auth = (gssapi_auth_t*)dcb->authenticator_data;
GSSAPI_INSTANCE *instance = (GSSAPI_INSTANCE*)dcb->listener->auth_instance;
gssapi_auth_t* auth = (gssapi_auth_t*)dcb->authenticator_data;
GSSAPI_INSTANCE* instance = (GSSAPI_INSTANCE*)dcb->listener->auth_instance;
if (auth->state == GSSAPI_AUTH_INIT)
{
/** We need to send the authentication switch packet to change the
* authentication to something other than the 'mysql_native_password'
* method */
GWBUF *buffer = create_auth_change_packet(instance, auth);
GWBUF* buffer = create_auth_change_packet(instance, auth);
if (buffer && dcb->func.write(dcb, buffer))
{
@ -491,11 +511,11 @@ int gssapi_auth_authenticate(DCB *dcb)
/** We sent the principal name and the client responded with the GSSAPI
* token that we must validate */
MYSQL_session *ses = (MYSQL_session*)dcb->data;
char *princ = NULL;
MYSQL_session* ses = (MYSQL_session*)dcb->data;
char* princ = NULL;
if (validate_gssapi_token(instance->principal_name, ses->auth_token, ses->auth_token_len, &princ) &&
validate_user(auth, dcb, ses, princ))
if (validate_gssapi_token(instance->principal_name, ses->auth_token, ses->auth_token_len, &princ)
&& validate_user(auth, dcb, ses, princ))
{
rval = MXS_AUTH_SUCCEEDED;
}
@ -511,11 +531,11 @@ int gssapi_auth_authenticate(DCB *dcb)
*
* @param dcb DCB to free
*/
void gssapi_auth_free_data(DCB *dcb)
void gssapi_auth_free_data(DCB* dcb)
{
if (dcb->data)
{
MYSQL_session *ses = static_cast<MYSQL_session*>(dcb->data);
MYSQL_session* ses = static_cast<MYSQL_session*>(dcb->data);
MXS_FREE(ses->auth_token);
MXS_FREE(ses);
dcb->data = NULL;
@ -526,9 +546,9 @@ void gssapi_auth_free_data(DCB *dcb)
* @brief Delete old users from the database
* @param handle Database handle
*/
static void delete_old_users(sqlite3 *handle)
static void delete_old_users(sqlite3* handle)
{
char *err;
char* err;
if (sqlite3_exec(handle, delete_query, NULL, NULL, &err) != SQLITE_OK)
{
@ -546,10 +566,14 @@ static void delete_old_users(sqlite3 *handle)
* @param db Database
* @param anydb Global access to databases
*/
static void add_gssapi_user(sqlite3 *handle, const char *user, const char *host,
const char *db, bool anydb, const char *princ)
static void add_gssapi_user(sqlite3* handle,
const char* user,
const char* host,
const char* db,
bool anydb,
const char* princ)
{
size_t dblen = db ? strlen(db) + 2 : sizeof(null_token); /** +2 for single quotes */
size_t dblen = db ? strlen(db) + 2 : sizeof(null_token); /** +2 for single quotes */
char dbstr[dblen + 1];
if (db)
@ -561,7 +585,8 @@ static void add_gssapi_user(sqlite3 *handle, const char *user, const char *host,
strcpy(dbstr, null_token);
}
size_t princlen = princ && *princ ? strlen(princ) + 2 : sizeof(null_token); /** +2 for single quotes */
size_t princlen = princ && *princ ? strlen(princ) + 2 : sizeof(null_token); /** +2 for single quotes
* */
char princstr[princlen + 1];
if (princ && *princ)
@ -578,7 +603,7 @@ static void add_gssapi_user(sqlite3 *handle, const char *user, const char *host,
char insert_sql[len + 1];
sprintf(insert_sql, insert_sql_pattern, user, host, dbstr, anydb ? "1" : "0", princstr);
char *err;
char* err;
if (sqlite3_exec(handle, insert_sql, NULL, NULL, &err) != SQLITE_OK)
{
MXS_ERROR("Failed to insert user: %s", err);
@ -597,12 +622,12 @@ static void add_gssapi_user(sqlite3 *handle, const char *user, const char *host,
* @param listener Listener definition
* @return MXS_AUTH_LOADUSERS_OK on success, MXS_AUTH_LOADUSERS_ERROR on error
*/
int gssapi_auth_load_users(SERV_LISTENER *listener)
int gssapi_auth_load_users(SERV_LISTENER* listener)
{
const char* user;
const char* password;
int rval = MXS_AUTH_LOADUSERS_ERROR;
GSSAPI_INSTANCE *inst = (GSSAPI_INSTANCE*)listener->auth_instance;
GSSAPI_INSTANCE* inst = (GSSAPI_INSTANCE*)listener->auth_instance;
serviceGetUser(listener->service, &user, &password);
char* pw;
@ -610,7 +635,7 @@ int gssapi_auth_load_users(SERV_LISTENER *listener)
{
bool no_active_servers = true;
for (SERVER_REF *servers = listener->service->dbref; servers; servers = servers->next)
for (SERVER_REF* servers = listener->service->dbref; servers; servers = servers->next)
{
if (!SERVER_REF_IS_ACTIVE(servers) || !server_is_active(servers->server))
{
@ -618,18 +643,19 @@ int gssapi_auth_load_users(SERV_LISTENER *listener)
}
no_active_servers = false;
MYSQL *mysql = mysql_init(NULL);
MYSQL* mysql = mysql_init(NULL);
if (mxs_mysql_real_connect(mysql, servers->server, user, pw))
{
if (mxs_mysql_query(mysql, gssapi_users_query))
{
MXS_ERROR("Failed to query server '%s' for GSSAPI users: %s",
servers->server->name, mysql_error(mysql));
servers->server->name,
mysql_error(mysql));
}
else
{
MYSQL_RES *res = mysql_store_result(mysql);
MYSQL_RES* res = mysql_store_result(mysql);
delete_old_users(inst->handle);
@ -640,7 +666,10 @@ int gssapi_auth_load_users(SERV_LISTENER *listener)
while ((row = mysql_fetch_row(res)))
{
add_gssapi_user(inst->handle, row[0], row[1], row[2],
add_gssapi_user(inst->handle,
row[0],
row[1],
row[2],
row[3] && strcasecmp(row[3], "Y") == 0,
row[4]);
}
@ -675,40 +704,39 @@ extern "C"
/**
* Module handle entry point
*/
MXS_MODULE* MXS_CREATE_MODULE()
{
static MXS_AUTHENTICATOR MyObject =
MXS_MODULE* MXS_CREATE_MODULE()
{
gssapi_auth_init, /* Initialize authenticator */
gssapi_auth_alloc, /* Allocate authenticator data */
gssapi_auth_extract, /* Extract data into structure */
gssapi_auth_connectssl, /* Check if client supports SSL */
gssapi_auth_authenticate, /* Authenticate user credentials */
gssapi_auth_free_data, /* Free the client data held in DCB */
gssapi_auth_free, /* Free authenticator data */
gssapi_auth_load_users, /* Load database users */
users_default_diagnostic, /* Default user diagnostic */
users_default_diagnostic_json, /* Default user diagnostic */
NULL /* No user reauthentication */
};
static MXS_AUTHENTICATOR MyObject =
{
gssapi_auth_init, /* Initialize authenticator */
gssapi_auth_alloc, /* Allocate authenticator data */
gssapi_auth_extract, /* Extract data into structure */
gssapi_auth_connectssl, /* Check if client supports SSL */
gssapi_auth_authenticate, /* Authenticate user credentials */
gssapi_auth_free_data, /* Free the client data held in DCB */
gssapi_auth_free, /* Free authenticator data */
gssapi_auth_load_users, /* Load database users */
users_default_diagnostic, /* Default user diagnostic */
users_default_diagnostic_json, /* Default user diagnostic */
NULL /* No user reauthentication */
};
static MXS_MODULE info =
{
MXS_MODULE_API_AUTHENTICATOR,
MXS_MODULE_GA,
MXS_AUTHENTICATOR_VERSION,
"GSSAPI authenticator",
"V1.0.0",
MXS_NO_MODULE_CAPABILITIES,
&MyObject,
NULL, /* Process init. */
NULL, /* Process finish. */
NULL, /* Thread init. */
NULL, /* Thread finish. */
{ { MXS_END_MODULE_PARAMS} }
};
return &info;
}
static MXS_MODULE info =
{
MXS_MODULE_API_AUTHENTICATOR,
MXS_MODULE_GA,
MXS_AUTHENTICATOR_VERSION,
"GSSAPI authenticator",
"V1.0.0",
MXS_NO_MODULE_CAPABILITIES,
&MyObject,
NULL, /* Process init. */
NULL, /* Process finish. */
NULL, /* Thread init. */
NULL, /* Thread finish. */
{{MXS_END_MODULE_PARAMS}}
};
return &info;
}
}

View File

@ -26,7 +26,7 @@
* @file gssapi_backend_auth.c - GSSAPI backend authenticator
*/
void* gssapi_backend_auth_alloc(void *instance)
void* gssapi_backend_auth_alloc(void* instance)
{
gssapi_auth_t* rval = static_cast<gssapi_auth_t*>(MXS_MALLOC(sizeof(gssapi_auth_t)));
@ -41,11 +41,11 @@ void* gssapi_backend_auth_alloc(void *instance)
return rval;
}
void gssapi_backend_auth_free(void *data)
void gssapi_backend_auth_free(void* data)
{
if (data)
{
gssapi_auth_t *auth = (gssapi_auth_t*)data;
gssapi_auth_t* auth = (gssapi_auth_t*)data;
MXS_FREE(auth->principal_name);
MXS_FREE(auth);
}
@ -56,7 +56,7 @@ void gssapi_backend_auth_free(void *data)
* @param dcb Backend DCB
* @return True on success, false on error
*/
static bool send_new_auth_token(DCB *dcb)
static bool send_new_auth_token(DCB* dcb)
{
bool rval = false;
OM_uint32 major = 0, minor = 0;
@ -65,7 +65,7 @@ static bool send_new_auth_token(DCB *dcb)
gss_buffer_desc out = {0, 0};
gss_buffer_desc target = {0, 0};
gss_name_t princ = GSS_C_NO_NAME;
gssapi_auth_t *auth = (gssapi_auth_t*)dcb->authenticator_data;
gssapi_auth_t* auth = (gssapi_auth_t*)dcb->authenticator_data;
/** The service principal name is sent by the backend server */
target.value = auth->principal_name;
@ -80,9 +80,19 @@ static bool send_new_auth_token(DCB *dcb)
}
/** Request the token for the service */
major = gss_init_sec_context(&minor, GSS_C_NO_CREDENTIAL,
&handle, princ, GSS_C_NO_OID, 0, 0,
GSS_C_NO_CHANNEL_BINDINGS, &in, NULL, &out, 0, 0);
major = gss_init_sec_context(&minor,
GSS_C_NO_CREDENTIAL,
&handle,
princ,
GSS_C_NO_OID,
0,
0,
GSS_C_NO_CHANNEL_BINDINGS,
&in,
NULL,
&out,
0,
0);
if (GSS_ERROR(major))
{
report_error(major, minor);
@ -90,11 +100,11 @@ static bool send_new_auth_token(DCB *dcb)
else
{
/** We successfully requested the token, send it to the backend server */
GWBUF *buffer = gwbuf_alloc(MYSQL_HEADER_LEN + out.length);
GWBUF* buffer = gwbuf_alloc(MYSQL_HEADER_LEN + out.length);
if (buffer)
{
uint8_t *data = (uint8_t*)GWBUF_DATA(buffer);
uint8_t* data = (uint8_t*)GWBUF_DATA(buffer);
gw_mysql_set_byte3(data, out.length);
data += 3;
*data++ = ++auth->sequence;
@ -122,7 +132,6 @@ static bool send_new_auth_token(DCB *dcb)
}
return rval;
}
/**
@ -132,13 +141,13 @@ static bool send_new_auth_token(DCB *dcb)
* @param buffer Buffer containing an AuthSwitchRequest packet
* @return True on success, false on error
*/
bool extract_principal_name(DCB *dcb, GWBUF *buffer)
bool extract_principal_name(DCB* dcb, GWBUF* buffer)
{
bool rval = false;
size_t buflen = gwbuf_length(buffer) - MYSQL_HEADER_LEN;
uint8_t databuf[buflen];
uint8_t *data = databuf;
gssapi_auth_t *auth = (gssapi_auth_t*)dcb->authenticator_data;
uint8_t* data = databuf;
gssapi_auth_t* auth = (gssapi_auth_t*)dcb->authenticator_data;
/** Copy the payload and the current packet sequence number */
gwbuf_copy_data(buffer, MYSQL_HEADER_LEN, buflen, databuf);
@ -150,9 +159,10 @@ bool extract_principal_name(DCB *dcb, GWBUF *buffer)
* it's possible that the server authenticated us as the anonymous user. This
* means that the server is not secure. */
MXS_ERROR("Server '%s' returned an unexpected authentication response.%s",
dcb->server->name, databuf[0] == MYSQL_REPLY_OK ?
" Authentication was complete before it even started, "
"anonymous users might not be disabled." : "");
dcb->server->name,
databuf[0] == MYSQL_REPLY_OK
? " Authentication was complete before it even started, "
"anonymous users might not be disabled." : "");
return false;
}
@ -176,7 +186,7 @@ bool extract_principal_name(DCB *dcb, GWBUF *buffer)
if (buflen > 0)
{
uint8_t *principal = static_cast<uint8_t*>(MXS_MALLOC(buflen + 1));
uint8_t* principal = static_cast<uint8_t*>(MXS_MALLOC(buflen + 1));
if (principal)
{
@ -204,10 +214,10 @@ bool extract_principal_name(DCB *dcb, GWBUF *buffer)
* @return True if authentication is ongoing or complete,
* false if authentication failed.
*/
static bool gssapi_backend_auth_extract(DCB *dcb, GWBUF *buffer)
static bool gssapi_backend_auth_extract(DCB* dcb, GWBUF* buffer)
{
bool rval = false;
gssapi_auth_t *auth = (gssapi_auth_t*)dcb->authenticator_data;
gssapi_auth_t* auth = (gssapi_auth_t*)dcb->authenticator_data;
if (auth->state == GSSAPI_AUTH_INIT && extract_principal_name(dcb, buffer))
{
@ -231,7 +241,7 @@ static bool gssapi_backend_auth_extract(DCB *dcb, GWBUF *buffer)
* @param dcb Backend DCB
* @return True if DCB supports SSL
*/
static bool gssapi_backend_auth_connectssl(DCB *dcb)
static bool gssapi_backend_auth_connectssl(DCB* dcb)
{
return dcb->server->server_ssl != NULL;
}
@ -242,10 +252,10 @@ static bool gssapi_backend_auth_connectssl(DCB *dcb)
* @return MXS_AUTH_INCOMPLETE if authentication is ongoing, MXS_AUTH_SUCCEEDED
* if authentication is complete and MXS_AUTH_FAILED if authentication failed.
*/
static int gssapi_backend_auth_authenticate(DCB *dcb)
static int gssapi_backend_auth_authenticate(DCB* dcb)
{
int rval = MXS_AUTH_FAILED;
gssapi_auth_t *auth = (gssapi_auth_t*)dcb->authenticator_data;
gssapi_auth_t* auth = (gssapi_auth_t*)dcb->authenticator_data;
if (auth->state == GSSAPI_AUTH_INIT)
{
@ -254,7 +264,6 @@ static int gssapi_backend_auth_authenticate(DCB *dcb)
rval = MXS_AUTH_INCOMPLETE;
auth->state = GSSAPI_AUTH_DATA_SENT;
}
}
else if (auth->state == GSSAPI_AUTH_OK)
{
@ -269,40 +278,39 @@ extern "C"
/**
* Module handle entry point
*/
MXS_MODULE* MXS_CREATE_MODULE()
{
static MXS_AUTHENTICATOR MyObject =
MXS_MODULE* MXS_CREATE_MODULE()
{
NULL, /* No initialize entry point */
gssapi_backend_auth_alloc, /* Allocate authenticator data */
gssapi_backend_auth_extract, /* Extract data into structure */
gssapi_backend_auth_connectssl, /* Check if client supports SSL */
gssapi_backend_auth_authenticate, /* Authenticate user credentials */
NULL, /* Client plugin will free shared data */
gssapi_backend_auth_free, /* Free authenticator data */
NULL, /* Load users from backend databases */
NULL, /* No diagnostic */
NULL,
NULL /* No user reauthentication */
};
static MXS_AUTHENTICATOR MyObject =
{
NULL, /* No initialize entry point */
gssapi_backend_auth_alloc, /* Allocate authenticator data */
gssapi_backend_auth_extract, /* Extract data into structure */
gssapi_backend_auth_connectssl, /* Check if client supports SSL */
gssapi_backend_auth_authenticate, /* Authenticate user credentials */
NULL, /* Client plugin will free shared data */
gssapi_backend_auth_free, /* Free authenticator data */
NULL, /* Load users from backend databases */
NULL, /* No diagnostic */
NULL,
NULL /* No user reauthentication */
};
static MXS_MODULE info =
{
MXS_MODULE_API_AUTHENTICATOR,
MXS_MODULE_GA,
MXS_AUTHENTICATOR_VERSION,
"GSSAPI backend authenticator",
"V1.0.0",
MXS_NO_MODULE_CAPABILITIES,
&MyObject,
NULL, /* Process init. */
NULL, /* Process finish. */
NULL, /* Thread init. */
NULL, /* Thread finish. */
{ { MXS_END_MODULE_PARAMS} }
};
return &info;
}
static MXS_MODULE info =
{
MXS_MODULE_API_AUTHENTICATOR,
MXS_MODULE_GA,
MXS_AUTHENTICATOR_VERSION,
"GSSAPI backend authenticator",
"V1.0.0",
MXS_NO_MODULE_CAPABILITIES,
&MyObject,
NULL, /* Process init. */
NULL, /* Process finish. */
NULL, /* Thread init. */
NULL, /* Thread finish. */
{{MXS_END_MODULE_PARAMS}}
};
return &info;
}
}

View File

@ -40,11 +40,11 @@ enum gssapi_auth_state
/** Common structure for both backend and client authenticators */
typedef struct gssapi_auth
{
enum gssapi_auth_state state; /**< Authentication state*/
uint8_t *principal_name; /**< Principal name */
size_t principal_name_len; /**< Length of the principal name */
uint8_t sequence; /**< The next packet seqence number */
sqlite3 *handle; /**< SQLite3 database handle */
enum gssapi_auth_state state; /**< Authentication state*/
uint8_t* principal_name; /**< Principal name */
size_t principal_name_len; /**< Length of the principal name */
uint8_t sequence; /**< The next packet seqence number */
sqlite3* handle; /**< SQLite3 database handle */
} gssapi_auth_t;
/** Report GSSAPI errors */

View File

@ -36,10 +36,10 @@
#include <maxscale/secrets.h>
#include <maxscale/users.h>
static bool http_auth_set_protocol_data(DCB *dcb, GWBUF *buf);
static bool http_auth_is_client_ssl_capable(DCB *dcb);
static int http_auth_authenticate(DCB *dcb);
static void http_auth_free_client_data(DCB *dcb);
static bool http_auth_set_protocol_data(DCB* dcb, GWBUF* buf);
static bool http_auth_is_client_ssl_capable(DCB* dcb);
static int http_auth_authenticate(DCB* dcb);
static void http_auth_free_client_data(DCB* dcb);
typedef struct http_auth
{
@ -57,41 +57,41 @@ extern "C"
*
* @return The module object
*/
MXS_MODULE* MXS_CREATE_MODULE()
{
static MXS_AUTHENTICATOR MyObject =
MXS_MODULE* MXS_CREATE_MODULE()
{
NULL, /* No initialize entry point */
NULL, /* No create entry point */
http_auth_set_protocol_data, /* Extract data into structure */
http_auth_is_client_ssl_capable, /* Check if client supports SSL */
http_auth_authenticate, /* Authenticate user credentials */
http_auth_free_client_data, /* Free the client data held in DCB */
NULL, /* No destroy entry point */
users_default_loadusers, /* Load generic users */
users_default_diagnostic, /* Default user diagnostic */
users_default_diagnostic_json, /* Default user diagnostic */
NULL /* No user reauthentication */
};
static MXS_AUTHENTICATOR MyObject =
{
NULL, /* No initialize entry point */
NULL, /* No create entry point */
http_auth_set_protocol_data, /* Extract data into structure */
http_auth_is_client_ssl_capable,/* Check if client supports SSL */
http_auth_authenticate, /* Authenticate user credentials */
http_auth_free_client_data, /* Free the client data held in DCB */
NULL, /* No destroy entry point */
users_default_loadusers, /* Load generic users */
users_default_diagnostic, /* Default user diagnostic */
users_default_diagnostic_json, /* Default user diagnostic */
NULL /* No user reauthentication */
};
static MXS_MODULE info =
{
MXS_MODULE_API_AUTHENTICATOR,
MXS_MODULE_GA,
MXS_AUTHENTICATOR_VERSION,
"The MaxScale HTTP BA authenticator",
"V1.1.0",
MXS_NO_MODULE_CAPABILITIES,
&MyObject,
NULL, /* Process init. */
NULL, /* Process finish. */
NULL, /* Thread init. */
NULL, /* Thread finish. */
{ { MXS_END_MODULE_PARAMS} }
};
static MXS_MODULE info =
{
MXS_MODULE_API_AUTHENTICATOR,
MXS_MODULE_GA,
MXS_AUTHENTICATOR_VERSION,
"The MaxScale HTTP BA authenticator",
"V1.1.0",
MXS_NO_MODULE_CAPABILITIES,
&MyObject,
NULL, /* Process init. */
NULL, /* Process finish. */
NULL, /* Thread init. */
NULL, /* Thread finish. */
{{MXS_END_MODULE_PARAMS}}
};
return &info;
}
return &info;
}
/*lint +e14 */
}
@ -103,11 +103,10 @@ MXS_MODULE* MXS_CREATE_MODULE()
* @param dcb Request handler DCB connected to the client
* @return Authentication status - always 0 to denote success
*/
static int
http_auth_authenticate(DCB *dcb)
static int http_auth_authenticate(DCB* dcb)
{
int rval = 1;
HTTP_AUTH *ses = (HTTP_AUTH*)dcb->data;
HTTP_AUTH* ses = (HTTP_AUTH*)dcb->data;
const char* user;
const char* password;
@ -134,8 +133,7 @@ http_auth_authenticate(DCB *dcb)
* @param buffer Pointer to pointer to buffers containing data from client
* @return Authentication status - true for success, false for failure
*/
static bool
http_auth_set_protocol_data(DCB *dcb, GWBUF *buf)
static bool http_auth_set_protocol_data(DCB* dcb, GWBUF* buf)
{
bool rval = false;
char* value = (char*)GWBUF_DATA(buf);
@ -146,19 +144,19 @@ http_auth_set_protocol_data(DCB *dcb, GWBUF *buf)
tok++;
char outbuf[strlen(tok) * 2 + 1];
BIO *b64 = BIO_new(BIO_f_base64());
BIO* b64 = BIO_new(BIO_f_base64());
BIO_set_flags(b64, BIO_FLAGS_BASE64_NO_NL);
BIO *bio = BIO_new_mem_buf(tok, -1);
BIO* bio = BIO_new_mem_buf(tok, -1);
BIO_push(b64, bio);
int nread = BIO_read(b64, outbuf, sizeof(outbuf));
outbuf[nread] = '\0';
BIO_free_all(b64);
char *pw_start = strchr(outbuf, ':');
char* pw_start = strchr(outbuf, ':');
if (pw_start)
{
*pw_start++ = '\0';
HTTP_AUTH *ses = static_cast<HTTP_AUTH*>(MXS_MALLOC(sizeof(*ses)));
HTTP_AUTH* ses = static_cast<HTTP_AUTH*>(MXS_MALLOC(sizeof(*ses)));
char* user = MXS_STRDUP(outbuf);
char* pw = MXS_STRDUP(pw_start);
@ -190,8 +188,7 @@ http_auth_set_protocol_data(DCB *dcb, GWBUF *buf)
* @param dcb Request handler DCB connected to the client
* @return Boolean indicating whether client is SSL capable - false
*/
static bool
http_auth_is_client_ssl_capable(DCB *dcb)
static bool http_auth_is_client_ssl_capable(DCB* dcb)
{
return false;
}
@ -204,10 +201,9 @@ http_auth_is_client_ssl_capable(DCB *dcb)
*
* @param dcb Request handler DCB connected to the client
*/
static void
http_auth_free_client_data(DCB *dcb)
static void http_auth_free_client_data(DCB* dcb)
{
HTTP_AUTH *ses = (HTTP_AUTH*)dcb->data;
HTTP_AUTH* ses = (HTTP_AUTH*)dcb->data;
MXS_FREE(ses->user);
MXS_FREE(ses->pw);
MXS_FREE(ses);

View File

@ -36,10 +36,10 @@
#include <maxscale/adminusers.h>
#include <maxscale/users.h>
static bool max_admin_auth_set_protocol_data(DCB *dcb, GWBUF *buf);
static bool max_admin_auth_is_client_ssl_capable(DCB *dcb);
static int max_admin_auth_authenticate(DCB *dcb);
static void max_admin_auth_free_client_data(DCB *dcb);
static bool max_admin_auth_set_protocol_data(DCB* dcb, GWBUF* buf);
static bool max_admin_auth_is_client_ssl_capable(DCB* dcb);
static int max_admin_auth_authenticate(DCB* dcb);
static void max_admin_auth_free_client_data(DCB* dcb);
extern "C"
{
@ -51,41 +51,41 @@ extern "C"
*
* @return The module object
*/
MXS_MODULE* MXS_CREATE_MODULE()
{
static MXS_AUTHENTICATOR MyObject =
MXS_MODULE* MXS_CREATE_MODULE()
{
NULL, /* No initialize entry point */
NULL, /* No create entry point */
max_admin_auth_set_protocol_data, /* Extract data into structure */
max_admin_auth_is_client_ssl_capable, /* Check if client supports SSL */
max_admin_auth_authenticate, /* Authenticate user credentials */
max_admin_auth_free_client_data, /* Free the client data held in DCB */
NULL, /* No destroy entry point */
users_default_loadusers, /* Load generic users */
users_default_diagnostic, /* Default user diagnostic */
users_default_diagnostic_json, /* Default user diagnostic */
NULL /* No user reauthentication */
};
static MXS_AUTHENTICATOR MyObject =
{
NULL, /* No initialize entry point */
NULL, /* No create entry point */
max_admin_auth_set_protocol_data, /* Extract data into structure */
max_admin_auth_is_client_ssl_capable, /* Check if client supports SSL */
max_admin_auth_authenticate, /* Authenticate user credentials */
max_admin_auth_free_client_data, /* Free the client data held in DCB */
NULL, /* No destroy entry point */
users_default_loadusers, /* Load generic users */
users_default_diagnostic, /* Default user diagnostic */
users_default_diagnostic_json, /* Default user diagnostic */
NULL /* No user reauthentication */
};
static MXS_MODULE info =
{
MXS_MODULE_API_AUTHENTICATOR,
MXS_MODULE_GA,
MXS_AUTHENTICATOR_VERSION,
"The MaxScale Admin client authenticator implementation",
"V2.1.0",
MXS_NO_MODULE_CAPABILITIES,
&MyObject,
NULL, /* Process init. */
NULL, /* Process finish. */
NULL, /* Thread init. */
NULL, /* Thread finish. */
{ { MXS_END_MODULE_PARAMS} }
};
static MXS_MODULE info =
{
MXS_MODULE_API_AUTHENTICATOR,
MXS_MODULE_GA,
MXS_AUTHENTICATOR_VERSION,
"The MaxScale Admin client authenticator implementation",
"V2.1.0",
MXS_NO_MODULE_CAPABILITIES,
&MyObject,
NULL, /* Process init. */
NULL, /* Process finish. */
NULL, /* Thread init. */
NULL, /* Thread finish. */
{{MXS_END_MODULE_PARAMS}}
};
return &info;
}
return &info;
}
/*lint +e14 */
}
@ -97,10 +97,9 @@ MXS_MODULE* MXS_CREATE_MODULE()
* @param dcb Request handler DCB connected to the client
* @return Authentication status - always 0 to denote success
*/
static int
max_admin_auth_authenticate(DCB *dcb)
static int max_admin_auth_authenticate(DCB* dcb)
{
return (dcb->data != NULL && ((ADMIN_session *)dcb->data)->validated) ? 0 : 1;
return (dcb->data != NULL && ((ADMIN_session*)dcb->data)->validated) ? 0 : 1;
}
/**
@ -113,19 +112,18 @@ max_admin_auth_authenticate(DCB *dcb)
* @param buffer Pointer to pointer to buffers containing data from client
* @return Authentication status - true for success, false for failure
*/
static bool
max_admin_auth_set_protocol_data(DCB *dcb, GWBUF *buf)
static bool max_admin_auth_set_protocol_data(DCB* dcb, GWBUF* buf)
{
ADMIN_session *session_data;
ADMIN_session* session_data;
max_admin_auth_free_client_data(dcb);
if ((session_data = (ADMIN_session *)MXS_CALLOC(1, sizeof(ADMIN_session))) != NULL)
if ((session_data = (ADMIN_session*)MXS_CALLOC(1, sizeof(ADMIN_session))) != NULL)
{
int user_len = (GWBUF_LENGTH(buf) > ADMIN_USER_MAXLEN) ? ADMIN_USER_MAXLEN : GWBUF_LENGTH(buf);
memcpy(session_data->user, GWBUF_DATA(buf), user_len);
session_data->validated = false;
dcb->data = (void *)session_data;
dcb->data = (void*)session_data;
/* Check for existance of the user */
if (admin_linux_account_enabled(session_data->user))
@ -146,8 +144,7 @@ max_admin_auth_set_protocol_data(DCB *dcb, GWBUF *buf)
* @param dcb Request handler DCB connected to the client
* @return Boolean indicating whether client is SSL capable - false
*/
static bool
max_admin_auth_is_client_ssl_capable(DCB *dcb)
static bool max_admin_auth_is_client_ssl_capable(DCB* dcb)
{
return false;
}
@ -160,8 +157,7 @@ max_admin_auth_is_client_ssl_capable(DCB *dcb)
*
* @param dcb Request handler DCB connected to the client
*/
static void
max_admin_auth_free_client_data(DCB *dcb)
static void max_admin_auth_free_client_data(DCB* dcb)
{
MXS_FREE(dcb->data);
}

View File

@ -43,7 +43,8 @@
/** MySQL 5.7 password column name */
#define MYSQL57_PASSWORD "authentication_string"
#define NEW_LOAD_DBUSERS_QUERY "SELECT u.user, u.host, d.db, u.select_priv, u.%s \
#define NEW_LOAD_DBUSERS_QUERY \
"SELECT u.user, u.host, d.db, u.select_priv, u.%s \
FROM mysql.user AS u LEFT JOIN mysql.db AS d \
ON (u.user = d.user AND u.host = d.host) WHERE u.plugin IN ('', 'mysql_native_password') %s \
UNION \
@ -51,83 +52,83 @@
FROM mysql.user AS u LEFT JOIN mysql.tables_priv AS t \
ON (u.user = t.user AND u.host = t.host) WHERE u.plugin IN ('', 'mysql_native_password') %s"
// Query used with MariaDB 10.1 and newer, supports roles
const char* mariadb_users_query =
// First, select all users
"SELECT t.user, t.host, t.db, t.select_priv, t.password FROM "
"( "
" SELECT u.user, u.host, d.db, u.select_priv, u.password AS password, u.is_role "
" FROM mysql.user AS u LEFT JOIN mysql.db AS d "
" ON (u.user = d.user AND u.host = d.host) "
" UNION "
" SELECT u.user, u.host, t.db, u.select_priv, u.password AS password, u.is_role "
" FROM mysql.user AS u LEFT JOIN mysql.tables_priv AS t "
" ON (u.user = t.user AND u.host = t.host) "
") AS t "
// Discard any users that are roles
"WHERE t.is_role <> 'Y' %s "
"UNION "
// Then select all users again
"SELECT r.user, r.host, u.db, u.select_priv, t.password FROM "
"( "
" SELECT u.user, u.host, d.db, u.select_priv, u.password AS password, u.default_role "
" FROM mysql.user AS u LEFT JOIN mysql.db AS d "
" ON (u.user = d.user AND u.host = d.host) "
" UNION "
" SELECT u.user, u.host, t.db, u.select_priv, u.password AS password, u.default_role "
" FROM mysql.user AS u LEFT JOIN mysql.tables_priv AS t "
" ON (u.user = t.user AND u.host = t.host) "
") AS t "
// Join it to the roles_mapping table to only have users with roles
"JOIN mysql.roles_mapping AS r "
"ON (r.user = t.user AND r.host = t.host) "
// Then join it into itself to get the privileges of the role with the name of the user
"JOIN "
"( "
" SELECT u.user, u.host, d.db, u.select_priv, u.password AS password, u.is_role "
" FROM mysql.user AS u LEFT JOIN mysql.db AS d "
" ON (u.user = d.user AND u.host = d.host) "
" UNION "
" SELECT u.user, u.host, t.db, u.select_priv, u.password AS password, u.is_role "
" FROM mysql.user AS u LEFT JOIN mysql.tables_priv AS t "
" ON (u.user = t.user AND u.host = t.host) "
") AS u "
"ON (u.user = r.role AND u.is_role = 'Y') "
// We only care about users that have a default role assigned
"WHERE t.default_role = u.user %s;";
// Query used with MariaDB 10.1 and newer, supports roles
const char* mariadb_users_query
= // First, select all users
"SELECT t.user, t.host, t.db, t.select_priv, t.password FROM "
"( "
" SELECT u.user, u.host, d.db, u.select_priv, u.password AS password, u.is_role "
" FROM mysql.user AS u LEFT JOIN mysql.db AS d "
" ON (u.user = d.user AND u.host = d.host) "
" UNION "
" SELECT u.user, u.host, t.db, u.select_priv, u.password AS password, u.is_role "
" FROM mysql.user AS u LEFT JOIN mysql.tables_priv AS t "
" ON (u.user = t.user AND u.host = t.host) "
") AS t "
// Discard any users that are roles
"WHERE t.is_role <> 'Y' %s "
"UNION "
// Then select all users again
"SELECT r.user, r.host, u.db, u.select_priv, t.password FROM "
"( "
" SELECT u.user, u.host, d.db, u.select_priv, u.password AS password, u.default_role "
" FROM mysql.user AS u LEFT JOIN mysql.db AS d "
" ON (u.user = d.user AND u.host = d.host) "
" UNION "
" SELECT u.user, u.host, t.db, u.select_priv, u.password AS password, u.default_role "
" FROM mysql.user AS u LEFT JOIN mysql.tables_priv AS t "
" ON (u.user = t.user AND u.host = t.host) "
") AS t "
// Join it to the roles_mapping table to only have users with roles
"JOIN mysql.roles_mapping AS r "
"ON (r.user = t.user AND r.host = t.host) "
// Then join it into itself to get the privileges of the role with the name of the user
"JOIN "
"( "
" SELECT u.user, u.host, d.db, u.select_priv, u.password AS password, u.is_role "
" FROM mysql.user AS u LEFT JOIN mysql.db AS d "
" ON (u.user = d.user AND u.host = d.host) "
" UNION "
" SELECT u.user, u.host, t.db, u.select_priv, u.password AS password, u.is_role "
" FROM mysql.user AS u LEFT JOIN mysql.tables_priv AS t "
" ON (u.user = t.user AND u.host = t.host) "
") AS u "
"ON (u.user = r.role AND u.is_role = 'Y') "
// We only care about users that have a default role assigned
"WHERE t.default_role = u.user %s;";
static int get_users(SERV_LISTENER *listener, bool skip_local);
static MYSQL *gw_mysql_init(void);
static int gw_mysql_set_timeouts(MYSQL* handle);
static char *mysql_format_user_entry(void *data);
static bool get_hostname(DCB *dcb, char *client_hostname, size_t size);
static int get_users(SERV_LISTENER* listener, bool skip_local);
static MYSQL* gw_mysql_init(void);
static int gw_mysql_set_timeouts(MYSQL* handle);
static char* mysql_format_user_entry(void* data);
static bool get_hostname(DCB* dcb, char* client_hostname, size_t size);
static char* get_mariadb_users_query(bool include_root)
{
const char *root = include_root ? "" : " AND t.user NOT IN ('root')";
const char* root = include_root ? "" : " AND t.user NOT IN ('root')";
size_t n_bytes = snprintf(NULL, 0, mariadb_users_query, root, root);
char *rval = static_cast<char*>(MXS_MALLOC(n_bytes + 1));
char* rval = static_cast<char*>(MXS_MALLOC(n_bytes + 1));
MXS_ABORT_IF_NULL(rval);
snprintf(rval, n_bytes + 1, mariadb_users_query, root, root);
return rval;
}
static char* get_users_query(const char *server_version, bool include_root, bool is_mariadb)
static char* get_users_query(const char* server_version, bool include_root, bool is_mariadb)
{
if (is_mariadb) // 10.1.1 or newer, supports default roles
if (is_mariadb) // 10.1.1 or newer, supports default roles
{
return get_mariadb_users_query(include_root);
}
// Either an older MariaDB version or a MySQL variant, use the legacy query
const char* password = strstr(server_version, "5.7.") || strstr(server_version, "8.0.")
? MYSQL57_PASSWORD : MYSQL_PASSWORD;
const char *with_root = include_root ? "" : " AND u.user NOT IN ('root')";
? MYSQL57_PASSWORD : MYSQL_PASSWORD;
const char* with_root = include_root ? "" : " AND u.user NOT IN ('root')";
size_t n_bytes = snprintf(NULL, 0, NEW_LOAD_DBUSERS_QUERY, password, with_root, password, with_root);
char *rval = static_cast<char*>(MXS_MALLOC(n_bytes + 1));
char* rval = static_cast<char*>(MXS_MALLOC(n_bytes + 1));
if (rval)
{
@ -137,14 +138,18 @@ static char* get_users_query(const char *server_version, bool include_root, bool
return rval;
}
int replace_mysql_users(SERV_LISTENER *listener, bool skip_local)
int replace_mysql_users(SERV_LISTENER* listener, bool skip_local)
{
int i = get_users(listener, skip_local);
return i;
}
static bool check_password(const char *output, uint8_t *token, size_t token_len,
uint8_t *scramble, size_t scramble_len, uint8_t *phase2_scramble)
static bool check_password(const char* output,
uint8_t* token,
size_t token_len,
uint8_t* scramble,
size_t scramble_len,
uint8_t* phase2_scramble)
{
uint8_t stored_token[SHA_DIGEST_LENGTH] = {};
size_t stored_token_len = sizeof(stored_token);
@ -192,14 +197,14 @@ static bool check_password(const char *output, uint8_t *token, size_t token_len,
}
/** Callback for check_database() */
static int database_cb(void *data, int columns, char** rows, char** row_names)
static int database_cb(void* data, int columns, char** rows, char** row_names)
{
bool *rval = (bool*)data;
bool* rval = (bool*)data;
*rval = true;
return 0;
}
static bool check_database(sqlite3 *handle, const char *database)
static bool check_database(sqlite3* handle, const char* database)
{
bool rval = true;
@ -211,7 +216,7 @@ static bool check_database(sqlite3 *handle, const char *database)
sprintf(sql, mysqlauth_validate_database_query, database);
char *err;
char* err;
if (sqlite3_exec(handle, sql, database_cb, &rval, &err) != SQLITE_OK)
{
@ -224,7 +229,7 @@ static bool check_database(sqlite3 *handle, const char *database)
return rval;
}
static bool no_password_required(const char *result, size_t tok_len)
static bool no_password_required(const char* result, size_t tok_len)
{
return *result == '\0' && tok_len == 0;
}
@ -237,26 +242,29 @@ struct user_query_result
};
/** @brief Callback for sqlite3_exec() */
static int auth_cb(void *data, int columns, char** rows, char** row_names)
static int auth_cb(void* data, int columns, char** rows, char** row_names)
{
struct user_query_result *res = (struct user_query_result*)data;
struct user_query_result* res = (struct user_query_result*)data;
strcpy(res->output, rows[0] ? rows[0] : "");
res->ok = true;
return 0;
}
int validate_mysql_user(MYSQL_AUTH* instance, DCB *dcb, MYSQL_session *session,
uint8_t *scramble, size_t scramble_len)
int validate_mysql_user(MYSQL_AUTH* instance,
DCB* dcb,
MYSQL_session* session,
uint8_t* scramble,
size_t scramble_len)
{
sqlite3 *handle = get_handle(instance);
const char* validate_query = instance->lower_case_table_names ?
mysqlauth_validate_user_query_lower :
mysqlauth_validate_user_query;
size_t len = strlen(validate_query) + 1 + strlen(session->user) * 2 +
strlen(session->db) * 2 + MYSQL_HOST_MAXLEN + session->auth_token_len * 4 + 1;
sqlite3* handle = get_handle(instance);
const char* validate_query = instance->lower_case_table_names
? mysqlauth_validate_user_query_lower
: mysqlauth_validate_user_query;
size_t len = strlen(validate_query) + 1 + strlen(session->user) * 2
+ strlen(session->db) * 2 + MYSQL_HOST_MAXLEN + session->auth_token_len * 4 + 1;
char sql[len + 1];
int rval = MXS_AUTH_FAILED;
char *err;
char* err;
if (instance->skip_auth)
{
@ -264,8 +272,13 @@ int validate_mysql_user(MYSQL_AUTH* instance, DCB *dcb, MYSQL_session *session,
}
else
{
sprintf(sql, validate_query, session->user, dcb->remote,
dcb->remote, session->db, session->db);
sprintf(sql,
validate_query,
session->user,
dcb->remote,
dcb->remote,
session->db,
session->db);
}
struct user_query_result res = {};
@ -279,9 +292,14 @@ int validate_mysql_user(MYSQL_AUTH* instance, DCB *dcb, MYSQL_session *session,
/** Check for IPv6 mapped IPv4 address */
if (!res.ok && strchr(dcb->remote, ':') && strchr(dcb->remote, '.'))
{
const char *ipv4 = strrchr(dcb->remote, ':') + 1;
sprintf(sql, validate_query, session->user, ipv4, ipv4,
session->db, session->db);
const char* ipv4 = strrchr(dcb->remote, ':') + 1;
sprintf(sql,
validate_query,
session->user,
ipv4,
ipv4,
session->db,
session->db);
if (sqlite3_exec(handle, sql, auth_cb, &res, &err) != SQLITE_OK)
{
@ -299,8 +317,13 @@ int validate_mysql_user(MYSQL_AUTH* instance, DCB *dcb, MYSQL_session *session,
char client_hostname[MYSQL_HOST_MAXLEN] = "";
get_hostname(dcb, client_hostname, sizeof(client_hostname) - 1);
sprintf(sql, validate_query, session->user, client_hostname,
client_hostname, session->db, session->db);
sprintf(sql,
validate_query,
session->user,
client_hostname,
client_hostname,
session->db,
session->db);
if (sqlite3_exec(handle, sql, auth_cb, &res, &err) != SQLITE_OK)
{
@ -313,9 +336,13 @@ int validate_mysql_user(MYSQL_AUTH* instance, DCB *dcb, MYSQL_session *session,
{
/** Found a matching row */
if (no_password_required(res.output, session->auth_token_len) ||
check_password(res.output, session->auth_token, session->auth_token_len,
scramble, scramble_len, session->client_sha1))
if (no_password_required(res.output, session->auth_token_len)
|| check_password(res.output,
session->auth_token,
session->auth_token_len,
scramble,
scramble_len,
session->client_sha1))
{
/** Password is OK, check that the database exists */
if (check_database(handle, session->db))
@ -337,13 +364,13 @@ int validate_mysql_user(MYSQL_AUTH* instance, DCB *dcb, MYSQL_session *session,
*
* @param handle SQLite handle
*/
static bool delete_mysql_users(sqlite3 *handle)
static bool delete_mysql_users(sqlite3* handle)
{
bool rval = true;
char *err;
char* err;
if (sqlite3_exec(handle, delete_users_query, NULL, NULL, &err) != SQLITE_OK ||
sqlite3_exec(handle, delete_databases_query, NULL, NULL, &err) != SQLITE_OK)
if (sqlite3_exec(handle, delete_users_query, NULL, NULL, &err) != SQLITE_OK
|| sqlite3_exec(handle, delete_databases_query, NULL, NULL, &err) != SQLITE_OK)
{
MXS_ERROR("Failed to delete old users: %s", err);
sqlite3_free(err);
@ -363,20 +390,20 @@ static bool delete_mysql_users(sqlite3 *handle)
* @param host The hostname, which is modified in-place. If merging is unsuccessful,
* it may end up garbled.
*/
static void merge_netmask(char *host)
static void merge_netmask(char* host)
{
char *delimiter_loc = strchr(host, '/');
char* delimiter_loc = strchr(host, '/');
if (delimiter_loc == NULL)
{
return; // Nothing to do
return; // Nothing to do
}
/* If anything goes wrong, we put the '/' back in to ensure the hostname
* cannot be used.
*/
*delimiter_loc = '\0';
char *ip_token_loc = host;
char *mask_token_loc = delimiter_loc + 1; // This is at minimum a \0
char* ip_token_loc = host;
char* mask_token_loc = delimiter_loc + 1; // This is at minimum a \0
while (ip_token_loc && mask_token_loc)
{
@ -396,7 +423,8 @@ static void merge_netmask(char *host)
*/
*delimiter_loc = '/';
MXS_ERROR("Unrecognized IP-bytes in host/mask-combination. "
"Merge incomplete: %s", host);
"Merge incomplete: %s",
host);
return;
}
@ -412,14 +440,19 @@ static void merge_netmask(char *host)
{
*delimiter_loc = '/';
MXS_ERROR("Unequal number of IP-bytes in host/mask-combination. "
"Merge incomplete: %s", host);
"Merge incomplete: %s",
host);
}
}
void add_mysql_user(sqlite3 *handle, const char *user, const char *host,
const char *db, bool anydb, const char *pw)
void add_mysql_user(sqlite3* handle,
const char* user,
const char* host,
const char* db,
bool anydb,
const char* pw)
{
size_t dblen = db && *db ? strlen(db) + 2 : sizeof(null_token); /** +2 for single quotes */
size_t dblen = db && *db ? strlen(db) + 2 : sizeof(null_token); /** +2 for single quotes */
char dbstr[dblen + 1];
if (db && *db)
@ -431,7 +464,7 @@ void add_mysql_user(sqlite3 *handle, const char *user, const char *host,
strcpy(dbstr, null_token);
}
size_t pwlen = pw && *pw ? strlen(pw) + 2 : sizeof(null_token); /** +2 for single quotes */
size_t pwlen = pw && *pw ? strlen(pw) + 2 : sizeof(null_token); /** +2 for single quotes */
char pwstr[pwlen + 1];
if (pw && *pw)
@ -442,7 +475,9 @@ void add_mysql_user(sqlite3 *handle, const char *user, const char *host,
"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.", user, host);
"this.",
user,
host);
return;
}
else if (*pw == '*')
@ -461,7 +496,7 @@ void add_mysql_user(sqlite3 *handle, const char *user, const char *host,
char insert_sql[len + 1];
sprintf(insert_sql, insert_user_query, user, host, dbstr, anydb ? "1" : "0", pwstr);
char *err;
char* err;
if (sqlite3_exec(handle, insert_sql, NULL, NULL, &err) != SQLITE_OK)
{
MXS_ERROR("Failed to insert user: %s", err);
@ -471,14 +506,14 @@ void add_mysql_user(sqlite3 *handle, const char *user, const char *host,
MXS_INFO("Added user: %s", insert_sql);
}
static void add_database(sqlite3 *handle, const char *db)
static void add_database(sqlite3* handle, const char* db)
{
size_t len = sizeof(insert_database_query) + strlen(db) + 1;
char insert_sql[len + 1];
sprintf(insert_sql, insert_database_query, db);
char *err;
char* err;
if (sqlite3_exec(handle, insert_sql, NULL, NULL, &err) != SQLITE_OK)
{
MXS_ERROR("Failed to insert database: %s", err);
@ -491,7 +526,7 @@ static void add_database(sqlite3 *handle, const char *db)
*
* @return An object or NULL if something fails.
*/
MYSQL *gw_mysql_init()
MYSQL* gw_mysql_init()
{
MYSQL* con = mysql_init(NULL);
@ -528,22 +563,25 @@ static int gw_mysql_set_timeouts(MYSQL* handle)
MXS_CONFIG* cnf = config_get_global_options();
if ((rc = mysql_optionsv(handle, MYSQL_OPT_READ_TIMEOUT,
(void *) &cnf->auth_read_timeout)))
if ((rc = mysql_optionsv(handle,
MYSQL_OPT_READ_TIMEOUT,
(void*) &cnf->auth_read_timeout)))
{
MXS_ERROR("Failed to set read timeout for backend connection.");
goto retblock;
}
if ((rc = mysql_optionsv(handle, MYSQL_OPT_CONNECT_TIMEOUT,
(void *) &cnf->auth_conn_timeout)))
if ((rc = mysql_optionsv(handle,
MYSQL_OPT_CONNECT_TIMEOUT,
(void*) &cnf->auth_conn_timeout)))
{
MXS_ERROR("Failed to set connect timeout for backend connection.");
goto retblock;
}
if ((rc = mysql_optionsv(handle, MYSQL_OPT_WRITE_TIMEOUT,
(void *) &cnf->auth_write_timeout)))
if ((rc = mysql_optionsv(handle,
MYSQL_OPT_WRITE_TIMEOUT,
(void*) &cnf->auth_write_timeout)))
{
MXS_ERROR("Failed to set write timeout for backend connection.");
goto retblock;
@ -562,10 +600,12 @@ retblock:
* @return True if the service permissions are OK, false if one or more permissions
* are missing.
*/
static bool check_server_permissions(SERVICE *service, SERVER* server,
const char* user, const char* password)
static bool check_server_permissions(SERVICE* service,
SERVER* server,
const char* user,
const char* password)
{
MYSQL *mysql = gw_mysql_init();
MYSQL* mysql = gw_mysql_init();
if (mysql == NULL)
{
@ -584,8 +624,12 @@ static bool check_server_permissions(SERVICE *service, SERVER* server,
MXS_ERROR("[%s] Failed to connect to server '%s' ([%s]:%d) when"
" checking authentication user credentials and permissions: %d %s",
service->name, server->name, server->address, server->port,
my_errno, mysql_error(mysql));
service->name,
server->name,
server->address,
server->port,
my_errno,
mysql_error(mysql));
mysql_close(mysql);
return my_errno != ER_ACCESS_DENIED_ERROR;
@ -602,8 +646,8 @@ static bool check_server_permissions(SERVICE *service, SERVER* server,
}
const char* format = "SELECT user, host, %s, Select_priv FROM mysql.user limit 1";
const char* query_pw = strstr(server->version_string, "5.7.") ?
MYSQL57_PASSWORD : MYSQL_PASSWORD;
const char* query_pw = strstr(server->version_string, "5.7.")
? MYSQL57_PASSWORD : MYSQL_PASSWORD;
char query[strlen(format) + strlen(query_pw) + 1];
bool rval = true;
sprintf(query, format, query_pw);
@ -614,13 +658,17 @@ static bool check_server_permissions(SERVICE *service, SERVER* server,
{
MXS_ERROR("[%s] User '%s' is missing SELECT privileges"
" on mysql.user table. MySQL error message: %s",
service->name, user, mysql_error(mysql));
service->name,
user,
mysql_error(mysql));
rval = false;
}
else
{
MXS_ERROR("[%s] Failed to query from mysql.user table."
" MySQL error message: %s", service->name, mysql_error(mysql));
" MySQL error message: %s",
service->name,
mysql_error(mysql));
}
}
else
@ -630,7 +678,9 @@ static bool check_server_permissions(SERVICE *service, SERVER* server,
if (res == NULL)
{
MXS_ERROR("[%s] Result retrieval failed when checking for permissions to "
"the mysql.user table: %s", service->name, mysql_error(mysql));
"the mysql.user table: %s",
service->name,
mysql_error(mysql));
}
else
{
@ -644,12 +694,16 @@ static bool check_server_permissions(SERVICE *service, SERVER* server,
{
MXS_WARNING("[%s] User '%s' is missing SELECT privileges on mysql.db table. "
"Database name will be ignored in authentication. "
"MySQL error message: %s", service->name, user, mysql_error(mysql));
"MySQL error message: %s",
service->name,
user,
mysql_error(mysql));
}
else
{
MXS_ERROR("[%s] Failed to query from mysql.db table. MySQL error message: %s",
service->name, mysql_error(mysql));
service->name,
mysql_error(mysql));
}
}
else
@ -658,7 +712,9 @@ static bool check_server_permissions(SERVICE *service, SERVER* server,
if (res == NULL)
{
MXS_ERROR("[%s] Result retrieval failed when checking for permissions "
"to the mysql.db table: %s", service->name, mysql_error(mysql));
"to the mysql.db table: %s",
service->name,
mysql_error(mysql));
}
else
{
@ -672,12 +728,17 @@ static bool check_server_permissions(SERVICE *service, SERVER* server,
{
MXS_WARNING("[%s] User '%s' is missing SELECT privileges on mysql.tables_priv table. "
"Database name will be ignored in authentication. "
"MySQL error message: %s", service->name, user, mysql_error(mysql));
"MySQL error message: %s",
service->name,
user,
mysql_error(mysql));
}
else
{
MXS_ERROR("[%s] Failed to query from mysql.tables_priv table. "
"MySQL error message: %s", service->name, mysql_error(mysql));
"MySQL error message: %s",
service->name,
mysql_error(mysql));
}
}
else
@ -686,7 +747,9 @@ static bool check_server_permissions(SERVICE *service, SERVER* server,
if (res == NULL)
{
MXS_ERROR("[%s] Result retrieval failed when checking for permissions "
"to the mysql.tables_priv table: %s", service->name, mysql_error(mysql));
"to the mysql.tables_priv table: %s",
service->name,
mysql_error(mysql));
}
else
{
@ -695,7 +758,8 @@ static bool check_server_permissions(SERVICE *service, SERVER* server,
}
// Check whether the current user has the SHOW DATABASES privilege
if (mxs_mysql_query(mysql, "SELECT show_db_priv FROM mysql.user "
if (mxs_mysql_query(mysql,
"SELECT show_db_priv FROM mysql.user "
"WHERE CONCAT(user, '@', host) = CURRENT_USER()") == 0)
{
MYSQL_RES* res = mysql_use_result(mysql);
@ -707,7 +771,8 @@ static bool check_server_permissions(SERVICE *service, SERVER* server,
{
MXS_WARNING("[%s] User '%s' is missing the SHOW DATABASES privilege. "
"This means that MaxScale cannot see all databases and authentication can fail.",
service->name, user);
service->name,
user);
}
mysql_free_result(res);
@ -721,9 +786,9 @@ static bool check_server_permissions(SERVICE *service, SERVER* server,
bool check_service_permissions(SERVICE* service)
{
if (rcap_type_required(service_get_capabilities(service), RCAP_TYPE_NO_AUTH) ||
config_get_global_options()->skip_permission_checks ||
service->dbref == NULL) // No servers to check
if (rcap_type_required(service_get_capabilities(service), RCAP_TYPE_NO_AUTH)
|| config_get_global_options()->skip_permission_checks
|| service->dbref == NULL) // No servers to check
{
return true;
}
@ -733,13 +798,13 @@ bool check_service_permissions(SERVICE* service)
serviceGetUser(service, &user, &password);
char *dpasswd = decrypt_password(password);
char* dpasswd = decrypt_password(password);
bool rval = false;
for (SERVER_REF *server = service->dbref; server; server = server->next)
for (SERVER_REF* server = service->dbref; server; server = server->next)
{
if (server_is_mxs_service(server->server) ||
check_server_permissions(service, server->server, user, dpasswd))
if (server_is_mxs_service(server->server)
|| check_server_permissions(service, server->server, user, dpasswd))
{
rval = true;
}
@ -760,32 +825,37 @@ bool check_service_permissions(SERVICE* service)
*
* @return True if the hostname query was successful
*/
static bool get_hostname(DCB *dcb, char *client_hostname, size_t size)
static bool get_hostname(DCB* dcb, char* client_hostname, size_t size)
{
struct addrinfo *ai = NULL, hint = {};
struct addrinfo* ai = NULL, hint = {};
hint.ai_flags = AI_ALL;
int rc;
if ((rc = getaddrinfo(dcb->remote, NULL, &hint, &ai)) != 0)
{
MXS_ERROR("Failed to obtain address for host %s, %s",
dcb->remote, gai_strerror(rc));
dcb->remote,
gai_strerror(rc));
return false;
}
/* Try to lookup the domain name of the given IP-address. This is a slow
* i/o-operation, which will stall the entire thread. TODO: cache results
* if this feature is used often. */
int lookup_result = getnameinfo(ai->ai_addr, ai->ai_addrlen,
client_hostname, size,
NULL, 0, // No need for the port
NI_NAMEREQD); // Text address only
int lookup_result = getnameinfo(ai->ai_addr,
ai->ai_addrlen,
client_hostname,
size,
NULL,
0, // No need for the port
NI_NAMEREQD); // Text address only
freeaddrinfo(ai);
if (lookup_result != 0 && lookup_result != EAI_NONAME)
{
MXS_WARNING("Client hostname lookup failed for '%s', getnameinfo() returned: '%s'.",
dcb->remote, gai_strerror(lookup_result));
dcb->remote,
gai_strerror(lookup_result));
}
return lookup_result == 0;
@ -799,8 +869,9 @@ static bool roles_are_available(MYSQL* conn, SERVICE* service, SERVER* server)
{
static bool log_missing_privs = true;
if (mxs_mysql_query(conn, "SET @roles_are_available=(SELECT 1 FROM mysql.roles_mapping LIMIT 1)") == 0 &&
mxs_mysql_query(conn, "SET @roles_are_available=(SELECT default_role FROM mysql.user LIMIT 1)") == 0)
if (mxs_mysql_query(conn, "SET @roles_are_available=(SELECT 1 FROM mysql.roles_mapping LIMIT 1)") == 0
&& mxs_mysql_query(conn,
"SET @roles_are_available=(SELECT default_role FROM mysql.user LIMIT 1)") == 0)
{
rval = true;
}
@ -810,24 +881,26 @@ static bool roles_are_available(MYSQL* conn, SERVICE* service, SERVER* server)
MXS_WARNING("The user for service '%s' might be missing the SELECT grant on "
"`mysql.roles_mapping` or `mysql.user`. Use of default roles is disabled "
"until the missing privileges are added. Error was: %s",
service->name, mysql_error(conn));
service->name,
mysql_error(conn));
}
}
return rval;
}
int get_users_from_server(MYSQL *con, SERVER_REF *server_ref, SERVICE *service, SERV_LISTENER *listener)
int get_users_from_server(MYSQL* con, SERVER_REF* server_ref, SERVICE* service, SERV_LISTENER* listener)
{
if (server_ref->server->version_string[0] == 0)
{
mxs_mysql_set_server_version(con, server_ref->server);
}
char *query = get_users_query(server_ref->server->version_string, service->enable_root,
char* query = get_users_query(server_ref->server->version_string,
service->enable_root,
roles_are_available(con, service, server_ref->server));
MYSQL_AUTH *instance = (MYSQL_AUTH*)listener->auth_instance;
MYSQL_AUTH* instance = (MYSQL_AUTH*)listener->auth_instance;
sqlite3* handle = get_handle(instance);
int users = 0;
@ -835,7 +908,7 @@ int get_users_from_server(MYSQL *con, SERVER_REF *server_ref, SERVICE *service,
{
if (mxs_mysql_query(con, query) == 0)
{
MYSQL_RES *result = mysql_store_result(con);
MYSQL_RES* result = mysql_store_result(con);
if (result)
{
@ -853,8 +926,12 @@ int get_users_from_server(MYSQL *con, SERVER_REF *server_ref, SERVICE *service,
merge_netmask(row[1]);
}
add_mysql_user(handle, row[0], row[1], row[2],
row[3] && strcmp(row[3], "Y") == 0, row[4]);
add_mysql_user(handle,
row[0],
row[1],
row[2],
row[3] && strcmp(row[3], "Y") == 0,
row[4]);
users++;
}
@ -872,7 +949,7 @@ int get_users_from_server(MYSQL *con, SERVER_REF *server_ref, SERVICE *service,
/** Load the list of databases */
if (mxs_mysql_query(con, "SHOW DATABASES") == 0)
{
MYSQL_RES *result = mysql_store_result(con);
MYSQL_RES* result = mysql_store_result(con);
if (result)
{
MYSQL_ROW row;
@ -900,15 +977,15 @@ int get_users_from_server(MYSQL *con, SERVER_REF *server_ref, SERVICE *service,
* @param users The users table into which to load the users
* @return -1 on any error or the number of users inserted
*/
static int get_users(SERV_LISTENER *listener, bool skip_local)
static int get_users(SERV_LISTENER* listener, bool skip_local)
{
const char *service_user = NULL;
const char *service_passwd = NULL;
SERVICE *service = listener->service;
const char* service_user = NULL;
const char* service_passwd = NULL;
SERVICE* service = listener->service;
serviceGetUser(service, &service_user, &service_passwd);
char *dpwd = decrypt_password(service_passwd);
char* dpwd = decrypt_password(service_passwd);
if (dpwd == NULL)
{
@ -916,33 +993,36 @@ static int get_users(SERV_LISTENER *listener, bool skip_local)
}
/** Delete the old users */
MYSQL_AUTH *instance = (MYSQL_AUTH*)listener->auth_instance;
MYSQL_AUTH* instance = (MYSQL_AUTH*)listener->auth_instance;
sqlite3* handle = get_handle(instance);
delete_mysql_users(handle);
SERVER_REF *server = service->dbref;
SERVER_REF* server = service->dbref;
int total_users = -1;
bool no_active_servers = true;
for (server = service->dbref; !maxscale_is_shutting_down() && server; server = server->next)
{
if (!SERVER_REF_IS_ACTIVE(server) || !server_is_active(server->server) ||
(skip_local && server_is_mxs_service(server->server)))
if (!SERVER_REF_IS_ACTIVE(server) || !server_is_active(server->server)
|| (skip_local && server_is_mxs_service(server->server)))
{
continue;
}
no_active_servers = false;
MYSQL *con = gw_mysql_init();
MYSQL* con = gw_mysql_init();
if (con)
{
if (mxs_mysql_real_connect(con, server->server, service_user, dpwd) == NULL)
{
MXS_ERROR("Failure loading users data from backend "
"[%s:%i] for service [%s]. MySQL error %i, %s",
server->server->address, server->server->port,
service->name, mysql_errno(con), mysql_error(con));
server->server->address,
server->server->port,
service->name,
mysql_errno(con),
mysql_error(con));
mysql_close(con);
}
else
@ -975,7 +1055,8 @@ static int get_users(SERV_LISTENER *listener, bool skip_local)
else if (server == NULL && total_users == -1)
{
MXS_ERROR("Unable to get user data from backend database for service [%s]."
" Failed to connect to any of the backend databases.", service->name);
" Failed to connect to any of the backend databases.",
service->name);
}
return total_users;

View File

@ -37,36 +37,38 @@
#include <maxscale/utils.h>
#include <maxscale/routingworker.h>
static void* mysql_auth_init(char **options);
static bool mysql_auth_set_protocol_data(DCB *dcb, GWBUF *buf);
static bool mysql_auth_is_client_ssl_capable(DCB *dcb);
static int mysql_auth_authenticate(DCB *dcb);
static void mysql_auth_free_client_data(DCB *dcb);
static int mysql_auth_load_users(SERV_LISTENER *port);
static void *mysql_auth_create(void *instance);
static void mysql_auth_destroy(void *data);
static void* mysql_auth_init(char** options);
static bool mysql_auth_set_protocol_data(DCB* dcb, GWBUF* buf);
static bool mysql_auth_is_client_ssl_capable(DCB* dcb);
static int mysql_auth_authenticate(DCB* dcb);
static void mysql_auth_free_client_data(DCB* dcb);
static int mysql_auth_load_users(SERV_LISTENER* port);
static void* mysql_auth_create(void* instance);
static void mysql_auth_destroy(void* data);
static int combined_auth_check(
DCB *dcb,
uint8_t *auth_token,
size_t auth_token_len,
MySQLProtocol *protocol,
char *username,
uint8_t *stage1_hash,
char *database
);
static bool mysql_auth_set_client_data(
MYSQL_session *client_data,
MySQLProtocol *protocol,
GWBUF *buffer);
static int combined_auth_check(DCB* dcb,
uint8_t* auth_token,
size_t auth_token_len,
MySQLProtocol* protocol,
char* username,
uint8_t* stage1_hash,
char* database
);
static bool mysql_auth_set_client_data(MYSQL_session* client_data,
MySQLProtocol* protocol,
GWBUF* buffer);
void mysql_auth_diagnostic(DCB *dcb, SERV_LISTENER *port);
json_t* mysql_auth_diagnostic_json(const SERV_LISTENER *port);
void mysql_auth_diagnostic(DCB* dcb, SERV_LISTENER* port);
json_t* mysql_auth_diagnostic_json(const SERV_LISTENER* port);
int mysql_auth_reauthenticate(DCB *dcb, const char *user,
uint8_t *token, size_t token_len,
uint8_t *scramble, size_t scramble_len,
uint8_t *output_token, size_t output_token_len);
int mysql_auth_reauthenticate(DCB* dcb,
const char* user,
uint8_t* token,
size_t token_len,
uint8_t* scramble,
size_t scramble_len,
uint8_t* output_token,
size_t output_token_len);
extern "C"
{
@ -78,45 +80,44 @@ extern "C"
*
* @return The module object
*/
MXS_MODULE* MXS_CREATE_MODULE()
{
static MXS_AUTHENTICATOR MyObject =
MXS_MODULE* MXS_CREATE_MODULE()
{
mysql_auth_init, /* Initialize the authenticator */
NULL, /* Create entry point */
mysql_auth_set_protocol_data, /* Extract data into structure */
mysql_auth_is_client_ssl_capable, /* Check if client supports SSL */
mysql_auth_authenticate, /* Authenticate user credentials */
mysql_auth_free_client_data, /* Free the client data held in DCB */
NULL, /* Destroy entry point */
mysql_auth_load_users, /* Load users from backend databases */
mysql_auth_diagnostic,
mysql_auth_diagnostic_json,
mysql_auth_reauthenticate /* Handle COM_CHANGE_USER */
};
static MXS_AUTHENTICATOR MyObject =
{
mysql_auth_init, /* Initialize the authenticator */
NULL, /* Create entry point */
mysql_auth_set_protocol_data, /* Extract data into structure */
mysql_auth_is_client_ssl_capable, /* Check if client supports SSL */
mysql_auth_authenticate, /* Authenticate user credentials */
mysql_auth_free_client_data, /* Free the client data held in DCB */
NULL, /* Destroy entry point */
mysql_auth_load_users, /* Load users from backend databases */
mysql_auth_diagnostic,
mysql_auth_diagnostic_json,
mysql_auth_reauthenticate /* Handle COM_CHANGE_USER */
};
static MXS_MODULE info =
{
MXS_MODULE_API_AUTHENTICATOR,
MXS_MODULE_GA,
MXS_AUTHENTICATOR_VERSION,
"The MySQL client to MaxScale authenticator implementation",
"V1.1.0",
ACAP_TYPE_ASYNC,
&MyObject,
NULL, /* Process init. */
NULL, /* Process finish. */
NULL, /* Thread init. */
NULL, /* Thread finish. */
{ { MXS_END_MODULE_PARAMS} }
};
static MXS_MODULE info =
{
MXS_MODULE_API_AUTHENTICATOR,
MXS_MODULE_GA,
MXS_AUTHENTICATOR_VERSION,
"The MySQL client to MaxScale authenticator implementation",
"V1.1.0",
ACAP_TYPE_ASYNC,
&MyObject,
NULL, /* Process init. */
NULL, /* Process finish. */
NULL, /* Thread init. */
NULL, /* Thread finish. */
{{MXS_END_MODULE_PARAMS}}
};
return &info;
return &info;
}
}
}
static bool open_instance_database(const char *path, sqlite3 **handle)
static bool open_instance_database(const char* path, sqlite3** handle)
{
int rc = sqlite3_open_v2(path, handle, db_flags, NULL);
@ -126,11 +127,11 @@ static bool open_instance_database(const char *path, sqlite3 **handle)
return false;
}
char *err;
char* err;
if (sqlite3_exec(*handle, users_create_sql, NULL, NULL, &err) != SQLITE_OK ||
sqlite3_exec(*handle, databases_create_sql, NULL, NULL, &err) != SQLITE_OK ||
sqlite3_exec(*handle, pragma_sql, NULL, NULL, &err) != SQLITE_OK)
if (sqlite3_exec(*handle, users_create_sql, NULL, NULL, &err) != SQLITE_OK
|| sqlite3_exec(*handle, databases_create_sql, NULL, NULL, &err) != SQLITE_OK
|| sqlite3_exec(*handle, pragma_sql, NULL, NULL, &err) != SQLITE_OK)
{
MXS_ERROR("Failed to create database: %s", err);
sqlite3_free(err);
@ -148,7 +149,7 @@ sqlite3* get_handle(MYSQL_AUTH* instance)
if (instance->handles[i] == NULL)
{
MXB_AT_DEBUG(bool rval = )open_instance_database(":memory:", &instance->handles[i]);
MXB_AT_DEBUG(bool rval = ) open_instance_database(":memory:", &instance->handles[i]);
mxb_assert(rval);
}
@ -174,12 +175,12 @@ static bool should_check_permissions(MYSQL_AUTH* instance)
* @param options Authenticator options
* @return New MYSQL_AUTH instance or NULL on error
*/
static void* mysql_auth_init(char **options)
static void* mysql_auth_init(char** options)
{
MYSQL_AUTH *instance = static_cast<MYSQL_AUTH*>(MXS_MALLOC(sizeof(*instance)));
MYSQL_AUTH* instance = static_cast<MYSQL_AUTH*>(MXS_MALLOC(sizeof(*instance)));
if (instance &&
(instance->handles = static_cast<sqlite3**>(MXS_CALLOC(config_threadcount(), sizeof(sqlite3*)))))
if (instance
&& (instance->handles = static_cast<sqlite3**>(MXS_CALLOC(config_threadcount(), sizeof(sqlite3*)))))
{
bool error = false;
instance->cache_dir = NULL;
@ -190,7 +191,7 @@ static void* mysql_auth_init(char **options)
for (int i = 0; options[i]; i++)
{
char *value = strchr(options[i], '=');
char* value = strchr(options[i], '=');
if (value)
{
@ -198,8 +199,8 @@ static void* mysql_auth_init(char **options)
if (strcmp(options[i], "cache_dir") == 0)
{
if ((instance->cache_dir = MXS_STRDUP(value)) == NULL ||
!clean_up_pathname(instance->cache_dir))
if ((instance->cache_dir = MXS_STRDUP(value)) == NULL
|| !clean_up_pathname(instance->cache_dir))
{
error = true;
}
@ -246,13 +247,13 @@ static void* mysql_auth_init(char **options)
return instance;
}
static bool is_localhost_address(struct sockaddr_storage *addr)
static bool is_localhost_address(struct sockaddr_storage* addr)
{
bool rval = false;
if (addr->ss_family == AF_INET)
{
struct sockaddr_in *ip = (struct sockaddr_in*)addr;
struct sockaddr_in* ip = (struct sockaddr_in*)addr;
if (ip->sin_addr.s_addr == INADDR_LOOPBACK)
{
rval = true;
@ -260,7 +261,7 @@ static bool is_localhost_address(struct sockaddr_storage *addr)
}
else if (addr->ss_family == AF_INET6)
{
struct sockaddr_in6 *ip = (struct sockaddr_in6*)addr;
struct sockaddr_in6* ip = (struct sockaddr_in6*)addr;
if (memcmp(&ip->sin6_addr, &in6addr_loopback, sizeof(ip->sin6_addr)) == 0)
{
rval = true;
@ -280,26 +281,32 @@ static bool is_localhost_address(struct sockaddr_storage *addr)
* @return Authentication status
* @note Authentication status codes are defined in maxscale/protocol/mysql.h
*/
static int
mysql_auth_authenticate(DCB *dcb)
static int mysql_auth_authenticate(DCB* dcb)
{
int auth_ret = ssl_authenticate_check_status(dcb);
MYSQL_session *client_data = (MYSQL_session *)dcb->data;
MYSQL_session* client_data = (MYSQL_session*)dcb->data;
if (auth_ret == MXS_AUTH_SSL_COMPLETE && *client_data->user)
{
MXS_DEBUG("Receiving connection from '%s' to database '%s'.",
client_data->user, client_data->db);
client_data->user,
client_data->db);
MYSQL_AUTH *instance = (MYSQL_AUTH*)dcb->listener->auth_instance;
MySQLProtocol *protocol = DCB_PROTOCOL(dcb, MySQLProtocol);
auth_ret = validate_mysql_user(instance, dcb, client_data,
protocol->scramble, sizeof(protocol->scramble));
MYSQL_AUTH* instance = (MYSQL_AUTH*)dcb->listener->auth_instance;
MySQLProtocol* protocol = DCB_PROTOCOL(dcb, MySQLProtocol);
auth_ret = validate_mysql_user(instance,
dcb,
client_data,
protocol->scramble,
sizeof(protocol->scramble));
if (auth_ret != MXS_AUTH_SUCCEEDED &&
service_refresh_users(dcb->service) == 0)
if (auth_ret != MXS_AUTH_SUCCEEDED
&& service_refresh_users(dcb->service) == 0)
{
auth_ret = validate_mysql_user(instance, dcb, client_data,
protocol->scramble, sizeof(protocol->scramble));
auth_ret = validate_mysql_user(instance,
dcb,
client_data,
protocol->scramble,
sizeof(protocol->scramble));
}
/* on successful authentication, set user into dcb field */
@ -327,21 +334,30 @@ mysql_auth_authenticate(DCB *dcb)
{
MXS_LOG_EVENT(maxscale::event::AUTHENTICATION_FAILURE,
"%s: login attempt for user '%s'@[%s]:%s, authentication failed. %s",
dcb->service->name, client_data->user, dcb->remote, dcb->path, extra);
dcb->service->name,
client_data->user,
dcb->remote,
dcb->path,
extra);
}
else
{
MXS_LOG_EVENT(maxscale::event::AUTHENTICATION_FAILURE,
"%s: login attempt for user '%s'@[%s]:%d, authentication failed. %s",
dcb->service->name, client_data->user, dcb->remote, dcb_get_port(dcb), extra);
dcb->service->name,
client_data->user,
dcb->remote,
dcb_get_port(dcb),
extra);
}
if (is_localhost_address(&dcb->ip) &&
!dcb->service->localhost_match_wildcard_host)
if (is_localhost_address(&dcb->ip)
&& !dcb->service->localhost_match_wildcard_host)
{
MXS_NOTICE("If you have a wildcard grant that covers this address, "
"try adding 'localhost_match_wildcard_host=true' for "
"service '%s'. ", dcb->service->name);
"service '%s'. ",
dcb->service->name);
}
}
@ -370,15 +386,14 @@ mysql_auth_authenticate(DCB *dcb)
* @param buffer Pointer to pointer to buffer containing data from client
* @return True on success, false on error
*/
static bool
mysql_auth_set_protocol_data(DCB *dcb, GWBUF *buf)
static bool mysql_auth_set_protocol_data(DCB* dcb, GWBUF* buf)
{
MySQLProtocol *protocol = NULL;
MYSQL_session *client_data = NULL;
MySQLProtocol* protocol = NULL;
MYSQL_session* client_data = NULL;
int client_auth_packet_size = 0;
protocol = DCB_PROTOCOL(dcb, MySQLProtocol);
client_data = (MYSQL_session *)dcb->data;
client_data = (MYSQL_session*)dcb->data;
client_auth_packet_size = gwbuf_length(buf);
@ -418,11 +433,9 @@ mysql_auth_set_protocol_data(DCB *dcb, GWBUF *buf)
* @param client_auth_packet size An integer giving the size of the data
* @return True on success, false on error
*/
static bool
mysql_auth_set_client_data(
MYSQL_session *client_data,
MySQLProtocol *protocol,
GWBUF *buffer)
static bool mysql_auth_set_client_data(MYSQL_session* client_data,
MySQLProtocol* protocol,
GWBUF* buffer)
{
int client_auth_packet_size = gwbuf_length(buffer);
uint8_t client_auth_packet[client_auth_packet_size];
@ -457,12 +470,14 @@ mysql_auth_set_client_data(
{
/* Extra 1 is for the terminating null after user name */
packet_length_used = MYSQL_AUTH_PACKET_BASE_SIZE + user_length + 1;
/* We should find an authentication token next */
/* One byte of packet is the length of authentication token */
/*
* We should find an authentication token next
* One byte of packet is the length of authentication token
*/
client_data->auth_token_len = client_auth_packet[packet_length_used];
if (client_auth_packet_size >
(packet_length_used + client_data->auth_token_len))
if (client_auth_packet_size
> (packet_length_used + client_data->auth_token_len))
{
client_data->auth_token = (uint8_t*)MXS_MALLOC(client_data->auth_token_len);
@ -504,10 +519,9 @@ mysql_auth_set_client_data(
* @param dcb Request handler DCB connected to the client
* @return Boolean indicating whether client is SSL capable
*/
static bool
mysql_auth_is_client_ssl_capable(DCB *dcb)
static bool mysql_auth_is_client_ssl_capable(DCB* dcb)
{
MySQLProtocol *protocol;
MySQLProtocol* protocol;
protocol = DCB_PROTOCOL(dcb, MySQLProtocol);
return (protocol->client_capabilities & (int)GW_MYSQL_CAPABILITIES_SSL) ? true : false;
@ -525,8 +539,7 @@ mysql_auth_is_client_ssl_capable(DCB *dcb)
*
* @param dcb Request handler DCB connected to the client
*/
static void
mysql_auth_free_client_data(DCB *dcb)
static void mysql_auth_free_client_data(DCB* dcb)
{
MXS_FREE(dcb->data);
}
@ -537,10 +550,10 @@ mysql_auth_free_client_data(DCB *dcb)
* @param port Service listener
* @return True on success, false on error
*/
static bool add_service_user(SERV_LISTENER *port)
static bool add_service_user(SERV_LISTENER* port)
{
const char *user = NULL;
const char *password = NULL;
const char* user = NULL;
const char* password = NULL;
bool rval = false;
serviceGetUser(port->service, &user, &password);
@ -549,11 +562,11 @@ static bool add_service_user(SERV_LISTENER *port)
if ((pw = decrypt_password(password)))
{
char *newpw = create_hex_sha1_sha1_passwd(pw);
char* newpw = create_hex_sha1_sha1_passwd(pw);
if (newpw)
{
MYSQL_AUTH *inst = (MYSQL_AUTH*)port->auth_instance;
MYSQL_AUTH* inst = (MYSQL_AUTH*)port->auth_instance;
sqlite3* handle = get_handle(inst);
add_mysql_user(handle, user, "%", "", "Y", newpw);
add_mysql_user(handle, user, "localhost", "", "Y", newpw);
@ -592,11 +605,11 @@ static bool service_has_servers(SERVICE* service)
* @return MXS_AUTH_LOADUSERS_OK on success, MXS_AUTH_LOADUSERS_ERROR and
* MXS_AUTH_LOADUSERS_FATAL on fatal error
*/
static int mysql_auth_load_users(SERV_LISTENER *port)
static int mysql_auth_load_users(SERV_LISTENER* port)
{
int rc = MXS_AUTH_LOADUSERS_OK;
SERVICE *service = port->listener->service;
MYSQL_AUTH *instance = (MYSQL_AUTH*)port->auth_instance;
SERVICE* service = port->listener->service;
MYSQL_AUTH* instance = (MYSQL_AUTH*)port->auth_instance;
bool first_load = false;
if (should_check_permissions(instance))
@ -618,8 +631,11 @@ static int mysql_auth_load_users(SERV_LISTENER *port)
{
if (loaded < 0)
{
MXS_ERROR("[%s] Unable to load users for listener %s listening at [%s]:%d.", service->name,
port->name, port->address ? port->address : "::", port->port);
MXS_ERROR("[%s] Unable to load users for listener %s listening at [%s]:%d.",
service->name,
port->name,
port->address ? port->address : "::",
port->port);
}
if (instance->inject_service_user)
@ -643,13 +659,15 @@ static int mysql_auth_load_users(SERV_LISTENER *port)
{
MXS_NOTICE("[%s] No users were loaded but 'inject_service_user' is enabled. "
"Enabling service credentials for authentication until "
"database users have been successfully loaded.", service->name);
"database users have been successfully loaded.",
service->name);
}
}
else if (loaded == 0 && !first_load)
{
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 && first_load)
{
@ -659,12 +677,16 @@ static int mysql_auth_load_users(SERV_LISTENER *port)
return rc;
}
int mysql_auth_reauthenticate(DCB *dcb, const char *user,
uint8_t *token, size_t token_len,
uint8_t *scramble, size_t scramble_len,
uint8_t *output_token, size_t output_token_len)
int mysql_auth_reauthenticate(DCB* dcb,
const char* user,
uint8_t* token,
size_t token_len,
uint8_t* scramble,
size_t scramble_len,
uint8_t* output_token,
size_t output_token_len)
{
MYSQL_session *client_data = (MYSQL_session *)dcb->data;
MYSQL_session* client_data = (MYSQL_session*)dcb->data;
MYSQL_session temp;
int rval = 1;
@ -673,7 +695,7 @@ int mysql_auth_reauthenticate(DCB *dcb, const char *user,
temp.auth_token = token;
temp.auth_token_len = token_len;
MYSQL_AUTH *instance = (MYSQL_AUTH*)dcb->listener->auth_instance;
MYSQL_AUTH* instance = (MYSQL_AUTH*)dcb->listener->auth_instance;
int rc = validate_mysql_user(instance, dcb, &temp, scramble, scramble_len);
if (rc != MXS_AUTH_SUCCEEDED && service_refresh_users(dcb->service) == 0)
@ -688,24 +710,26 @@ int mysql_auth_reauthenticate(DCB *dcb, const char *user,
}
return rval;
}
int diag_cb(void *data, int columns, char **row, char **field_names)
int diag_cb(void* data, int columns, char** row, char** field_names)
{
DCB *dcb = (DCB*)data;
DCB* dcb = (DCB*)data;
dcb_printf(dcb, "%s@%s ", row[0], row[1]);
return 0;
}
void mysql_auth_diagnostic(DCB *dcb, SERV_LISTENER *port)
void mysql_auth_diagnostic(DCB* dcb, SERV_LISTENER* port)
{
MYSQL_AUTH *instance = (MYSQL_AUTH*)port->auth_instance;
MYSQL_AUTH* instance = (MYSQL_AUTH*)port->auth_instance;
sqlite3* handle = get_handle(instance);
char *err;
char* err;
if (sqlite3_exec(handle, "SELECT user, host FROM " MYSQLAUTH_USERS_TABLE_NAME,
diag_cb, dcb, &err) != SQLITE_OK)
if (sqlite3_exec(handle,
"SELECT user, host FROM " MYSQLAUTH_USERS_TABLE_NAME,
diag_cb,
dcb,
&err) != SQLITE_OK)
{
dcb_printf(dcb, "Could not access users: %s", err);
MXS_ERROR("Could not access users: %s", err);
@ -713,7 +737,7 @@ void mysql_auth_diagnostic(DCB *dcb, SERV_LISTENER *port)
}
}
int diag_cb_json(void *data, int columns, char **row, char **field_names)
int diag_cb_json(void* data, int columns, char** row, char** field_names)
{
json_t* obj = json_object();
json_object_set_new(obj, "user", json_string(row[0]));
@ -724,16 +748,19 @@ int diag_cb_json(void *data, int columns, char **row, char **field_names)
return 0;
}
json_t* mysql_auth_diagnostic_json(const SERV_LISTENER *port)
json_t* mysql_auth_diagnostic_json(const SERV_LISTENER* port)
{
json_t* rval = json_array();
MYSQL_AUTH *instance = (MYSQL_AUTH*)port->auth_instance;
char *err;
MYSQL_AUTH* instance = (MYSQL_AUTH*)port->auth_instance;
char* err;
sqlite3* handle = get_handle(instance);
if (sqlite3_exec(handle, "SELECT user, host FROM " MYSQLAUTH_USERS_TABLE_NAME,
diag_cb_json, rval, &err) != SQLITE_OK)
if (sqlite3_exec(handle,
"SELECT user, host FROM " MYSQLAUTH_USERS_TABLE_NAME,
diag_cb_json,
rval,
&err) != SQLITE_OK)
{
MXS_ERROR("Failed to print users: %s", err);
sqlite3_free(err);

View File

@ -10,7 +10,7 @@
* of this software will be governed by version 2 or later of the General
* Public License.
*/
#pragma once
#pragma once
/*
* @verbatim
@ -43,44 +43,44 @@ static const char DBUSERS_DIR[] = "cache";
static const char DBUSERS_FILE[] = "dbusers.db";
/** The table name where we store the users */
#define MYSQLAUTH_USERS_TABLE_NAME "mysqlauth_users"
#define MYSQLAUTH_USERS_TABLE_NAME "mysqlauth_users"
/** The table name where we store the users */
#define MYSQLAUTH_DATABASES_TABLE_NAME "mysqlauth_databases"
#define MYSQLAUTH_DATABASES_TABLE_NAME "mysqlauth_databases"
/** CREATE TABLE statement for the in-memory users table */
static const char users_create_sql[] =
"CREATE TABLE IF NOT EXISTS " MYSQLAUTH_USERS_TABLE_NAME
"(user varchar(255), host varchar(255), db varchar(255), anydb boolean, password text)";
static const char users_create_sql[]
= "CREATE TABLE IF NOT EXISTS " MYSQLAUTH_USERS_TABLE_NAME
"(user varchar(255), host varchar(255), db varchar(255), anydb boolean, password text)";
/** CREATE TABLE statement for the in-memory databases table */
static const char databases_create_sql[] =
"CREATE TABLE IF NOT EXISTS " MYSQLAUTH_DATABASES_TABLE_NAME "(db varchar(255))";
static const char databases_create_sql[]
= "CREATE TABLE IF NOT EXISTS " MYSQLAUTH_DATABASES_TABLE_NAME "(db varchar(255))";
/** PRAGMA configuration options for SQLite */
static const char pragma_sql[] = "PRAGMA JOURNAL_MODE=NONE";
/** Query that checks if there's a grant for the user being authenticated */
static const char mysqlauth_validate_user_query[] =
"SELECT password FROM " MYSQLAUTH_USERS_TABLE_NAME
" WHERE user = '%s' AND ( '%s' = host OR '%s' LIKE host) AND (anydb = '1' OR '%s' = '' OR '%s' LIKE db)"
" LIMIT 1";
static const char mysqlauth_validate_user_query[]
= "SELECT password FROM " MYSQLAUTH_USERS_TABLE_NAME
" WHERE user = '%s' AND ( '%s' = host OR '%s' LIKE host) AND (anydb = '1' OR '%s' = '' OR '%s' LIKE db)"
" LIMIT 1";
/** Query that checks if there's a grant for the user being authenticated */
static const char mysqlauth_validate_user_query_lower[] =
"SELECT password FROM " MYSQLAUTH_USERS_TABLE_NAME
" WHERE user = '%s' AND ( '%s' = host OR '%s' LIKE host) AND (anydb = '1' OR '%s' = '' OR LOWER('%s') LIKE LOWER(db))"
" LIMIT 1";
static const char mysqlauth_validate_user_query_lower[]
= "SELECT password FROM " MYSQLAUTH_USERS_TABLE_NAME
" WHERE user = '%s' AND ( '%s' = host OR '%s' LIKE host) AND (anydb = '1' OR '%s' = '' OR LOWER('%s') LIKE LOWER(db))"
" LIMIT 1";
/** Query that only checks if there's a matching user */
static const char mysqlauth_skip_auth_query[] =
"SELECT password FROM " MYSQLAUTH_USERS_TABLE_NAME
" WHERE user = '%s' AND (anydb = '1' OR '%s' = '' OR '%s' LIKE db)"
" LIMIT 1";
static const char mysqlauth_skip_auth_query[]
= "SELECT password FROM " MYSQLAUTH_USERS_TABLE_NAME
" WHERE user = '%s' AND (anydb = '1' OR '%s' = '' OR '%s' LIKE db)"
" LIMIT 1";
/** Query that checks that the database exists */
static const char mysqlauth_validate_database_query[] =
"SELECT * FROM " MYSQLAUTH_DATABASES_TABLE_NAME " WHERE db = '%s' LIMIT 1";
static const char mysqlauth_validate_database_query[]
= "SELECT * FROM " MYSQLAUTH_DATABASES_TABLE_NAME " WHERE db = '%s' LIMIT 1";
/** Delete query used to clean up the database before loading new users */
static const char delete_users_query[] = "DELETE FROM " MYSQLAUTH_USERS_TABLE_NAME;
@ -89,35 +89,35 @@ static const char delete_users_query[] = "DELETE FROM " MYSQLAUTH_USERS_TABLE_NA
static const char delete_databases_query[] = "DELETE FROM " MYSQLAUTH_DATABASES_TABLE_NAME;
/** The insert query template which adds users to the mysqlauth_users table */
static const char insert_user_query[] =
"INSERT OR REPLACE INTO " MYSQLAUTH_USERS_TABLE_NAME " VALUES ('%s', '%s', %s, %s, %s)";
static const char insert_user_query[]
= "INSERT OR REPLACE INTO " MYSQLAUTH_USERS_TABLE_NAME " VALUES ('%s', '%s', %s, %s, %s)";
/** The insert query template which adds the databases to the table */
static const char insert_database_query[] =
"INSERT OR REPLACE INTO " MYSQLAUTH_DATABASES_TABLE_NAME " VALUES ('%s')";
static const char insert_database_query[]
= "INSERT OR REPLACE INTO " MYSQLAUTH_DATABASES_TABLE_NAME " VALUES ('%s')";
static const char dump_users_query[] =
"SELECT user, host, db, anydb, password FROM " MYSQLAUTH_USERS_TABLE_NAME;
static const char dump_users_query[]
= "SELECT user, host, db, anydb, password FROM " MYSQLAUTH_USERS_TABLE_NAME;
static const char dump_databases_query[] =
"SELECT db FROM " MYSQLAUTH_DATABASES_TABLE_NAME;
static const char dump_databases_query[]
= "SELECT db FROM " MYSQLAUTH_DATABASES_TABLE_NAME;
/** Used for NULL value creation in the INSERT query */
static const char null_token[] = "NULL";
/** Flags for sqlite3_open_v2() */
static int db_flags = SQLITE_OPEN_READWRITE |
SQLITE_OPEN_CREATE |
SQLITE_OPEN_NOMUTEX;
static int db_flags = SQLITE_OPEN_READWRITE
| SQLITE_OPEN_CREATE
| SQLITE_OPEN_NOMUTEX;
typedef struct mysql_auth
{
sqlite3 **handles; /**< SQLite3 database handle */
char *cache_dir; /**< Custom cache directory location */
bool inject_service_user; /**< Inject the service user into the list of users */
bool skip_auth; /**< Authentication will always be successful */
bool check_permissions;
bool lower_case_table_names; /**< Disable database case-sensitivity */
sqlite3** handles; /**< SQLite3 database handle */
char* cache_dir; /**< Custom cache directory location */
bool inject_service_user; /**< Inject the service user into the list of users */
bool skip_auth; /**< Authentication will always be successful */
bool check_permissions;
bool lower_case_table_names; /**< Disable database case-sensitivity */
} MYSQL_AUTH;
/**
@ -125,11 +125,11 @@ typedef struct mysql_auth
*/
typedef struct mysql_user_host_key
{
char *user;
char* user;
struct sockaddr_in ipv4;
int netmask;
char *resource;
char hostname[MYSQL_HOST_MAXLEN + 1];
int netmask;
char* resource;
char hostname[MYSQL_HOST_MAXLEN + 1];
} MYSQL_USER_HOST;
/**
@ -150,8 +150,12 @@ sqlite3* get_handle(MYSQL_AUTH* instance);
* @param db Database
* @param anydb Global access to databases
*/
void add_mysql_user(sqlite3 *handle, const char *user, const char *host,
const char *db, bool anydb, const char *pw);
void add_mysql_user(sqlite3* handle,
const char* user,
const char* host,
const char* db,
bool anydb,
const char* pw);
/**
* @brief Check if the service user has all required permissions to operate properly.
@ -174,7 +178,7 @@ bool check_service_permissions(SERVICE* service);
*
* @return True on success
*/
bool dbusers_load(sqlite3 *handle, const char *filename);
bool dbusers_load(sqlite3* handle, const char* filename);
/**
* Save users to persisted database
@ -183,7 +187,7 @@ bool dbusers_load(sqlite3 *handle, const char *filename);
*
* @return True on success
*/
bool dbusers_save(sqlite3 *src, const char *filename);
bool dbusers_save(sqlite3* src, const char* filename);
/**
* Reload and replace the currently loaded database users
@ -193,7 +197,7 @@ bool dbusers_save(sqlite3 *src, const char *filename);
*
* @return -1 on any error or the number of users inserted (0 means no users at all)
*/
int replace_mysql_users(SERV_LISTENER *listener, bool skip_local);
int replace_mysql_users(SERV_LISTENER* listener, bool skip_local);
/**
* @brief Verify the user has access to the database
@ -206,7 +210,10 @@ int replace_mysql_users(SERV_LISTENER *listener, bool skip_local);
*
* @return MXS_AUTH_SUCCEEDED if the user has access to the database
*/
int validate_mysql_user(MYSQL_AUTH* instance, DCB *dcb, MYSQL_session *session,
uint8_t *scramble, size_t scramble_len);
int validate_mysql_user(MYSQL_AUTH* instance,
DCB* dcb,
MYSQL_session* session,
uint8_t* scramble,
size_t scramble_len);
MXS_END_DECLS

View File

@ -41,14 +41,14 @@ enum mba_state
/** Structure representing the authentication state */
typedef struct mysql_backend_auth
{
enum mba_state state; /**< Authentication state */
enum mba_state state; /**< Authentication state */
} mysql_backend_auth_t;
/**
* @brief Allocate a new mysql_backend_auth object
* @return Allocated object or NULL if memory allocation failed
*/
void* auth_backend_create(void *instance)
void* auth_backend_create(void* instance)
{
mysql_backend_auth_t* mba = static_cast<mysql_backend_auth_t*>(MXS_MALLOC(sizeof(*mba)));
@ -64,7 +64,7 @@ void* auth_backend_create(void *instance)
* @brief Free allocated mysql_backend_auth object
* @param data Allocated mysql_backend_auth object
*/
void auth_backend_destroy(void *data)
void auth_backend_destroy(void* data)
{
if (data)
{
@ -79,10 +79,10 @@ void auth_backend_destroy(void *data)
* @return True on success, false on error
* @see authenticator.h
*/
static bool auth_backend_extract(DCB *dcb, GWBUF *buf)
static bool auth_backend_extract(DCB* dcb, GWBUF* buf)
{
bool rval = false;
mysql_backend_auth_t *mba = (mysql_backend_auth_t*)dcb->authenticator_data;
mysql_backend_auth_t* mba = (mysql_backend_auth_t*)dcb->authenticator_data;
switch (mba->state)
{
@ -114,10 +114,10 @@ static bool auth_backend_extract(DCB *dcb, GWBUF *buf)
* @return Authentication status
* @see authenticator.h
*/
static int auth_backend_authenticate(DCB *dcb)
static int auth_backend_authenticate(DCB* dcb)
{
int rval = MXS_AUTH_FAILED;
mysql_backend_auth_t *mba = (mysql_backend_auth_t*)dcb->authenticator_data;
mysql_backend_auth_t* mba = (mysql_backend_auth_t*)dcb->authenticator_data;
if (mba->state == MBA_AUTH_OK)
{
@ -138,7 +138,7 @@ static int auth_backend_authenticate(DCB *dcb)
* @param dcb Request handler DCB connected to the client
* @return Boolean indicating whether client is SSL capable
*/
static bool auth_backend_ssl(DCB *dcb)
static bool auth_backend_ssl(DCB* dcb)
{
return dcb->server->server_ssl != NULL;
}
@ -153,42 +153,42 @@ extern "C"
*
* @return The module object
*/
MXS_MODULE* MXS_CREATE_MODULE()
{
static MXS_AUTHENTICATOR MyObject =
MXS_MODULE* MXS_CREATE_MODULE()
{
NULL, /* No initialize entry point */
auth_backend_create, /* Create authenticator */
auth_backend_extract, /* Extract data into structure */
auth_backend_ssl, /* Check if client supports SSL */
auth_backend_authenticate, /* Authenticate user credentials */
NULL, /* The shared data is freed by the client DCB */
auth_backend_destroy, /* Destroy authenticator */
NULL, /* We don't need to load users */
NULL, /* No diagnostic */
NULL,
NULL /* No user reauthentication */
};
static MXS_MODULE info =
{
MXS_MODULE_API_AUTHENTICATOR,
MXS_MODULE_GA,
MXS_AUTHENTICATOR_VERSION,
"The MySQL MaxScale to backend server authenticator",
"V1.0.0",
MXS_NO_MODULE_CAPABILITIES,
&MyObject,
NULL, /* Process init. */
NULL, /* Process finish. */
NULL, /* Thread init. */
NULL, /* Thread finish. */
static MXS_AUTHENTICATOR MyObject =
{
{MXS_END_MODULE_PARAMS}
}
};
NULL, /* No initialize entry point */
auth_backend_create, /* Create authenticator */
auth_backend_extract, /* Extract data into structure */
auth_backend_ssl, /* Check if client supports SSL */
auth_backend_authenticate, /* Authenticate user credentials */
NULL, /* The shared data is freed by the client DCB */
auth_backend_destroy, /* Destroy authenticator */
NULL, /* We don't need to load users */
NULL, /* No diagnostic */
NULL,
NULL /* No user reauthentication */
};
return &info;
}
static MXS_MODULE info =
{
MXS_MODULE_API_AUTHENTICATOR,
MXS_MODULE_GA,
MXS_AUTHENTICATOR_VERSION,
"The MySQL MaxScale to backend server authenticator",
"V1.0.0",
MXS_NO_MODULE_CAPABILITIES,
&MyObject,
NULL, /* Process init. */
NULL, /* Process finish. */
NULL, /* Thread init. */
NULL, /* Thread finish. */
{
{MXS_END_MODULE_PARAMS}
}
};
return &info;
}
/*lint +e14 */
}

View File

@ -38,10 +38,10 @@
/** MXS-1026: Without MySQL protocol data structures, the NullAuth authenticator will crash. */
#include <maxscale/protocol/mysql.h>
static bool null_auth_set_protocol_data(DCB *dcb, GWBUF *buf);
static bool null_auth_is_client_ssl_capable(DCB *dcb);
static int null_auth_authenticate(DCB *dcb);
static void null_auth_free_client_data(DCB *dcb);
static bool null_auth_set_protocol_data(DCB* dcb, GWBUF* buf);
static bool null_auth_is_client_ssl_capable(DCB* dcb);
static int null_auth_authenticate(DCB* dcb);
static void null_auth_free_client_data(DCB* dcb);
extern "C"
{
@ -53,43 +53,43 @@ extern "C"
*
* @return The module object
*/
MXS_MODULE* MXS_CREATE_MODULE()
{
static MXS_AUTHENTICATOR MyObject =
MXS_MODULE* MXS_CREATE_MODULE()
{
NULL, /* No initialize entry point */
NULL, /* No create entry point */
null_auth_set_protocol_data, /* Extract data into structure */
null_auth_is_client_ssl_capable, /* Check if client supports SSL */
null_auth_authenticate, /* Authenticate user credentials */
null_auth_free_client_data, /* Free the client data held in DCB */
NULL, /* No destroy entry point */
users_default_loadusers, /* Load generic users */
NULL, /* No diagnostic */
NULL,
NULL /* No user reauthentication */
};
static MXS_MODULE info =
{
MXS_MODULE_API_AUTHENTICATOR,
MXS_MODULE_GA,
MXS_AUTHENTICATOR_VERSION,
"The Null client authenticator implementation",
"V1.1.0",
MXS_NO_MODULE_CAPABILITIES,
&MyObject,
NULL, /* Process init. */
NULL, /* Process finish. */
NULL, /* Thread init. */
NULL, /* Thread finish. */
static MXS_AUTHENTICATOR MyObject =
{
{MXS_END_MODULE_PARAMS}
}
};
NULL, /* No initialize entry point */
NULL, /* No create entry point */
null_auth_set_protocol_data, /* Extract data into structure */
null_auth_is_client_ssl_capable,/* Check if client supports SSL */
null_auth_authenticate, /* Authenticate user credentials */
null_auth_free_client_data, /* Free the client data held in DCB */
NULL, /* No destroy entry point */
users_default_loadusers, /* Load generic users */
NULL, /* No diagnostic */
NULL,
NULL /* No user reauthentication */
};
return &info;
}
static MXS_MODULE info =
{
MXS_MODULE_API_AUTHENTICATOR,
MXS_MODULE_GA,
MXS_AUTHENTICATOR_VERSION,
"The Null client authenticator implementation",
"V1.1.0",
MXS_NO_MODULE_CAPABILITIES,
&MyObject,
NULL, /* Process init. */
NULL, /* Process finish. */
NULL, /* Thread init. */
NULL, /* Thread finish. */
{
{MXS_END_MODULE_PARAMS}
}
};
return &info;
}
/*lint +e14 */
}
@ -101,8 +101,7 @@ MXS_MODULE* MXS_CREATE_MODULE()
* @param dcb Request handler DCB connected to the client
* @return Authentication status - always 0 to denote success
*/
static int
null_auth_authenticate(DCB *dcb)
static int null_auth_authenticate(DCB* dcb)
{
return 0;
}
@ -116,8 +115,7 @@ null_auth_authenticate(DCB *dcb)
* @param buffer Pointer to pointer to buffer containing data from client
* @return Always true
*/
static bool
null_auth_set_protocol_data(DCB *dcb, GWBUF *buf)
static bool null_auth_set_protocol_data(DCB* dcb, GWBUF* buf)
{
/** MXS-1026: This will just prevent a crash when the NullAuth authenticator
* is used. This does not provide a way to use MaxScale with no authentication. */
@ -135,8 +133,7 @@ null_auth_set_protocol_data(DCB *dcb, GWBUF *buf)
* @param dcb Request handler DCB connected to the client
* @return Boolean indicating whether client is SSL capable - always true
*/
static bool
null_auth_is_client_ssl_capable(DCB *dcb)
static bool null_auth_is_client_ssl_capable(DCB* dcb)
{
return true;
}
@ -148,8 +145,7 @@ null_auth_is_client_ssl_capable(DCB *dcb)
*
* @param dcb Request handler DCB connected to the client
*/
static void
null_auth_free_client_data(DCB *dcb)
static void null_auth_free_client_data(DCB* dcb)
{
free(dcb->data);
dcb->data = NULL;

View File

@ -35,10 +35,10 @@
#include <maxscale/buffer.h>
#include <maxscale/users.h>
static bool null_auth_set_protocol_data(DCB *dcb, GWBUF *buf);
static bool null_auth_is_client_ssl_capable(DCB *dcb);
static int null_auth_authenticate(DCB *dcb);
static void null_auth_free_client_data(DCB *dcb);
static bool null_auth_set_protocol_data(DCB* dcb, GWBUF* buf);
static bool null_auth_is_client_ssl_capable(DCB* dcb);
static int null_auth_authenticate(DCB* dcb);
static void null_auth_free_client_data(DCB* dcb);
extern "C"
{
@ -50,43 +50,43 @@ extern "C"
*
* @return The module object
*/
MXS_MODULE* MXS_CREATE_MODULE()
{
static MXS_AUTHENTICATOR MyObject =
MXS_MODULE* MXS_CREATE_MODULE()
{
NULL, /* No initialize entry point */
NULL, /* No create entry point */
null_auth_set_protocol_data, /* Extract data into structure */
null_auth_is_client_ssl_capable, /* Check if client supports SSL */
null_auth_authenticate, /* Authenticate user credentials */
null_auth_free_client_data, /* Free the client data held in DCB */
NULL, /* No destroy entry point */
users_default_loadusers, /* Load generic users */
NULL, /* No diagnostic */
NULL,
NULL /* No user reauthentication */
};
static MXS_MODULE info =
{
MXS_MODULE_API_AUTHENTICATOR,
MXS_MODULE_GA,
MXS_AUTHENTICATOR_VERSION,
"The Null client authenticator implementation",
"V1.1.0",
MXS_NO_MODULE_CAPABILITIES,
&MyObject,
NULL, /* Process init. */
NULL, /* Process finish. */
NULL, /* Thread init. */
NULL, /* Thread finish. */
static MXS_AUTHENTICATOR MyObject =
{
{MXS_END_MODULE_PARAMS}
}
};
NULL, /* No initialize entry point */
NULL, /* No create entry point */
null_auth_set_protocol_data, /* Extract data into structure */
null_auth_is_client_ssl_capable,/* Check if client supports SSL */
null_auth_authenticate, /* Authenticate user credentials */
null_auth_free_client_data, /* Free the client data held in DCB */
NULL, /* No destroy entry point */
users_default_loadusers, /* Load generic users */
NULL, /* No diagnostic */
NULL,
NULL /* No user reauthentication */
};
return &info;
}
static MXS_MODULE info =
{
MXS_MODULE_API_AUTHENTICATOR,
MXS_MODULE_GA,
MXS_AUTHENTICATOR_VERSION,
"The Null client authenticator implementation",
"V1.1.0",
MXS_NO_MODULE_CAPABILITIES,
&MyObject,
NULL, /* Process init. */
NULL, /* Process finish. */
NULL, /* Thread init. */
NULL, /* Thread finish. */
{
{MXS_END_MODULE_PARAMS}
}
};
return &info;
}
/*lint +e14 */
}
@ -98,8 +98,7 @@ MXS_MODULE* MXS_CREATE_MODULE()
* @param dcb Request handler DCB connected to the client
* @return Authentication status - always 1 to denote failure
*/
static int
null_auth_authenticate(DCB *dcb)
static int null_auth_authenticate(DCB* dcb)
{
return 1;
}
@ -113,8 +112,7 @@ null_auth_authenticate(DCB *dcb)
* @param buffer Pointer to pointer to buffer containing data from client
* @return Always true
*/
static bool
null_auth_set_protocol_data(DCB *dcb, GWBUF *buf)
static bool null_auth_set_protocol_data(DCB* dcb, GWBUF* buf)
{
return true;
}
@ -128,8 +126,7 @@ null_auth_set_protocol_data(DCB *dcb, GWBUF *buf)
* @param dcb Request handler DCB connected to the client
* @return Boolean indicating whether client is SSL capable - always true
*/
static bool
null_auth_is_client_ssl_capable(DCB *dcb)
static bool null_auth_is_client_ssl_capable(DCB* dcb)
{
return true;
}
@ -141,5 +138,6 @@ null_auth_is_client_ssl_capable(DCB *dcb)
*
* @param dcb Request handler DCB connected to the client
*/
static void
null_auth_free_client_data(DCB *dcb) {}
static void null_auth_free_client_data(DCB* dcb)
{
}

View File

@ -10,7 +10,7 @@
* of this software will be governed by version 2 or later of the General
* Public License.
*/
#include"pam_auth.hh"
#include "pam_auth.hh"
#include <string>
#include <maxscale/authenticator.h>
@ -35,7 +35,7 @@ const int NUM_FIELDS = 5;
*
* @return Authenticator instance, or NULL on error
*/
static void* pam_auth_init(char **options)
static void* pam_auth_init(char** options)
{
return PamInstance::create(options);
}
@ -47,7 +47,7 @@ static void* pam_auth_init(char **options)
*
* @return Authenticator session
*/
static void* pam_auth_alloc(void *instance)
static void* pam_auth_alloc(void* instance)
{
PamInstance* inst = static_cast<PamInstance*>(instance);
return PamClientSession::create(*inst);
@ -58,7 +58,7 @@ static void* pam_auth_alloc(void *instance)
*
* @param data PAM session
*/
static void pam_auth_free(void *data)
static void pam_auth_free(void* data)
{
delete static_cast<PamClientSession*>(data);
}
@ -72,9 +72,9 @@ static void pam_auth_free(void *data)
* @return True if authentication can continue, false if
* authentication failed
*/
static bool pam_auth_extract(DCB *dcb, GWBUF *read_buffer)
static bool pam_auth_extract(DCB* dcb, GWBUF* read_buffer)
{
PamClientSession *pses = static_cast<PamClientSession*>(dcb->authenticator_data);
PamClientSession* pses = static_cast<PamClientSession*>(dcb->authenticator_data);
return pses->extract(dcb, read_buffer);
}
@ -85,9 +85,9 @@ static bool pam_auth_extract(DCB *dcb, GWBUF *read_buffer)
*
* @return True if client supports SSL
*/
static bool pam_auth_connectssl(DCB *dcb)
static bool pam_auth_connectssl(DCB* dcb)
{
MySQLProtocol *protocol = (MySQLProtocol*)dcb->protocol;
MySQLProtocol* protocol = (MySQLProtocol*)dcb->protocol;
return protocol->client_capabilities & GW_MYSQL_CAPABILITIES_SSL;
}
@ -100,7 +100,7 @@ static bool pam_auth_connectssl(DCB *dcb)
* if authentication was successfully completed. MXS_AUTH_FAILED if authentication
* has failed.
*/
static int pam_auth_authenticate(DCB *dcb)
static int pam_auth_authenticate(DCB* dcb)
{
PamClientSession* pses = static_cast<PamClientSession*>(dcb->authenticator_data);
return pses->authenticate(dcb);
@ -113,11 +113,11 @@ static int pam_auth_authenticate(DCB *dcb)
*
* @param dcb DCB to free data from
*/
static void pam_auth_free_data(DCB *dcb)
static void pam_auth_free_data(DCB* dcb)
{
if (dcb->data)
{
MYSQL_session *ses = (MYSQL_session *)dcb->data;
MYSQL_session* ses = (MYSQL_session*)dcb->data;
MXS_FREE(ses->auth_token);
MXS_FREE(ses);
dcb->data = NULL;
@ -134,21 +134,21 @@ static void pam_auth_free_data(DCB *dcb)
*
* @return MXS_AUTH_LOADUSERS_OK on success, MXS_AUTH_LOADUSERS_ERROR on error
*/
static int pam_auth_load_users(SERV_LISTENER *listener)
static int pam_auth_load_users(SERV_LISTENER* listener)
{
PamInstance *inst = static_cast<PamInstance*>(listener->auth_instance);
PamInstance* inst = static_cast<PamInstance*>(listener->auth_instance);
return inst->load_users(listener->service);
}
static void pam_auth_diagnostic(DCB *dcb, SERV_LISTENER *listener)
static void pam_auth_diagnostic(DCB* dcb, SERV_LISTENER* listener)
{
PamInstance *inst = static_cast<PamInstance*>(listener->auth_instance);
PamInstance* inst = static_cast<PamInstance*>(listener->auth_instance);
inst->diagnostic(dcb);
}
static json_t* pam_auth_diagnostic_json(const SERV_LISTENER *listener)
static json_t* pam_auth_diagnostic_json(const SERV_LISTENER* listener)
{
PamInstance *inst = static_cast<PamInstance*>(listener->auth_instance);
PamInstance* inst = static_cast<PamInstance*>(listener->auth_instance);
return inst->diagnostic_json();
}
@ -157,40 +157,39 @@ extern "C"
/**
* Module handle entry point
*/
MXS_MODULE* MXS_CREATE_MODULE()
{
static MXS_AUTHENTICATOR MyObject =
MXS_MODULE* MXS_CREATE_MODULE()
{
pam_auth_init, /* Initialize authenticator */
pam_auth_alloc, /* Allocate authenticator data */
pam_auth_extract, /* Extract data into structure */
pam_auth_connectssl, /* Check if client supports SSL */
pam_auth_authenticate, /* Authenticate user credentials */
pam_auth_free_data, /* Free the client data held in DCB */
pam_auth_free, /* Free authenticator data */
pam_auth_load_users, /* Load database users */
pam_auth_diagnostic, /* Default user diagnostic */
pam_auth_diagnostic_json, /* Default user diagnostic */
NULL /* No user reauthentication */
};
static MXS_AUTHENTICATOR MyObject =
{
pam_auth_init, /* Initialize authenticator */
pam_auth_alloc, /* Allocate authenticator data */
pam_auth_extract, /* Extract data into structure */
pam_auth_connectssl, /* Check if client supports SSL */
pam_auth_authenticate, /* Authenticate user credentials */
pam_auth_free_data, /* Free the client data held in DCB */
pam_auth_free, /* Free authenticator data */
pam_auth_load_users, /* Load database users */
pam_auth_diagnostic, /* Default user diagnostic */
pam_auth_diagnostic_json, /* Default user diagnostic */
NULL /* No user reauthentication */
};
static MXS_MODULE info =
{
MXS_MODULE_API_AUTHENTICATOR,
MXS_MODULE_GA,
MXS_AUTHENTICATOR_VERSION,
"PAM authenticator",
"V1.0.0",
MXS_NO_MODULE_CAPABILITIES,
&MyObject,
NULL, /* Process init. */
NULL, /* Process finish. */
NULL, /* Thread init. */
NULL, /* Thread finish. */
{ { MXS_END_MODULE_PARAMS} }
};
return &info;
}
static MXS_MODULE info =
{
MXS_MODULE_API_AUTHENTICATOR,
MXS_MODULE_GA,
MXS_AUTHENTICATOR_VERSION,
"PAM authenticator",
"V1.0.0",
MXS_NO_MODULE_CAPABILITIES,
&MyObject,
NULL, /* Process init. */
NULL, /* Process finish. */
NULL, /* Thread init. */
NULL, /* Thread finish. */
{{MXS_END_MODULE_PARAMS}}
};
return &info;
}
}

View File

@ -10,7 +10,7 @@
* of this software will be governed by version 2 or later of the General
* Public License.
*/
#pragma once
#pragma once
/*
* Common definitions and includes for PAM client authenticator
@ -32,4 +32,4 @@ extern const string FIELD_HOST;
extern const string FIELD_DB;
extern const string FIELD_ANYDB;
extern const string FIELD_AUTHSTR;
extern const int NUM_FIELDS;
extern const int NUM_FIELDS;

View File

@ -30,7 +30,7 @@ namespace
*
* @return True on success, false if memory allocation failed
*/
bool store_client_password(DCB *dcb, GWBUF *buffer)
bool store_client_password(DCB* dcb, GWBUF* buffer)
{
bool rval = false;
uint8_t header[MYSQL_HEADER_LEN];
@ -38,8 +38,8 @@ bool store_client_password(DCB *dcb, GWBUF *buffer)
if (gwbuf_copy_data(buffer, 0, MYSQL_HEADER_LEN, header) == MYSQL_HEADER_LEN)
{
size_t plen = gw_mysql_get_byte3(header);
MYSQL_session *ses = (MYSQL_session*)dcb->data;
ses->auth_token = (uint8_t *)MXS_CALLOC(plen, sizeof(uint8_t));
MYSQL_session* ses = (MYSQL_session*)dcb->data;
ses->auth_token = (uint8_t*)MXS_CALLOC(plen, sizeof(uint8_t));
if (ses->auth_token)
{
ses->auth_token_len = gwbuf_copy_data(buffer, MYSQL_HEADER_LEN, plen, ses->auth_token);
@ -59,7 +59,7 @@ bool store_client_password(DCB *dcb, GWBUF *buffer)
* @param column_names Column names
* @return Always 0
*/
int user_services_cb(void *data, int columns, char** column_vals, char** column_names)
int user_services_cb(void* data, int columns, char** column_vals, char** column_names)
{
mxb_assert(columns == 1);
PamClientSession::StringVector* results = static_cast<PamClientSession::StringVector*>(data);
@ -78,14 +78,14 @@ int user_services_cb(void *data, int columns, char** column_vals, char** column_
/** Used by the PAM conversation function */
struct ConversationData
{
DCB* m_client;
int m_counter;
DCB* m_client;
int m_counter;
string m_password;
ConversationData(DCB* client, int counter, const string& password)
: m_client(client),
m_counter(counter),
m_password(password)
: m_client(client)
, m_counter(counter)
, m_password(password)
{
}
};
@ -97,8 +97,10 @@ struct ConversationData
* http://www.linux-pam.org/Linux-PAM-html/adg-interface-of-app-expected.html#adg-pam_conv
* for more information.
*/
int conversation_func(int num_msg, const struct pam_message **msg,
struct pam_response **resp_out, void *appdata_ptr)
int conversation_func(int num_msg,
const struct pam_message** msg,
struct pam_response** resp_out,
void* appdata_ptr)
{
MXS_DEBUG("Entering PAM conversation function.");
int rval = PAM_CONV_ERR;
@ -106,16 +108,18 @@ int conversation_func(int num_msg, const struct pam_message **msg,
if (data->m_counter > 1)
{
MXS_ERROR("Multiple calls to conversation function for client '%s'. %s",
data->m_client->user, GENERAL_ERRMSG);
data->m_client->user,
GENERAL_ERRMSG);
}
else if (num_msg == 1)
{
pam_message first = *msg[0];
if ((first.msg_style != PAM_PROMPT_ECHO_OFF && first.msg_style != PAM_PROMPT_ECHO_ON) ||
PASSWORD != first.msg)
if ((first.msg_style != PAM_PROMPT_ECHO_OFF && first.msg_style != PAM_PROMPT_ECHO_ON)
|| PASSWORD != first.msg)
{
MXS_ERROR("Unexpected PAM message: type='%d', contents='%s'",
first.msg_style, first.msg);
first.msg_style,
first.msg);
}
else
{
@ -132,7 +136,8 @@ int conversation_func(int num_msg, const struct pam_message **msg,
else
{
MXS_ERROR("Conversation function received '%d' messages from API. Only "
"singular messages are supported.", num_msg);
"singular messages are supported.",
num_msg);
}
data->m_counter++;
return rval;
@ -167,16 +172,22 @@ bool validate_pam_password(const string& user, const string& password, const str
authenticated = true;
MXS_DEBUG("pam_authenticate returned success.");
break;
case PAM_USER_UNKNOWN:
case PAM_AUTH_ERR:
// Normal failure, username or password was wrong.
MXS_LOG_EVENT(maxscale::event::AUTHENTICATION_FAILURE,
PAM_AUTH_ERR_MSG, user.c_str(), pam_strerror(pam_handle, pam_status));
PAM_AUTH_ERR_MSG,
user.c_str(),
pam_strerror(pam_handle, pam_status));
break;
default:
// More exotic error
MXS_LOG_EVENT(maxscale::event::AUTHENTICATION_FAILURE,
PAM_AUTH_ERR_MSG, user.c_str(), pam_strerror(pam_handle, pam_status));
PAM_AUTH_ERR_MSG,
user.c_str(),
pam_strerror(pam_handle, pam_status));
break;
}
}
@ -193,6 +204,7 @@ bool validate_pam_password(const string& user, const string& password, const str
case PAM_SUCCESS:
account_ok = true;
break;
default:
// Credentials have already been checked to be ok, so this is again a bit of an exotic error.
MXS_ERROR(PAM_ACC_ERR_MSG, user.c_str(), pam_strerror(pam_handle, pam_status));
@ -202,18 +214,17 @@ bool validate_pam_password(const string& user, const string& password, const str
pam_end(pam_handle, pam_status);
return account_ok;
}
}
PamClientSession::PamClientSession(sqlite3* dbhandle, const PamInstance& instance)
: m_state(PAM_AUTH_INIT),
m_sequence(0),
m_dbhandle(dbhandle),
m_instance(instance)
: m_state(PAM_AUTH_INIT)
, m_sequence(0)
, m_dbhandle(dbhandle)
, m_instance(instance)
{
}
PamClientSession:: ~PamClientSession()
PamClientSession::~PamClientSession()
{
sqlite3_close_v2(m_dbhandle);
}
@ -222,7 +233,7 @@ PamClientSession* PamClientSession::create(const PamInstance& inst)
{
// This handle is only used from one thread, can define no_mutex.
sqlite3* dbhandle = NULL;
int db_flags = SQLITE_OPEN_READONLY | SQLITE_OPEN_SHAREDCACHE | SQLITE_OPEN_NOMUTEX;
int db_flags = SQLITE_OPEN_READONLY | SQLITE_OPEN_SHAREDCACHE | SQLITE_OPEN_NOMUTEX;
if (sqlite3_open_v2(inst.m_dbname.c_str(), &dbhandle, db_flags, NULL) == SQLITE_OK)
{
sqlite3_busy_timeout(dbhandle, 1000);
@ -232,7 +243,7 @@ PamClientSession* PamClientSession::create(const PamInstance& inst)
MXS_ERROR("Failed to open SQLite3 handle.");
}
PamClientSession* rval = NULL;
if (!dbhandle || (rval = new (std::nothrow) PamClientSession(dbhandle, inst)) == NULL)
if (!dbhandle || (rval = new( std::nothrow) PamClientSession(dbhandle, inst)) == NULL)
{
sqlite3_close_v2(dbhandle);
}
@ -246,29 +257,32 @@ PamClientSession* PamClientSession::create(const PamInstance& inst)
* @param session MySQL session
* @param services_out Output for services
*/
void PamClientSession::get_pam_user_services(const DCB* dcb, const MYSQL_session* session,
void PamClientSession::get_pam_user_services(const DCB* dcb,
const MYSQL_session* session,
StringVector* services_out)
{
string services_query = string("SELECT authentication_string FROM ") + m_instance.m_tablename +
" WHERE " + FIELD_USER + " = '" + session->user + "' AND '" + dcb->remote +
"' LIKE " + FIELD_HOST + " AND (" + FIELD_ANYDB + " = '1' OR '" + session->db +
"' = '' OR '" + session->db + "' LIKE " + FIELD_DB +
") ORDER BY authentication_string;";
string services_query = string("SELECT authentication_string FROM ") + m_instance.m_tablename
+ " WHERE " + FIELD_USER + " = '" + session->user + "' AND '" + dcb->remote
+ "' LIKE " + FIELD_HOST + " AND (" + FIELD_ANYDB + " = '1' OR '" + session->db
+ "' = '' OR '" + session->db + "' LIKE " + FIELD_DB
+ ") ORDER BY authentication_string;";
MXS_DEBUG("PAM services search sql: '%s'.", services_query.c_str());
char *err;
char* err;
if (sqlite3_exec(m_dbhandle, services_query.c_str(), user_services_cb, services_out, &err) != SQLITE_OK)
{
MXS_ERROR("Failed to execute query: '%s'", err);
sqlite3_free(err);
}
MXS_DEBUG("User '%s' matched %lu rows in %s db.", session->user,
services_out->size(), m_instance.m_tablename.c_str());
MXS_DEBUG("User '%s' matched %lu rows in %s db.",
session->user,
services_out->size(),
m_instance.m_tablename.c_str());
if (services_out->empty())
{
// No service found for user with correct username & password. Check if anonymous user exists.
const string anon_query = string("SELECT authentication_string FROM ") + m_instance.m_tablename +
" WHERE " + FIELD_USER + " = '' AND " + FIELD_HOST + " = '%';";
const string anon_query = string("SELECT authentication_string FROM ") + m_instance.m_tablename
+ " WHERE " + FIELD_USER + " = '' AND " + FIELD_HOST + " = '%';";
if (sqlite3_exec(m_dbhandle, anon_query.c_str(), user_services_cb, services_out, &err) != SQLITE_OK)
{
MXS_ERROR("Failed to execute query: '%s'", err);
@ -286,7 +300,8 @@ void PamClientSession::get_pam_user_services(const DCB* dcb, const MYSQL_session
* This obviously only works with the basic password authentication scheme.
*
* @return Allocated packet
* @see https://dev.mysql.com/doc/internals/en/connection-phase-packets.html#packet-Protocol::AuthSwitchRequest
* @see
*https://dev.mysql.com/doc/internals/en/connection-phase-packets.html#packet-Protocol::AuthSwitchRequest
*/
Buffer PamClientSession::create_auth_change_packet() const
{
@ -305,11 +320,11 @@ Buffer PamClientSession::create_auth_change_packet() const
gw_mysql_set_byte3(pData, plen);
pData += 3;
*pData++ = m_sequence;
*pData++ = 0xfe; // AuthSwitchRequest command
*pData++ = 0xfe; // AuthSwitchRequest command
memcpy(pData, DIALOG.c_str(), DIALOG_SIZE); // Plugin name
pData += DIALOG_SIZE;
*pData++ = DIALOG_ECHO_DISABLED;
memcpy(pData, PASSWORD.c_str(), PASSWORD.length()); // First message
memcpy(pData, PASSWORD.c_str(), PASSWORD.length()); // First message
Buffer buffer(bufdata, buflen);
return buffer;
@ -318,7 +333,7 @@ Buffer PamClientSession::create_auth_change_packet() const
int PamClientSession::authenticate(DCB* dcb)
{
int rval = ssl_authenticate_check_status(dcb);
MYSQL_session *ses = static_cast<MYSQL_session*>(dcb->data);
MYSQL_session* ses = static_cast<MYSQL_session*>(dcb->data);
if (rval == MXS_AUTH_SSL_COMPLETE && *ses->user)
{
rval = MXS_AUTH_FAILED;
@ -391,7 +406,7 @@ int PamClientSession::authenticate(DCB* dcb)
return rval;
}
bool PamClientSession::extract(DCB *dcb, GWBUF *buffer)
bool PamClientSession::extract(DCB* dcb, GWBUF* buffer)
{
gwbuf_copy_data(buffer, MYSQL_SEQ_OFFSET, 1, &m_sequence);
m_sequence++;

View File

@ -10,7 +10,7 @@
* of this software will be governed by version 2 or later of the General
* Public License.
*/
#pragma once
#pragma once
#include "pam_auth.hh"
#include <stdint.h>
@ -29,18 +29,17 @@ public:
typedef std::vector<std::string> StringVector;
static PamClientSession* create(const PamInstance& inst);
~PamClientSession();
int authenticate(DCB* client);
bool extract(DCB *dcb, GWBUF *read_buffer);
int authenticate(DCB* client);
bool extract(DCB* dcb, GWBUF* read_buffer);
private:
PamClientSession(sqlite3* dbhandle, const PamInstance& instance);
void get_pam_user_services(const DCB* dcb, const MYSQL_session* session,
void get_pam_user_services(const DCB* dcb,
const MYSQL_session* session,
StringVector* services_out);
maxscale::Buffer create_auth_change_packet() const;
pam_auth_state m_state; /**< Authentication state*/
uint8_t m_sequence; /**< The next packet seqence number */
sqlite3* const m_dbhandle; /**< SQLite3 database handle */
const PamInstance& m_instance; /**< Authenticator instance */
pam_auth_state m_state; /**< Authentication state*/
uint8_t m_sequence; /**< The next packet seqence number */
sqlite3* const m_dbhandle; /**< SQLite3 database handle */
const PamInstance& m_instance; /**< Authenticator instance */
};

View File

@ -21,7 +21,7 @@
#include <maxscale/mysql_utils.h>
#define DEFAULT_PAM_DATABASE_NAME "file:pam.db?mode=memory&cache=shared"
#define DEFAULT_PAM_TABLE_NAME "pam_users"
#define DEFAULT_PAM_TABLE_NAME "pam_users"
using std::string;
/**
@ -30,17 +30,17 @@ using std::string;
* @param options Listener options
* @return New client authenticator instance or NULL on error
*/
PamInstance* PamInstance::create(char **options)
PamInstance* PamInstance::create(char** options)
{
/** Name of the in-memory database */
const string pam_db_name = DEFAULT_PAM_DATABASE_NAME;
/** The table name where we store the users */
const string pam_table_name = DEFAULT_PAM_TABLE_NAME;
/** CREATE TABLE statement for the in-memory table */
const string create_sql = string("CREATE TABLE IF NOT EXISTS ") + pam_table_name +
" (" + FIELD_USER + " varchar(255), " + FIELD_HOST + " varchar(255), " +
FIELD_DB + " varchar(255), " + FIELD_ANYDB + " boolean, " +
FIELD_AUTHSTR + " text);";
const string create_sql = string("CREATE TABLE IF NOT EXISTS ") + pam_table_name
+ " (" + FIELD_USER + " varchar(255), " + FIELD_HOST + " varchar(255), "
+ FIELD_DB + " varchar(255), " + FIELD_ANYDB + " boolean, "
+ FIELD_AUTHSTR + " text);";
if (sqlite3_threadsafe() == 0)
{
MXS_WARNING("SQLite3 was compiled with thread safety off. May cause "
@ -49,15 +49,15 @@ PamInstance* PamInstance::create(char **options)
bool error = false;
/* This handle may be used from multiple threads, set full mutex. */
sqlite3* dbhandle = NULL;
int db_flags = SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE |
SQLITE_OPEN_SHAREDCACHE | SQLITE_OPEN_FULLMUTEX;
int db_flags = SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE
| SQLITE_OPEN_SHAREDCACHE | SQLITE_OPEN_FULLMUTEX;
if (sqlite3_open_v2(pam_db_name.c_str(), &dbhandle, db_flags, NULL) != SQLITE_OK)
{
MXS_ERROR("Failed to open SQLite3 handle.");
error = true;
}
char *err;
char* err;
if (!error && sqlite3_exec(dbhandle, create_sql.c_str(), NULL, NULL, &err) != SQLITE_OK)
{
MXS_ERROR("Failed to create database: '%s'", err);
@ -65,9 +65,9 @@ PamInstance* PamInstance::create(char **options)
error = true;
}
PamInstance *instance = NULL;
if (!error &&
((instance = new (std::nothrow) PamInstance(dbhandle, pam_db_name, pam_table_name)) == NULL))
PamInstance* instance = NULL;
if (!error
&& ((instance = new( std::nothrow) PamInstance(dbhandle, pam_db_name, pam_table_name)) == NULL))
{
sqlite3_close_v2(dbhandle);
}
@ -97,8 +97,11 @@ PamInstance::PamInstance(sqlite3* dbhandle, const string& dbname, const string&
* @param anydb Global access to databases
* @param pam_service The PAM service used
*/
void PamInstance::add_pam_user(const char *user, const char *host,
const char *db, bool anydb, const char *pam_service)
void PamInstance::add_pam_user(const char* user,
const char* host,
const char* db,
bool anydb,
const char* pam_service)
{
/**
* The insert query template which adds users to the pam_users table.
@ -106,8 +109,8 @@ void PamInstance::add_pam_user(const char *user, const char *host,
* Note that 'db' and 'pam_service' are strings that can be NULL and thus they have
* no quotes around them. The quotes for strings are added in this function.
*/
const string insert_sql_template =
"INSERT INTO " + m_tablename + " VALUES ('%s', '%s', %s, '%s', %s)";
const string insert_sql_template
= "INSERT INTO " + m_tablename + " VALUES ('%s', '%s', %s, '%s', %s)";
/** Used for NULL value creation in the INSERT query */
const char NULL_TOKEN[] = "NULL";
@ -132,14 +135,19 @@ void PamInstance::add_pam_user(const char *user, const char *host,
service_str = NULL_TOKEN;
}
size_t len = insert_sql_template.length() + strlen(user) + strlen(host) + db_str.length() +
service_str.length() + 1;
size_t len = insert_sql_template.length() + strlen(user) + strlen(host) + db_str.length()
+ service_str.length() + 1;
char insert_sql[len + 1];
sprintf(insert_sql, insert_sql_template.c_str(), user, host, db_str.c_str(),
anydb ? "1" : "0", service_str.c_str());
sprintf(insert_sql,
insert_sql_template.c_str(),
user,
host,
db_str.c_str(),
anydb ? "1" : "0",
service_str.c_str());
char *err;
char* err;
if (sqlite3_exec(m_dbhandle, insert_sql, NULL, NULL, &err) != SQLITE_OK)
{
MXS_ERROR("Failed to insert user: %s", err);
@ -154,7 +162,7 @@ void PamInstance::delete_old_users()
{
/** Delete query used to clean up the database before loading new users */
const string delete_query = "DELETE FROM " + m_tablename;
char *err;
char* err;
if (sqlite3_exec(m_dbhandle, delete_query.c_str(), NULL, NULL, &err) != SQLITE_OK)
{
MXS_ERROR("Failed to delete old users: %s", err);
@ -172,17 +180,17 @@ void PamInstance::delete_old_users()
int PamInstance::load_users(SERVICE* service)
{
/** Query that gets all users that authenticate via the pam plugin */
const char PAM_USERS_QUERY[] =
"SELECT u.user, u.host, d.db, u.select_priv, u.authentication_string FROM "
"mysql.user AS u LEFT JOIN mysql.db AS d ON (u.user = d.user AND u.host = d.host) WHERE "
"(u.plugin = 'pam' AND (d.db IS NOT NULL OR u.select_priv = 'Y')) "
"UNION "
"SELECT u.user, u.host, t.db, u.select_priv, u.authentication_string FROM "
"mysql.user AS u LEFT JOIN mysql.tables_priv AS t ON (u.user = t.user AND u.host = t.host) WHERE "
"(u.plugin = 'pam' AND t.db IS NOT NULL AND u.select_priv = 'N') "
"ORDER BY user";
#if defined(SS_DEBUG)
const unsigned int PAM_USERS_QUERY_NUM_FIELDS = 5;
const char PAM_USERS_QUERY[]
= "SELECT u.user, u.host, d.db, u.select_priv, u.authentication_string FROM "
"mysql.user AS u LEFT JOIN mysql.db AS d ON (u.user = d.user AND u.host = d.host) WHERE "
"(u.plugin = 'pam' AND (d.db IS NOT NULL OR u.select_priv = 'Y')) "
"UNION "
"SELECT u.user, u.host, t.db, u.select_priv, u.authentication_string FROM "
"mysql.user AS u LEFT JOIN mysql.tables_priv AS t ON (u.user = t.user AND u.host = t.host) WHERE "
"(u.plugin = 'pam' AND t.db IS NOT NULL AND u.select_priv = 'N') "
"ORDER BY user";
#if defined (SS_DEBUG)
const unsigned int PAM_USERS_QUERY_NUM_FIELDS = 5;
#endif
const char* user;
@ -193,29 +201,33 @@ int PamInstance::load_users(SERVICE* service)
if ((pw = decrypt_password(password)))
{
for (SERVER_REF *servers = service->dbref; servers; servers = servers->next)
for (SERVER_REF* servers = service->dbref; servers; servers = servers->next)
{
MYSQL *mysql = mysql_init(NULL);
MYSQL* mysql = mysql_init(NULL);
if (mxs_mysql_real_connect(mysql, servers->server, user, pw))
{
if (mysql_query(mysql, PAM_USERS_QUERY))
{
MXS_ERROR("Failed to query server '%s' for PAM users: '%s'.",
servers->server->name, mysql_error(mysql));
servers->server->name,
mysql_error(mysql));
}
else
{
MYSQL_RES *res = mysql_store_result(mysql);
MYSQL_RES* res = mysql_store_result(mysql);
delete_old_users();
if (res)
{
mxb_assert(mysql_num_fields(res) == PAM_USERS_QUERY_NUM_FIELDS);
MXS_NOTICE("Loaded %llu users for service %s.", mysql_num_rows(res),
MXS_NOTICE("Loaded %llu users for service %s.",
mysql_num_rows(res),
service->name);
MYSQL_ROW row;
while ((row = mysql_fetch_row(res)))
{
add_pam_user(row[0], row[1], row[2],
add_pam_user(row[0],
row[1],
row[2],
row[3] && strcasecmp(row[3], "Y") == 0,
row[4]);
}
@ -267,7 +279,7 @@ void PamInstance::diagnostic(DCB* dcb)
json_decref(array);
}
static int diag_cb_json(void *data, int columns, char **row, char **field_names)
static int diag_cb_json(void* data, int columns, char** row, char** field_names)
{
mxb_assert(columns == NUM_FIELDS);
json_t* obj = json_object();
@ -283,7 +295,7 @@ static int diag_cb_json(void *data, int columns, char **row, char **field_names)
json_t* PamInstance::diagnostic_json()
{
json_t* rval = json_array();
char *err;
char* err;
string select = "SELECT * FROM " + m_tablename + ";";
if (sqlite3_exec(m_dbhandle, select.c_str(), diag_cb_json, rval, &err) != SQLITE_OK)
{
@ -308,12 +320,13 @@ bool PamInstance::query_anon_proxy_user(SERVER* server, MYSQL* conn)
if (mysql_query(conn, ANON_USER_QUERY))
{
MXS_ERROR("Failed to query server '%s' for the anonymous PAM user: '%s'.",
server->name, mysql_error(conn));
server->name,
mysql_error(conn));
success = false;
}
else
{
MYSQL_RES *res = mysql_store_result(conn);
MYSQL_RES* res = mysql_store_result(conn);
if (res)
{
MYSQL_ROW row = mysql_fetch_row(res);
@ -334,7 +347,8 @@ bool PamInstance::query_anon_proxy_user(SERVER* server, MYSQL* conn)
if (mysql_query(conn, ANON_GRANT_QUERY))
{
MXS_ERROR("Failed to query server '%s' for the grants of the anonymous PAM user: '%s'.",
server->name, mysql_error(conn));
server->name,
mysql_error(conn));
success = false;
}
else

View File

@ -10,7 +10,7 @@
* of this software will be governed by version 2 or later of the General
* Public License.
*/
#pragma once
#pragma once
#include "pam_auth.hh"
#include <string>
@ -23,22 +23,23 @@ class PamInstance
PamInstance(const PamInstance& orig);
PamInstance& operator=(const PamInstance&);
public:
static PamInstance* create(char **options);
static PamInstance* create(char** options);
~PamInstance();
int load_users(SERVICE* service);
void diagnostic(DCB* dcb);
int load_users(SERVICE* service);
void diagnostic(DCB* dcb);
json_t* diagnostic_json();
const std::string m_dbname; /**< Name of the in-memory database */
const std::string m_tablename; /**< The table where users are stored */
const std::string m_dbname; /**< Name of the in-memory database */
const std::string m_tablename; /**< The table where users are stored */
private:
PamInstance(sqlite3* dbhandle, const std::string& m_dbname, const std::string& tablename);
void add_pam_user(const char *user, const char *host, const char *db, bool anydb,
const char *pam_service);
void add_pam_user(const char* user,
const char* host,
const char* db,
bool anydb,
const char* pam_service);
void delete_old_users();
bool query_anon_proxy_user(SERVER* server, MYSQL* conn);
sqlite3 * const m_dbhandle; /**< SQLite3 database handle */
sqlite3* const m_dbhandle; /**< SQLite3 database handle */
};

View File

@ -19,13 +19,13 @@
#include "pam_backend_session.hh"
#include "../pam_auth_common.hh"
static void* pam_backend_auth_alloc(void *instance)
static void* pam_backend_auth_alloc(void* instance)
{
PamBackendSession* pses = new (std::nothrow) PamBackendSession();
PamBackendSession* pses = new( std::nothrow) PamBackendSession();
return pses;
}
static void pam_backend_auth_free(void *data)
static void pam_backend_auth_free(void* data)
{
delete static_cast<PamBackendSession*>(data);
}
@ -39,9 +39,9 @@ static void pam_backend_auth_free(void *data)
* @return MXS_AUTH_INCOMPLETE if authentication is ongoing, MXS_AUTH_SUCCEEDED
* if authentication is complete and MXS_AUTH_FAILED if authentication failed.
*/
static bool pam_backend_auth_extract(DCB *dcb, GWBUF *buffer)
static bool pam_backend_auth_extract(DCB* dcb, GWBUF* buffer)
{
PamBackendSession *pses = static_cast<PamBackendSession*>(dcb->authenticator_data);
PamBackendSession* pses = static_cast<PamBackendSession*>(dcb->authenticator_data);
return pses->extract(dcb, buffer);
}
@ -52,7 +52,7 @@ static bool pam_backend_auth_extract(DCB *dcb, GWBUF *buffer)
*
* @return True if DCB supports SSL
*/
static bool pam_backend_auth_connectssl(DCB *dcb)
static bool pam_backend_auth_connectssl(DCB* dcb)
{
return dcb->server->server_ssl != NULL;
}
@ -65,9 +65,9 @@ static bool pam_backend_auth_connectssl(DCB *dcb)
* @return MXS_AUTH_INCOMPLETE if authentication is ongoing, MXS_AUTH_SUCCEEDED
* if authentication is complete and MXS_AUTH_FAILED if authentication failed.
*/
static int pam_backend_auth_authenticate(DCB *dcb)
static int pam_backend_auth_authenticate(DCB* dcb)
{
PamBackendSession *pses = static_cast<PamBackendSession*>(dcb->authenticator_data);
PamBackendSession* pses = static_cast<PamBackendSession*>(dcb->authenticator_data);
return pses->authenticate(dcb);
}
@ -76,40 +76,39 @@ extern "C"
/**
* Module handle entry point
*/
MXS_MODULE* MXS_CREATE_MODULE()
{
static MXS_AUTHENTICATOR MyObject =
MXS_MODULE* MXS_CREATE_MODULE()
{
NULL, /* No initialize entry point */
pam_backend_auth_alloc, /* Allocate authenticator data */
pam_backend_auth_extract, /* Extract data into structure */
pam_backend_auth_connectssl, /* Check if client supports SSL */
pam_backend_auth_authenticate, /* Authenticate user credentials */
NULL, /* Client plugin will free shared data */
pam_backend_auth_free, /* Free authenticator data */
NULL, /* Load users from backend databases */
NULL, /* No diagnostic */
NULL,
NULL /* No user reauthentication */
};
static MXS_AUTHENTICATOR MyObject =
{
NULL, /* No initialize entry point */
pam_backend_auth_alloc, /* Allocate authenticator data */
pam_backend_auth_extract, /* Extract data into structure */
pam_backend_auth_connectssl, /* Check if client supports SSL */
pam_backend_auth_authenticate, /* Authenticate user credentials */
NULL, /* Client plugin will free shared data */
pam_backend_auth_free, /* Free authenticator data */
NULL, /* Load users from backend databases */
NULL, /* No diagnostic */
NULL,
NULL /* No user reauthentication */
};
static MXS_MODULE info =
{
MXS_MODULE_API_AUTHENTICATOR,
MXS_MODULE_ALPHA_RELEASE,
MXS_AUTHENTICATOR_VERSION,
"PAM backend authenticator",
"V1.0.0",
MXS_NO_MODULE_CAPABILITIES,
&MyObject,
NULL, /* Process init. */
NULL, /* Process finish. */
NULL, /* Thread init. */
NULL, /* Thread finish. */
{ { MXS_END_MODULE_PARAMS} }
};
return &info;
}
static MXS_MODULE info =
{
MXS_MODULE_API_AUTHENTICATOR,
MXS_MODULE_ALPHA_RELEASE,
MXS_AUTHENTICATOR_VERSION,
"PAM backend authenticator",
"V1.0.0",
MXS_NO_MODULE_CAPABILITIES,
&MyObject,
NULL, /* Process init. */
NULL, /* Process finish. */
NULL, /* Thread init. */
NULL, /* Thread finish. */
{{MXS_END_MODULE_PARAMS}}
};
return &info;
}
}

View File

@ -10,7 +10,7 @@
* of this software will be governed by version 2 or later of the General
* Public License.
*/
#pragma once
#pragma once
/**
* Common definitions and includes for PAMBackendAuth

View File

@ -17,14 +17,14 @@
namespace
{
/**
* Check that the AuthSwitchRequest packet is as expected. Inverse of
* create_auth_change_packet() in pam_auth.cc.
*
* @param dcb Backend DCB
* @param buffer Buffer containing an AuthSwitchRequest packet
* @return True on success, false on error
*/
bool check_auth_switch_request(DCB *dcb, GWBUF *buffer)
* Check that the AuthSwitchRequest packet is as expected. Inverse of
* create_auth_change_packet() in pam_auth.cc.
*
* @param dcb Backend DCB
* @param buffer Buffer containing an AuthSwitchRequest packet
* @return True on success, false on error
*/
bool check_auth_switch_request(DCB* dcb, GWBUF* buffer)
{
/**
* The AuthSwitchRequest packet:
@ -45,19 +45,22 @@ bool check_auth_switch_request(DCB *dcb, GWBUF *buffer)
/** Server responded with something we did not expect. If it's an OK packet,
* it's possible that the server authenticated us as the anonymous user. This
* means that the server is not secure. */
bool was_ok_packet = copied > MYSQL_HEADER_LEN &&
data[MYSQL_HEADER_LEN + 1] == MYSQL_REPLY_OK;
bool was_ok_packet = copied > MYSQL_HEADER_LEN
&& data[MYSQL_HEADER_LEN + 1] == MYSQL_REPLY_OK;
MXS_ERROR("Server '%s' returned an unexpected authentication response.%s",
dcb->server->name, was_ok_packet ?
" Authentication was complete before it even started, "
"anonymous users might not be disabled." : "");
dcb->server->name,
was_ok_packet
? " Authentication was complete before it even started, "
"anonymous users might not be disabled." : "");
return false;
}
unsigned int buflen = gwbuf_length(buffer);
if (buflen != expected_buflen)
{
MXS_ERROR("Length of server AuthSwitchRequest packet was '%u', expected '%u'. %s",
buflen, expected_buflen, GENERAL_ERRMSG);
buflen,
expected_buflen,
GENERAL_ERRMSG);
return false;
}
@ -68,9 +71,9 @@ bool check_auth_switch_request(DCB *dcb, GWBUF *buffer)
uint8_t* msg_loc = msg_type_loc + 1;
bool rval = false;
if ((DIALOG == (char*)plugin_name_loc) &&
(msg_type == DIALOG_ECHO_ENABLED || msg_type == DIALOG_ECHO_DISABLED) &&
PASSWORD.compare(0, PASSWORD.length(), (char*)msg_loc, PASSWORD.length()) == 0)
if ((DIALOG == (char*)plugin_name_loc)
&& (msg_type == DIALOG_ECHO_ENABLED || msg_type == DIALOG_ECHO_DISABLED)
&& PASSWORD.compare(0, PASSWORD.length(), (char*)msg_loc, PASSWORD.length()) == 0)
{
rval = true;
}
@ -93,10 +96,10 @@ PamBackendSession::PamBackendSession()
* @param dcb Backend DCB
* @return True on success, false on error
*/
bool PamBackendSession::send_client_password(DCB *dcb)
bool PamBackendSession::send_client_password(DCB* dcb)
{
bool rval = false;
MYSQL_session *ses = (MYSQL_session*)dcb->session->client_dcb->data;
MYSQL_session* ses = (MYSQL_session*)dcb->session->client_dcb->data;
size_t buflen = MYSQL_HEADER_LEN + ses->auth_token_len;
uint8_t bufferdata[buflen];
gw_mysql_set_byte3(bufferdata, ses->auth_token_len);
@ -105,7 +108,7 @@ bool PamBackendSession::send_client_password(DCB *dcb)
return dcb_write(dcb, gwbuf_alloc_and_load(buflen, bufferdata));
}
bool PamBackendSession::extract(DCB *dcb, GWBUF *buffer)
bool PamBackendSession::extract(DCB* dcb, GWBUF* buffer)
{
gwbuf_copy_data(buffer, MYSQL_SEQ_OFFSET, 1, &m_sequence);
m_sequence++;
@ -135,12 +138,13 @@ bool PamBackendSession::extract(DCB *dcb, GWBUF *buffer)
if (!rval)
{
MXS_DEBUG("pam_backend_auth_extract to backend '%s' failed for user '%s'.",
dcb->server->name, dcb->user);
dcb->server->name,
dcb->user);
}
return rval;
}
int PamBackendSession::authenticate(DCB *dcb)
int PamBackendSession::authenticate(DCB* dcb)
{
int rval = MXS_AUTH_FAILED;

View File

@ -10,7 +10,7 @@
* of this software will be governed by version 2 or later of the General
* Public License.
*/
#pragma once
#pragma once
#include "pam_backend_auth.hh"
#include <stdint.h>
@ -22,12 +22,12 @@ class PamBackendSession
PamBackendSession& operator=(const PamBackendSession&);
public:
PamBackendSession();
bool extract(DCB *dcb, GWBUF *buffer);
int authenticate(DCB *dcb);
bool extract(DCB* dcb, GWBUF* buffer);
int authenticate(DCB* dcb);
private:
bool send_client_password(DCB *dcb);
bool send_client_password(DCB* dcb);
pam_auth_state m_state; /**< Authentication state*/
uint8_t m_sequence; /**< The next packet seqence number */
pam_auth_state m_state; /**< Authentication state*/
uint8_t m_sequence; /**< The next packet seqence number */
};

View File

@ -10,7 +10,7 @@
* of this software will be governed by version 2 or later of the General
* Public License.
*/
#pragma once
#pragma once
/**
* Common declarations for both PAMAuth and PAMBackendAuth
@ -33,10 +33,9 @@ enum pam_auth_state
};
/* Magic numbers from server source
https://github.com/MariaDB/server/blob/10.2/plugin/auth_pam/auth_pam.c */
* https://github.com/MariaDB/server/blob/10.2/plugin/auth_pam/auth_pam.c */
enum dialog_plugin_msg_types
{
DIALOG_ECHO_ENABLED = 2,
DIALOG_ECHO_ENABLED = 2,
DIALOG_ECHO_DISABLED = 4
};