MXS-862: Make packet sequence handling automatic

Made the packet sequence number handling automatic so that it always uses
the correct one.

All functions now have documentation in them. Cleaned up code and added
comments to GSSAPI code.
This commit is contained in:
Markus Makela
2016-10-13 23:10:59 +03:00
parent 68e53567a0
commit 571919264f
6 changed files with 122 additions and 37 deletions

View File

@ -19,11 +19,14 @@
#include "gssapi_auth.h"
/**
* @file gssapi_backend_auth.c GSSAPI backend authenticator
* @file gssapi_backend_auth.c - GSSAPI backend authenticator
*/
/** TODO: Document functions and GSSAPI specific code */
/**
* @brief Create a new GSSAPI token
* @param dcb Backend DCB
* @return True on success, false on error
*/
static bool send_new_auth_token(DCB *dcb)
{
bool rval = false;
@ -35,9 +38,11 @@ static bool send_new_auth_token(DCB *dcb)
gss_name_t princ = GSS_C_NO_NAME;
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;
target.length = auth->principal_name_len + 1;
/** Convert the name into GSSAPI format */
major = gss_import_name(&minor, &target, GSS_C_NT_USER_NAME, &princ);
if (GSS_ERROR(major))
@ -45,6 +50,7 @@ static bool send_new_auth_token(DCB *dcb)
report_error(major, minor);
}
/** 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);
@ -54,6 +60,7 @@ 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);
if (buffer)
@ -61,8 +68,9 @@ static bool send_new_auth_token(DCB *dcb)
uint8_t *data = (uint8_t*)GWBUF_DATA(buffer);
gw_mysql_set_byte3(data, out.length);
data += 3;
*data++ = 0x03;
*data++ = ++auth->sequence;
memcpy(data, out.value, out.length);
if (dcb_write(dcb, buffer))
{
rval = true;
@ -77,6 +85,7 @@ static bool send_new_auth_token(DCB *dcb)
}
major = gss_release_name(&minor, &princ);
if (GSS_ERROR(major))
{
report_error(major, minor);
@ -87,15 +96,48 @@ static bool send_new_auth_token(DCB *dcb)
}
/**
* @brief Extract the principal name from the AuthSwitchRequest packet
*
* @param dcb Backend DCB
* @param buffer Buffer containing an AuthSwitchRequest packet
* @return True on success, false on error
*/
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;
gssapi_auth_t *auth = (gssapi_auth_t*)dcb->authenticator_data;
while (*data)
/** Copy the payload and the current packet sequence number */
gwbuf_copy_data(buffer, MYSQL_HEADER_LEN, buflen, databuf);
gwbuf_copy_data(buffer, MYSQL_SEQ_OFFSET, 1, &auth->sequence);
if (databuf[0] != MYSQL_REPLY_AUTHSWITCHREQUEST)
{
/** 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. */
MXS_ERROR("Server '%s' returned an unexpected authentication response.%s",
dcb->server->unique_name, databuf[0] == MYSQL_REPLY_OK ?
" Authentication was complete before it even started, "
"anonymous users might not be disabled." : "");
return false;
}
/**
* The AuthSwitchRequest packet
*
* 0xfe - Command byte
* string[NUL] - Auth plugin name
* string[EOF] - Auth plugin data
*
* Skip over the auth plugin name and copy the service principal name stored
* in the auth plugin data section.
*/
while (*data && data < databuf + buflen)
{
data++;
}
@ -103,35 +145,51 @@ bool extract_principal_name(DCB *dcb, GWBUF *buffer)
data++;
buflen -= data - databuf;
uint8_t *principal = MXS_MALLOC(buflen);
if (principal)
if (buflen > 0)
{
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;
uint8_t *principal = MXS_MALLOC(buflen + 1);
if (principal)
{
/** Store the principal name for later when we request the token
* from the GSSAPI server */
memcpy(principal, data, buflen);
principal[buflen] = '\0';
auth->principal_name = principal;
auth->principal_name_len = buflen;
rval = true;
}
}
else
{
MXS_ERROR("Backend server did not send any auth plugin data.");
}
return rval;
}
/**
* @brief Extract data from a MySQL packet
* @param dcb Backend DCB
* @param buffer Buffer containing a complete packet
* @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_extract(DCB *dcb, GWBUF *buffer)
{
int rval = MXS_AUTH_FAILED;
gssapi_auth_t *data = (gssapi_auth_t*)dcb->authenticator_data;
gssapi_auth_t *auth = (gssapi_auth_t*)dcb->authenticator_data;
if (data->state == GSSAPI_AUTH_INIT && extract_principal_name(dcb, buffer))
if (auth->state == GSSAPI_AUTH_INIT && extract_principal_name(dcb, buffer))
{
rval = MXS_AUTH_INCOMPLETE;
}
else if (data->state == GSSAPI_AUTH_DATA_SENT)
else if (auth->state == GSSAPI_AUTH_DATA_SENT)
{
/** Read authentication response */
if (mxs_mysql_is_ok_packet(buffer))
{
data->state = GSSAPI_AUTH_OK;
auth->state = GSSAPI_AUTH_OK;
rval = MXS_AUTH_SUCCEEDED;
}
}
@ -139,26 +197,37 @@ static int gssapi_backend_auth_extract(DCB *dcb, GWBUF *buffer)
return rval;
}
/**
* @brief Check whether the DCB supports SSL
* @param dcb Backend DCB
* @return True if DCB supports SSL
*/
static bool gssapi_backend_auth_connectssl(DCB *dcb)
{
return dcb->server->server_ssl != NULL;
}
/**
* @brief Authenticate the backend connection
* @param dcb Backend 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)
{
int rval = MXS_AUTH_FAILED;
gssapi_auth_t *auth_data = (gssapi_auth_t*)dcb->authenticator_data;
gssapi_auth_t *auth = (gssapi_auth_t*)dcb->authenticator_data;
if (auth_data->state == GSSAPI_AUTH_INIT)
if (auth->state == GSSAPI_AUTH_INIT)
{
if (send_new_auth_token(dcb))
{
rval = MXS_AUTH_INCOMPLETE;
auth_data->state = GSSAPI_AUTH_DATA_SENT;
auth->state = GSSAPI_AUTH_DATA_SENT;
}
}
else if (auth_data->state == GSSAPI_AUTH_OK)
else if (auth->state == GSSAPI_AUTH_OK)
{
rval = MXS_AUTH_SUCCEEDED;
}
@ -171,7 +240,7 @@ static int gssapi_backend_auth_authenticate(DCB *dcb)
*/
static GWAUTHENTICATOR MyObject =
{
NULL, /* TODO: implement initialize entry point */
NULL, /* No initialize entry point */
gssapi_auth_alloc, /* Allocate authenticator data */
gssapi_backend_auth_extract, /* Extract data into structure */
gssapi_backend_auth_connectssl, /* Check if client supports SSL */