Handle error response during caching_sha2_password auth

In particular, this fixes handling of expired passwords.
This commit is contained in:
Nikita Popov 2019-12-27 16:07:28 +01:00
parent e7e1254f3e
commit 813d4a00b4
3 changed files with 24 additions and 6 deletions

View file

@ -1073,6 +1073,13 @@ mysqlnd_caching_sha2_handle_server_response(struct st_mysqlnd_authentication_plu
} }
switch (result_packet.response_code) { switch (result_packet.response_code) {
case 0xFF:
if (result_packet.sqlstate[0]) {
strlcpy(conn->error_info->sqlstate, result_packet.sqlstate, sizeof(conn->error_info->sqlstate));
DBG_ERR_FMT("ERROR:%u [SQLSTATE:%s] %s", result_packet.error_no, result_packet.sqlstate, result_packet.error);
}
SET_CLIENT_ERROR(conn->error_info, result_packet.error_no, UNKNOWN_SQLSTATE, result_packet.error);
DBG_RETURN(FAIL);
case 0xFE: case 0xFE:
DBG_INF("auth switch response"); DBG_INF("auth switch response");
*new_auth_protocol = result_packet.new_auth_protocol; *new_auth_protocol = result_packet.new_auth_protocol;

View file

@ -2178,7 +2178,6 @@ php_mysqlnd_cached_sha2_result_read(MYSQLND_CONN_DATA * conn, void * _packet)
zend_uchar buf[SHA256_PK_REQUEST_RESP_BUFFER_SIZE]; zend_uchar buf[SHA256_PK_REQUEST_RESP_BUFFER_SIZE];
zend_uchar *p = buf; zend_uchar *p = buf;
const zend_uchar * const begin = buf; const zend_uchar * const begin = buf;
uint8_t main_response_code;
DBG_ENTER("php_mysqlnd_cached_sha2_result_read"); DBG_ENTER("php_mysqlnd_cached_sha2_result_read");
if (FAIL == mysqlnd_read_packet_header_and_body(&(packet->header), pfc, vio, stats, error_info, connection_state, buf, sizeof(buf), "PROT_CACHED_SHA2_RESULT_PACKET", PROT_CACHED_SHA2_RESULT_PACKET)) { if (FAIL == mysqlnd_read_packet_header_and_body(&(packet->header), pfc, vio, stats, error_info, connection_state, buf, sizeof(buf), "PROT_CACHED_SHA2_RESULT_PACKET", PROT_CACHED_SHA2_RESULT_PACKET)) {
@ -2186,12 +2185,18 @@ php_mysqlnd_cached_sha2_result_read(MYSQLND_CONN_DATA * conn, void * _packet)
} }
BAIL_IF_NO_MORE_DATA; BAIL_IF_NO_MORE_DATA;
main_response_code = uint1korr(p); packet->response_code = uint1korr(p);
p++; p++;
BAIL_IF_NO_MORE_DATA; BAIL_IF_NO_MORE_DATA;
if (0xFE == main_response_code) { if (ERROR_MARKER == packet->response_code) {
packet->response_code = main_response_code; php_mysqlnd_read_error_from_line(p, packet->header.size - 1,
packet->error, sizeof(packet->error),
&packet->error_no, packet->sqlstate
);
DBG_RETURN(PASS);
}
if (0xFE == packet->response_code) {
/* Authentication Switch Response */ /* Authentication Switch Response */
if (packet->header.size > (size_t) (p - buf)) { if (packet->header.size > (size_t) (p - buf)) {
packet->new_auth_protocol = mnd_pestrdup((char *)p, FALSE); packet->new_auth_protocol = mnd_pestrdup((char *)p, FALSE);
@ -2209,10 +2214,11 @@ php_mysqlnd_cached_sha2_result_read(MYSQLND_CONN_DATA * conn, void * _packet)
DBG_RETURN(PASS); DBG_RETURN(PASS);
} }
if (0x1 != main_response_code) { if (0x1 != packet->response_code) {
DBG_ERR_FMT("Unexpected response code %d", main_response_code); DBG_ERR_FMT("Unexpected response code %d", packet->response_code);
} }
/* This is not really the response code, but we reuse the field. */
packet->response_code = uint1korr(p); packet->response_code = uint1korr(p);
p++; p++;
BAIL_IF_NO_MORE_DATA; BAIL_IF_NO_MORE_DATA;

View file

@ -288,10 +288,15 @@ typedef struct st_mysqlnd_packet_cached_sha2_result {
uint8_t request; uint8_t request;
zend_uchar * password; zend_uchar * password;
size_t password_len; size_t password_len;
/* Used for auth switch request */
char *new_auth_protocol; char *new_auth_protocol;
size_t new_auth_protocol_len; size_t new_auth_protocol_len;
zend_uchar *new_auth_protocol_data; zend_uchar *new_auth_protocol_data;
size_t new_auth_protocol_data_len; size_t new_auth_protocol_data_len;
/* Used for error result */
char error[MYSQLND_ERRMSG_SIZE+1];
char sqlstate[MYSQLND_SQLSTATE_LENGTH + 1];
unsigned int error_no;
} MYSQLND_PACKET_CACHED_SHA2_RESULT; } MYSQLND_PACKET_CACHED_SHA2_RESULT;