diff --git a/server/modules/authenticator/gssapi_auth.c b/server/modules/authenticator/gssapi_auth.c index 27d574950..d166c3ed8 100644 --- a/server/modules/authenticator/gssapi_auth.c +++ b/server/modules/authenticator/gssapi_auth.c @@ -15,7 +15,6 @@ #include #include #include -#include #include "gssapi_auth.h" /** @@ -87,9 +86,14 @@ bool store_client_token(DCB *dcb, GWBUF *buffer) * @param dcb Client DCB * @param buffer Buffer containing the first authentication response */ -static void copy_shared_username(DCB *dcb, GWBUF *buffer) +static void copy_client_information(DCB *dcb, GWBUF *buffer) { size_t buflen = gwbuf_length(buffer); + MySQLProtocol *protocol = (MySQLProtocol*)dcb->protocol; + /* Take data from fixed locations first */ + gwbuf_copy_data(buffer, 4, 4, (uint8_t*)&protocol->client_capabilities); + protocol->charset = 0; + gwbuf_copy_data(buffer, 4 + 4 + 4, 1, (uint8_t*)&protocol->charset); if (buflen > MYSQL_AUTH_PACKET_BASE_SIZE) { @@ -123,7 +127,7 @@ static int gssapi_auth_extract(DCB *dcb, GWBUF *read_buffer) switch (auth->state) { case GSSAPI_AUTH_INIT: - copy_shared_username(dcb, read_buffer); + copy_client_information(dcb, read_buffer); rval = MXS_AUTH_SUCCEEDED; break; @@ -153,38 +157,6 @@ bool gssapi_auth_connectssl(DCB *dcb) return protocol->client_capabilities & GW_MYSQL_CAPABILITIES_SSL; } -/** - * @brief Report GSSAPI errors - * - * @param major GSSAPI major error number - * @param minor GSSAPI minor error number - */ -static void report_error(OM_uint32 major, OM_uint32 minor) -{ - OM_uint32 status_maj = major; - OM_uint32 status_min = minor; - OM_uint32 res = 0; - gss_buffer_desc buf = {0, 0}; - - major = gss_display_status(&minor, status_maj, GSS_C_GSS_CODE, NULL, &res, &buf); - - { - char sbuf[buf.length + 1]; - memcpy(sbuf, buf.value, buf.length); - sbuf[buf.length] = '\0'; - MXS_ERROR("GSSAPI Major Error: %s", sbuf); - } - - major = gss_display_status(&minor, status_min, GSS_C_MECH_CODE, NULL, &res, &buf); - - { - char sbuf[buf.length + 1]; - memcpy(sbuf, buf.value, buf.length); - sbuf[buf.length] = '\0'; - MXS_ERROR("GSSAPI Minor Error: %s", sbuf); - } -} - static gss_name_t server_name = GSS_C_NO_NAME; /** diff --git a/server/modules/authenticator/gssapi_auth.h b/server/modules/authenticator/gssapi_auth.h index cb2ca6084..819768f1e 100644 --- a/server/modules/authenticator/gssapi_auth.h +++ b/server/modules/authenticator/gssapi_auth.h @@ -14,6 +14,9 @@ #ifndef _GSSAPI_AUTH_H #define _GSSAPI_AUTH_H +#include +#include +#include /** Client auth plugin name */ static const char auth_plugin_name[] = "auth_gssapi_client"; @@ -34,10 +37,15 @@ enum gssapi_auth_state typedef struct gssapi_auth { enum gssapi_auth_state state; + uint8_t *principal_name; + size_t principal_name_len; } gssapi_auth_t; /** These functions can used for the `create` and `destroy` entry points */ void* gssapi_auth_alloc(); void gssapi_auth_free(void *data); +/** Report GSSAPI errors */ +void report_error(OM_uint32 major, OM_uint32 minor); + #endif diff --git a/server/modules/authenticator/gssapi_auth_common.c b/server/modules/authenticator/gssapi_auth_common.c index a6bcef631..a147c7186 100644 --- a/server/modules/authenticator/gssapi_auth_common.c +++ b/server/modules/authenticator/gssapi_auth_common.c @@ -21,6 +21,8 @@ void* gssapi_auth_alloc() if (rval) { rval->state = GSSAPI_AUTH_INIT; + rval->principal_name = NULL; + rval->principal_name_len = 0; } return rval; @@ -30,6 +32,40 @@ void gssapi_auth_free(void *data) { if (data) { - MXS_FREE(data); + gssapi_auth_t *auth = (gssapi_auth_t*)data; + MXS_FREE(auth->principal_name); + MXS_FREE(auth); + } +} + +/** + * @brief Report GSSAPI errors + * + * @param major GSSAPI major error number + * @param minor GSSAPI minor error number + */ +void report_error(OM_uint32 major, OM_uint32 minor) +{ + OM_uint32 status_maj = major; + OM_uint32 status_min = minor; + OM_uint32 res = 0; + gss_buffer_desc buf = {0, 0}; + + major = gss_display_status(&minor, status_maj, GSS_C_GSS_CODE, NULL, &res, &buf); + + { + char sbuf[buf.length + 1]; + memcpy(sbuf, buf.value, buf.length); + sbuf[buf.length] = '\0'; + MXS_ERROR("GSSAPI Major Error: %s", sbuf); + } + + major = gss_display_status(&minor, status_min, GSS_C_MECH_CODE, NULL, &res, &buf); + + { + char sbuf[buf.length + 1]; + memcpy(sbuf, buf.value, buf.length); + sbuf[buf.length] = '\0'; + MXS_ERROR("GSSAPI Minor Error: %s", sbuf); } } diff --git a/server/modules/authenticator/gssapi_backend_auth.c b/server/modules/authenticator/gssapi_backend_auth.c index 38b260aae..a6c8e2c06 100644 --- a/server/modules/authenticator/gssapi_backend_auth.c +++ b/server/modules/authenticator/gssapi_backend_auth.c @@ -15,17 +15,127 @@ #include #include #include -#include #include "gssapi_auth.h" /** * @file gssapi_backend_auth.c GSSAPI backend authenticator */ +/** TODO: Document functions and GSSAPI specific code */ + +static bool send_new_auth_token(DCB *dcb) +{ + bool rval = false; + OM_uint32 major = 0, minor = 0; + gss_ctx_id_t handle = NULL; + gss_buffer_desc in = {0, 0}; + 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; + + target.value = auth->principal_name; + target.length = auth->principal_name_len + 1; + + major = gss_import_name(&minor, &target, GSS_C_NT_USER_NAME, &princ); + + if (GSS_ERROR(major)) + { + report_error(major, minor); + } + + 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); + } + else + { + GWBUF *buffer = gwbuf_alloc(MYSQL_HEADER_LEN + out.length); + + if (buffer) + { + uint8_t *data = (uint8_t*)GWBUF_DATA(buffer); + gw_mysql_set_byte3(data, out.length); + data += 3; + *data++ = 0x03; + memcpy(data, out.value, out.length); + if (dcb_write(dcb, buffer)) + { + rval = true; + } + } + + major = gss_delete_sec_context(&minor, &handle, &in); + + if (GSS_ERROR(major)) + { + report_error(major, minor); + } + + major = gss_release_name(&minor, &princ); + if (GSS_ERROR(major)) + { + report_error(major, minor); + } + } + + return rval; + +} + +bool extract_principal_name(DCB *dcb, GWBUF *buffer) +{ + bool rval = false; + size_t buflen = gwbuf_length(buffer) - MYSQL_HEADER_LEN; + uint8_t databuf[buflen]; + gwbuf_copy_data(buffer, MYSQL_HEADER_LEN, buflen, databuf); + uint8_t *data = databuf; + + while (*data) + { + data++; + } + + data++; + buflen -= data - databuf; + + uint8_t *principal = MXS_MALLOC(buflen); + + if (principal) + { + memcpy(principal, data, buflen); + gssapi_auth_t *auth = (gssapi_auth_t*)dcb->authenticator_data; + auth->principal_name = principal; + auth->principal_name_len = buflen; + rval = true; + } + + return rval; +} + static int gssapi_backend_auth_extract(DCB *dcb, GWBUF *buffer) { - gw_send_backend_auth(dcb); - return MXS_AUTH_SUCCEEDED; + int rval = MXS_AUTH_FAILED; + gssapi_auth_t *data = (gssapi_auth_t*)dcb->authenticator_data; + + if (data->state == GSSAPI_AUTH_INIT && extract_principal_name(dcb, buffer)) + { + rval = MXS_AUTH_INCOMPLETE; + } + else if (data->state == GSSAPI_AUTH_DATA_SENT) + { + /** Read authentication response */ + if (mxs_mysql_is_ok_packet(buffer)) + { + data->state = GSSAPI_AUTH_OK; + rval = MXS_AUTH_SUCCEEDED; + } + } + + return rval; } static bool gssapi_backend_auth_connectssl(DCB *dcb) @@ -35,7 +145,24 @@ static bool gssapi_backend_auth_connectssl(DCB *dcb) static int gssapi_backend_auth_authenticate(DCB *dcb) { - return MXS_AUTH_SUCCEEDED; + int rval = MXS_AUTH_FAILED; + gssapi_auth_t *auth_data = (gssapi_auth_t*)dcb->authenticator_data; + + if (auth_data->state == GSSAPI_AUTH_INIT) + { + if (send_new_auth_token(dcb)) + { + rval = MXS_AUTH_INCOMPLETE; + auth_data->state = GSSAPI_AUTH_DATA_SENT; + } + + } + else if (auth_data->state == GSSAPI_AUTH_OK) + { + rval = MXS_AUTH_SUCCEEDED; + } + + return rval; } /** @@ -43,13 +170,13 @@ static int gssapi_backend_auth_authenticate(DCB *dcb) */ static GWAUTHENTICATOR MyObject = { - gssapi_auth_alloc, - 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, - gssapi_auth_free, - NULL /* Load users from backend databases */ + gssapi_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_auth_free, /* Free authenticator data */ + NULL /* Load users from backend databases */ }; MODULE_INFO info = diff --git a/server/modules/protocol/MySQL/mysql_common.c b/server/modules/protocol/MySQL/mysql_common.c index cfe6abe91..834256fe4 100644 --- a/server/modules/protocol/MySQL/mysql_common.c +++ b/server/modules/protocol/MySQL/mysql_common.c @@ -1354,7 +1354,7 @@ mxs_auth_state_t gw_send_backend_auth(DCB *dcb) */ const char* auth_plugin_name = DEFAULT_MYSQL_AUTH_PLUGIN; - long bytes = response_length(conn, local_session.user, local_session.client_sha1, + long bytes = response_length(conn, local_session.user, curr_passwd, local_session.db, auth_plugin_name); // allocating the GWBUF