Add missing principal name verification to GSSAPIAuth
The authenticator module did not compare the username with the principal name that was given by the GSSAPI server.
This commit is contained in:
@ -31,16 +31,16 @@
|
|||||||
|
|
||||||
/** Query that gets all users that authenticate via the gssapi plugin */
|
/** Query that gets all users that authenticate via the gssapi plugin */
|
||||||
const char *gssapi_users_query =
|
const char *gssapi_users_query =
|
||||||
"SELECT u.user, u.host, d.db, u.select_priv FROM "
|
"SELECT u.user, u.host, d.db, u.select_priv, u.authentication_string FROM "
|
||||||
"mysql.user AS u LEFT JOIN mysql.db AS d "
|
"mysql.user AS u LEFT JOIN mysql.db AS d "
|
||||||
"ON (u.user = d.user AND u.host = d.host) WHERE u.plugin = 'gssapi' "
|
"ON (u.user = d.user AND u.host = d.host) WHERE u.plugin = 'gssapi' "
|
||||||
"UNION "
|
"UNION "
|
||||||
"SELECT u.user, u.host, t.db, u.select_priv FROM "
|
"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 "
|
"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' "
|
"ON (u.user = t.user AND u.host = t.host) WHERE u.plugin = 'gssapi' "
|
||||||
"ORDER BY user";
|
"ORDER BY user";
|
||||||
|
|
||||||
#define GSSAPI_USERS_QUERY_NUM_FIELDS 4
|
#define GSSAPI_USERS_QUERY_NUM_FIELDS 5
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* SQLite queries for authenticating users
|
* SQLite queries for authenticating users
|
||||||
@ -55,19 +55,20 @@ const char *gssapi_users_query =
|
|||||||
/** CREATE TABLE statement for the in-memory table */
|
/** CREATE TABLE statement for the in-memory table */
|
||||||
const char create_sql[] =
|
const char create_sql[] =
|
||||||
"CREATE TABLE IF NOT EXISTS " GSSAPI_TABLE_NAME
|
"CREATE TABLE IF NOT EXISTS " GSSAPI_TABLE_NAME
|
||||||
"(user varchar(255), host varchar(255), db varchar(255), anydb boolean)";
|
"(user varchar(255), host varchar(255), db varchar(255), anydb boolean, princ text)";
|
||||||
|
|
||||||
/** The query that is executed when a user is authenticated */
|
/** The query that is executed when a user is authenticated */
|
||||||
static const char gssapi_auth_query[] =
|
static const char gssapi_auth_query[] =
|
||||||
"SELECT * FROM " GSSAPI_TABLE_NAME
|
"SELECT * FROM " GSSAPI_TABLE_NAME
|
||||||
" WHERE user = '%s' AND '%s' LIKE host AND (anydb = '1' OR '%s' = '' OR '%s' LIKE db) LIMIT 1";
|
" 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 */
|
/** Delete query used to clean up the database before loading new users */
|
||||||
static const char delete_query[] = "DELETE FROM " GSSAPI_TABLE_NAME;
|
static const char delete_query[] = "DELETE FROM " GSSAPI_TABLE_NAME;
|
||||||
|
|
||||||
/** The insert query template which adds users to the gssapi_users table */
|
/** The insert query template which adds users to the gssapi_users table */
|
||||||
static const char insert_sql_pattern[] =
|
static const char insert_sql_pattern[] =
|
||||||
"INSERT INTO " GSSAPI_TABLE_NAME " VALUES ('%s', '%s', %s, %s)";
|
"INSERT INTO " GSSAPI_TABLE_NAME " VALUES ('%s', '%s', %s, %s, %s)";
|
||||||
|
|
||||||
/** Used for NULL value creation in the INSERT query */
|
/** Used for NULL value creation in the INSERT query */
|
||||||
static const char null_token[] = "NULL";
|
static const char null_token[] = "NULL";
|
||||||
@ -316,9 +317,10 @@ static gss_name_t server_name = GSS_C_NO_NAME;
|
|||||||
*
|
*
|
||||||
* @param token Client token
|
* @param token Client token
|
||||||
* @param len Length of the token
|
* @param len Length of the token
|
||||||
|
* @param output Pointer where the client principal name is stored
|
||||||
* @return True if client token is valid
|
* @return True if client token is valid
|
||||||
*/
|
*/
|
||||||
static bool validate_gssapi_token(char* principal, uint8_t* token, size_t len)
|
static bool validate_gssapi_token(char* principal, uint8_t* token, size_t len, char **output)
|
||||||
{
|
{
|
||||||
OM_uint32 major = 0, minor = 0;
|
OM_uint32 major = 0, minor = 0;
|
||||||
gss_buffer_desc server_buf = {0, 0};
|
gss_buffer_desc server_buf = {0, 0};
|
||||||
@ -350,21 +352,41 @@ static bool validate_gssapi_token(char* principal, uint8_t* token, size_t len)
|
|||||||
gss_ctx_id_t handle = NULL;
|
gss_ctx_id_t handle = NULL;
|
||||||
gss_buffer_desc in = {0, 0};
|
gss_buffer_desc in = {0, 0};
|
||||||
gss_buffer_desc out = {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.value = token;
|
||||||
in.length = len;
|
in.length = len;
|
||||||
|
|
||||||
major = gss_accept_sec_context(&minor, &handle, GSS_C_NO_CREDENTIAL,
|
major = gss_accept_sec_context(&minor, &handle, GSS_C_NO_CREDENTIAL,
|
||||||
&in, GSS_C_NO_CHANNEL_BINDINGS,
|
&in, GSS_C_NO_CHANNEL_BINDINGS,
|
||||||
&server_name, &oid, &out,
|
&client, &oid, &out,
|
||||||
0, 0, NULL);
|
0, 0, NULL);
|
||||||
if (GSS_ERROR(major))
|
if (GSS_ERROR(major))
|
||||||
{
|
{
|
||||||
return false;
|
|
||||||
report_error(major, minor);
|
report_error(major, minor);
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
major = gss_display_name(&minor, client, &client_name, NULL);
|
||||||
|
|
||||||
|
if (GSS_ERROR(major))
|
||||||
|
{
|
||||||
|
report_error(major, minor);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
char *princ_name = MXS_MALLOC(client_name.length + 1);
|
||||||
|
|
||||||
|
if (!princ_name)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
memcpy(princ_name, (const char*)client_name.value, client_name.length);
|
||||||
|
princ_name[client_name.length] = '\0';
|
||||||
|
*output = princ_name;
|
||||||
}
|
}
|
||||||
while (major & GSS_S_CONTINUE_NEEDED);
|
while (major & GSS_S_CONTINUE_NEEDED);
|
||||||
|
|
||||||
@ -385,17 +407,28 @@ static int auth_cb(void *data, int columns, char** rows, char** row_names)
|
|||||||
* @param auth Authenticator session
|
* @param auth Authenticator session
|
||||||
* @param dcb Client DCB
|
* @param dcb Client DCB
|
||||||
* @param session MySQL session
|
* @param session MySQL session
|
||||||
|
* @param princ Client principal name
|
||||||
* @return True if the user has access to the database
|
* @return True if the user has access to the database
|
||||||
*/
|
*/
|
||||||
static bool validate_user(gssapi_auth_t *auth, DCB *dcb, MYSQL_session *session)
|
static bool validate_user(gssapi_auth_t *auth, DCB *dcb, MYSQL_session *session, const char *princ)
|
||||||
{
|
{
|
||||||
size_t len = sizeof(gssapi_auth_query) + strlen(session->user) +
|
ss_dassert(princ);
|
||||||
strlen(session->db) + strlen(dcb->remote);
|
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];
|
char sql[len + 1];
|
||||||
bool rval = false;
|
bool rval = false;
|
||||||
char *err;
|
char *err;
|
||||||
|
|
||||||
sprintf(sql, gssapi_auth_query, session->user, dcb->remote, session->db, session->db);
|
char princ_user[strlen(princ) + 1];
|
||||||
|
strcpy(princ_user, princ);
|
||||||
|
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);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Try authentication twice; first time with the current users, second
|
* Try authentication twice; first time with the current users, second
|
||||||
@ -452,12 +485,15 @@ int gssapi_auth_authenticate(DCB *dcb)
|
|||||||
* token that we must validate */
|
* token that we must validate */
|
||||||
|
|
||||||
MYSQL_session *ses = (MYSQL_session*)dcb->data;
|
MYSQL_session *ses = (MYSQL_session*)dcb->data;
|
||||||
|
char *princ = NULL;
|
||||||
|
|
||||||
if (validate_gssapi_token(instance->principal_name, ses->auth_token, ses->auth_token_len) &&
|
if (validate_gssapi_token(instance->principal_name, ses->auth_token, ses->auth_token_len, &princ) &&
|
||||||
validate_user(auth, dcb, ses))
|
validate_user(auth, dcb, ses, princ))
|
||||||
{
|
{
|
||||||
rval = MXS_AUTH_SUCCEEDED;
|
rval = MXS_AUTH_SUCCEEDED;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
MXS_FREE(princ);
|
||||||
}
|
}
|
||||||
|
|
||||||
return rval;
|
return rval;
|
||||||
@ -504,7 +540,7 @@ static void delete_old_users(sqlite3 *handle)
|
|||||||
* @param anydb Global access to databases
|
* @param anydb Global access to databases
|
||||||
*/
|
*/
|
||||||
static void add_gssapi_user(sqlite3 *handle, const char *user, const char *host,
|
static void add_gssapi_user(sqlite3 *handle, const char *user, const char *host,
|
||||||
const char *db, bool anydb)
|
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];
|
char dbstr[dblen + 1];
|
||||||
@ -518,9 +554,22 @@ static void add_gssapi_user(sqlite3 *handle, const char *user, const char *host,
|
|||||||
strcpy(dbstr, null_token);
|
strcpy(dbstr, null_token);
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t len = sizeof(insert_sql_pattern) + strlen(user) + strlen(host) + dblen + 1;
|
size_t princlen = princ && *princ ? strlen(princ) + 2 : sizeof(null_token); /** +2 for single quotes */
|
||||||
|
char princstr[princlen + 1];
|
||||||
|
|
||||||
|
if (princ && *princ)
|
||||||
|
{
|
||||||
|
sprintf(princstr, "'%s'", princ);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
strcpy(princstr, null_token);
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t len = sizeof(insert_sql_pattern) + strlen(user) + strlen(host) + dblen + princlen + 1;
|
||||||
|
|
||||||
char insert_sql[len + 1];
|
char insert_sql[len + 1];
|
||||||
sprintf(insert_sql, insert_sql_pattern, user, host, dbstr, anydb ? "1" : "0");
|
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)
|
if (sqlite3_exec(handle, insert_sql, NULL, NULL, &err) != SQLITE_OK)
|
||||||
@ -574,7 +623,8 @@ int gssapi_auth_load_users(SERV_LISTENER *listener)
|
|||||||
while ((row = mysql_fetch_row(res)))
|
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[3] && strcasecmp(row[3], "Y") == 0,
|
||||||
|
row[4]);
|
||||||
}
|
}
|
||||||
|
|
||||||
rval = MXS_AUTH_LOADUSERS_OK;
|
rval = MXS_AUTH_LOADUSERS_OK;
|
||||||
|
Reference in New Issue
Block a user