Merge branch 'PHP-7.4'

* PHP-7.4:
  Handle empty password fast path in caching_sha2_password
  Handle error response during caching_sha2_password auth
  Add support for caching_sha2_password in change user authentication
  Fix unix socket check during caching_sha2_password
  Support auth switch request during caching sha2 auth
This commit is contained in:
Nikita Popov 2019-12-27 17:31:27 +01:00
commit 184f118d3f
6 changed files with 111 additions and 20 deletions

View File

@ -136,6 +136,7 @@ mysqlnd_run_authentication(
ret = mysqlnd_auth_change_user(conn, user, strlen(user), passwd, passwd_len, db, db_len, silent,
first_call,
requested_protocol,
auth_plugin, plugin_data, plugin_data_len,
scrambled_data, scrambled_data_len,
&switch_to_auth_protocol, &switch_to_auth_protocol_len,
&switch_to_auth_protocol_data, &switch_to_auth_protocol_data_len
@ -318,8 +319,12 @@ mysqlnd_auth_handshake(MYSQLND_CONN_DATA * conn,
}
if (auth_plugin && auth_plugin->methods.handle_server_response) {
auth_plugin->methods.handle_server_response(auth_plugin, conn,
orig_auth_plugin_data, orig_auth_plugin_data_len, passwd, passwd_len);
if (FAIL == auth_plugin->methods.handle_server_response(auth_plugin, conn,
orig_auth_plugin_data, orig_auth_plugin_data_len, passwd, passwd_len,
switch_to_auth_protocol, switch_to_auth_protocol_len,
switch_to_auth_protocol_data, switch_to_auth_protocol_data_len)) {
goto end;
}
}
if (FAIL == PACKET_READ(conn, &auth_resp_packet) || auth_resp_packet.response_code >= 0xFE) {
@ -371,6 +376,9 @@ mysqlnd_auth_change_user(MYSQLND_CONN_DATA * const conn,
const zend_bool silent,
const zend_bool use_full_blown_auth_packet,
const char * const auth_protocol,
struct st_mysqlnd_authentication_plugin * auth_plugin,
const zend_uchar * const orig_auth_plugin_data,
const size_t orig_auth_plugin_data_len,
const zend_uchar * const auth_plugin_data,
const size_t auth_plugin_data_len,
char ** switch_to_auth_protocol,
@ -436,6 +444,15 @@ mysqlnd_auth_change_user(MYSQLND_CONN_DATA * const conn,
PACKET_FREE(&auth_packet);
}
if (auth_plugin && auth_plugin->methods.handle_server_response) {
if (FAIL == auth_plugin->methods.handle_server_response(auth_plugin, conn,
orig_auth_plugin_data, orig_auth_plugin_data_len, passwd, passwd_len,
switch_to_auth_protocol, switch_to_auth_protocol_len,
switch_to_auth_protocol_data, switch_to_auth_protocol_data_len)) {
goto end;
}
}
ret = PACKET_READ(conn, &chg_user_resp);
COPY_CLIENT_ERROR(conn->error_info, chg_user_resp.error_info);
@ -1026,39 +1043,69 @@ mysqlnd_caching_sha2_get_and_use_key(MYSQLND_CONN_DATA *conn,
}
/* }}} */
/* {{{ mysqlnd_native_auth_get_auth_data */
static void
static int is_secure_transport(MYSQLND_CONN_DATA *conn) {
if (conn->vio->data->ssl) {
return 1;
}
return strcmp(conn->vio->data->stream->ops->label, "unix_socket") == 0;
}
/* {{{ mysqlnd_caching_sha2_handle_server_response */
static enum_func_status
mysqlnd_caching_sha2_handle_server_response(struct st_mysqlnd_authentication_plugin *self,
MYSQLND_CONN_DATA * conn,
const zend_uchar * auth_plugin_data, const size_t auth_plugin_data_len,
const char * const passwd,
const size_t passwd_len)
const size_t passwd_len,
char **new_auth_protocol, size_t *new_auth_protocol_len,
zend_uchar **new_auth_protocol_data, size_t *new_auth_protocol_data_len
)
{
DBG_ENTER("mysqlnd_caching_sha2_handle_server_response");
MYSQLND_PACKET_CACHED_SHA2_RESULT result_packet;
conn->payload_decoder_factory->m.init_cached_sha2_result_packet(&result_packet);
if (passwd_len == 0) {
DBG_INF("empty password fast path");
DBG_RETURN(PASS);
}
conn->payload_decoder_factory->m.init_cached_sha2_result_packet(&result_packet);
if (FAIL == PACKET_READ(conn, &result_packet)) {
DBG_VOID_RETURN;
DBG_RETURN(PASS);
}
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:
DBG_INF("auth switch response");
*new_auth_protocol = result_packet.new_auth_protocol;
*new_auth_protocol_len = result_packet.new_auth_protocol_len;
*new_auth_protocol_data = result_packet.new_auth_protocol_data;
*new_auth_protocol_data_len = result_packet.new_auth_protocol_data_len;
DBG_RETURN(FAIL);
case 3:
DBG_INF("fast path succeeded");
DBG_VOID_RETURN;
DBG_RETURN(PASS);
case 4:
if (conn->vio->data->ssl || conn->unix_socket.s) {
DBG_INF("fast path failed, doing full auth via SSL");
if (is_secure_transport(conn)) {
DBG_INF("fast path failed, doing full auth via secure transport");
result_packet.password = (zend_uchar *)passwd;
result_packet.password_len = passwd_len + 1;
PACKET_WRITE(conn, &result_packet);
} else {
DBG_INF("fast path failed, doing full auth without SSL");
DBG_INF("fast path failed, doing full auth via insecure transport");
result_packet.password_len = mysqlnd_caching_sha2_get_and_use_key(conn, auth_plugin_data, auth_plugin_data_len, &result_packet.password, passwd, passwd_len);
PACKET_WRITE(conn, &result_packet);
efree(result_packet.password);
}
DBG_VOID_RETURN;
DBG_RETURN(PASS);
case 2:
// The server tried to send a key, which we didn't expect
// fall-through
@ -1066,7 +1113,7 @@ mysqlnd_caching_sha2_handle_server_response(struct st_mysqlnd_authentication_plu
php_error_docref(NULL, E_WARNING, "Unexpected server response while doing caching_sha2 auth: %i", result_packet.response_code);
}
DBG_VOID_RETURN;
DBG_RETURN(PASS);
}
/* }}} */

View File

@ -51,6 +51,9 @@ mysqlnd_auth_change_user(MYSQLND_CONN_DATA * const conn,
const zend_bool silent,
const zend_bool use_full_blown_auth_packet,
const char * const auth_protocol,
struct st_mysqlnd_authentication_plugin * auth_plugin,
const zend_uchar * const orig_auth_plugin_data,
const size_t orig_auth_plugin_data_len,
const zend_uchar * auth_plugin_data,
const size_t auth_plugin_data_len,
char ** switch_to_auth_protocol,

View File

@ -669,13 +669,9 @@ MYSQLND_METHOD(mysqlnd_conn_data, connect)(MYSQLND_CONN_DATA * conn,
{
const MYSQLND_CSTRING scheme = { transport.s, transport.l };
/* This will be overwritten below with a copy, but we can use it during authentication */
conn->unix_socket.s = (char *)socket_or_pipe.s;
if (FAIL == conn->m->connect_handshake(conn, &scheme, &username, &password, &database, mysql_flags)) {
conn->unix_socket.s = NULL;
goto err;
}
conn->unix_socket.s = NULL;
}
{

View File

@ -1381,11 +1381,14 @@ typedef zend_uchar * (*func_auth_plugin__get_auth_data)(struct st_mysqlnd_authen
const MYSQLND_PFC_DATA * const pfc_data, const zend_ulong mysql_flags
);
typedef void (*func_auth_plugin__handle_server_response)(struct st_mysqlnd_authentication_plugin * self,
typedef enum_func_status (*func_auth_plugin__handle_server_response)(struct st_mysqlnd_authentication_plugin * self,
MYSQLND_CONN_DATA * conn,
const zend_uchar * auth_plugin_data, size_t auth_plugin_data_len,
const char * const passwd,
const size_t passwd_len);
const size_t passwd_len,
char **new_auth_protocol, size_t *new_auth_protocol_len,
zend_uchar **new_auth_protocol_data, size_t *new_auth_protocol_data_len
);
struct st_mysqlnd_authentication_plugin
{

View File

@ -2183,11 +2183,44 @@ php_mysqlnd_cached_sha2_result_read(MYSQLND_CONN_DATA * conn, void * _packet)
}
BAIL_IF_NO_MORE_DATA;
p++;
packet->response_code = uint1korr(p);
p++;
BAIL_IF_NO_MORE_DATA;
if (ERROR_MARKER == packet->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 */
if (packet->header.size > (size_t) (p - buf)) {
packet->new_auth_protocol = mnd_pestrdup((char *)p, FALSE);
packet->new_auth_protocol_len = strlen(packet->new_auth_protocol);
p+= packet->new_auth_protocol_len + 1; /* +1 for the \0 */
packet->new_auth_protocol_data_len = packet->header.size - (size_t) (p - buf);
if (packet->new_auth_protocol_data_len) {
packet->new_auth_protocol_data = mnd_emalloc(packet->new_auth_protocol_data_len);
memcpy(packet->new_auth_protocol_data, p, packet->new_auth_protocol_data_len);
}
DBG_INF_FMT("The server requested switching auth plugin to : %s", packet->new_auth_protocol);
DBG_INF_FMT("Server salt : [%d][%.*s]", packet->new_auth_protocol_data_len, packet->new_auth_protocol_data_len, packet->new_auth_protocol_data);
}
DBG_RETURN(PASS);
}
if (0x1 != packet->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);
p++;
BAIL_IF_NO_MORE_DATA;
packet->result = uint1korr(p);
BAIL_IF_NO_MORE_DATA;

View File

@ -286,6 +286,15 @@ typedef struct st_mysqlnd_packet_cached_sha2_result {
uint8_t request;
zend_uchar * password;
size_t password_len;
/* Used for auth switch request */
char *new_auth_protocol;
size_t new_auth_protocol_len;
zend_uchar *new_auth_protocol_data;
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;