Skip to content

Commit 184f118

Browse files
committed
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
2 parents 7e130df + 32cd373 commit 184f118

File tree

6 files changed

+111
-20
lines changed

6 files changed

+111
-20
lines changed

ext/mysqlnd/mysqlnd_auth.c

Lines changed: 60 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,7 @@ mysqlnd_run_authentication(
136136
ret = mysqlnd_auth_change_user(conn, user, strlen(user), passwd, passwd_len, db, db_len, silent,
137137
first_call,
138138
requested_protocol,
139+
auth_plugin, plugin_data, plugin_data_len,
139140
scrambled_data, scrambled_data_len,
140141
&switch_to_auth_protocol, &switch_to_auth_protocol_len,
141142
&switch_to_auth_protocol_data, &switch_to_auth_protocol_data_len
@@ -318,8 +319,12 @@ mysqlnd_auth_handshake(MYSQLND_CONN_DATA * conn,
318319
}
319320

320321
if (auth_plugin && auth_plugin->methods.handle_server_response) {
321-
auth_plugin->methods.handle_server_response(auth_plugin, conn,
322-
orig_auth_plugin_data, orig_auth_plugin_data_len, passwd, passwd_len);
322+
if (FAIL == auth_plugin->methods.handle_server_response(auth_plugin, conn,
323+
orig_auth_plugin_data, orig_auth_plugin_data_len, passwd, passwd_len,
324+
switch_to_auth_protocol, switch_to_auth_protocol_len,
325+
switch_to_auth_protocol_data, switch_to_auth_protocol_data_len)) {
326+
goto end;
327+
}
323328
}
324329

325330
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,
371376
const zend_bool silent,
372377
const zend_bool use_full_blown_auth_packet,
373378
const char * const auth_protocol,
379+
struct st_mysqlnd_authentication_plugin * auth_plugin,
380+
const zend_uchar * const orig_auth_plugin_data,
381+
const size_t orig_auth_plugin_data_len,
374382
const zend_uchar * const auth_plugin_data,
375383
const size_t auth_plugin_data_len,
376384
char ** switch_to_auth_protocol,
@@ -436,6 +444,15 @@ mysqlnd_auth_change_user(MYSQLND_CONN_DATA * const conn,
436444
PACKET_FREE(&auth_packet);
437445
}
438446

447+
if (auth_plugin && auth_plugin->methods.handle_server_response) {
448+
if (FAIL == auth_plugin->methods.handle_server_response(auth_plugin, conn,
449+
orig_auth_plugin_data, orig_auth_plugin_data_len, passwd, passwd_len,
450+
switch_to_auth_protocol, switch_to_auth_protocol_len,
451+
switch_to_auth_protocol_data, switch_to_auth_protocol_data_len)) {
452+
goto end;
453+
}
454+
}
455+
439456
ret = PACKET_READ(conn, &chg_user_resp);
440457
COPY_CLIENT_ERROR(conn->error_info, chg_user_resp.error_info);
441458

@@ -1026,47 +1043,77 @@ mysqlnd_caching_sha2_get_and_use_key(MYSQLND_CONN_DATA *conn,
10261043
}
10271044
/* }}} */
10281045

1029-
/* {{{ mysqlnd_native_auth_get_auth_data */
1030-
static void
1046+
static int is_secure_transport(MYSQLND_CONN_DATA *conn) {
1047+
if (conn->vio->data->ssl) {
1048+
return 1;
1049+
}
1050+
1051+
return strcmp(conn->vio->data->stream->ops->label, "unix_socket") == 0;
1052+
}
1053+
1054+
/* {{{ mysqlnd_caching_sha2_handle_server_response */
1055+
static enum_func_status
10311056
mysqlnd_caching_sha2_handle_server_response(struct st_mysqlnd_authentication_plugin *self,
10321057
MYSQLND_CONN_DATA * conn,
10331058
const zend_uchar * auth_plugin_data, const size_t auth_plugin_data_len,
10341059
const char * const passwd,
1035-
const size_t passwd_len)
1060+
const size_t passwd_len,
1061+
char **new_auth_protocol, size_t *new_auth_protocol_len,
1062+
zend_uchar **new_auth_protocol_data, size_t *new_auth_protocol_data_len
1063+
)
10361064
{
10371065
DBG_ENTER("mysqlnd_caching_sha2_handle_server_response");
10381066
MYSQLND_PACKET_CACHED_SHA2_RESULT result_packet;
1039-
conn->payload_decoder_factory->m.init_cached_sha2_result_packet(&result_packet);
10401067

1068+
if (passwd_len == 0) {
1069+
DBG_INF("empty password fast path");
1070+
DBG_RETURN(PASS);
1071+
}
1072+
1073+
conn->payload_decoder_factory->m.init_cached_sha2_result_packet(&result_packet);
10411074
if (FAIL == PACKET_READ(conn, &result_packet)) {
1042-
DBG_VOID_RETURN;
1075+
DBG_RETURN(PASS);
10431076
}
10441077

10451078
switch (result_packet.response_code) {
1079+
case 0xFF:
1080+
if (result_packet.sqlstate[0]) {
1081+
strlcpy(conn->error_info->sqlstate, result_packet.sqlstate, sizeof(conn->error_info->sqlstate));
1082+
DBG_ERR_FMT("ERROR:%u [SQLSTATE:%s] %s", result_packet.error_no, result_packet.sqlstate, result_packet.error);
1083+
}
1084+
SET_CLIENT_ERROR(conn->error_info, result_packet.error_no, UNKNOWN_SQLSTATE, result_packet.error);
1085+
DBG_RETURN(FAIL);
1086+
case 0xFE:
1087+
DBG_INF("auth switch response");
1088+
*new_auth_protocol = result_packet.new_auth_protocol;
1089+
*new_auth_protocol_len = result_packet.new_auth_protocol_len;
1090+
*new_auth_protocol_data = result_packet.new_auth_protocol_data;
1091+
*new_auth_protocol_data_len = result_packet.new_auth_protocol_data_len;
1092+
DBG_RETURN(FAIL);
10461093
case 3:
10471094
DBG_INF("fast path succeeded");
1048-
DBG_VOID_RETURN;
1095+
DBG_RETURN(PASS);
10491096
case 4:
1050-
if (conn->vio->data->ssl || conn->unix_socket.s) {
1051-
DBG_INF("fast path failed, doing full auth via SSL");
1097+
if (is_secure_transport(conn)) {
1098+
DBG_INF("fast path failed, doing full auth via secure transport");
10521099
result_packet.password = (zend_uchar *)passwd;
10531100
result_packet.password_len = passwd_len + 1;
10541101
PACKET_WRITE(conn, &result_packet);
10551102
} else {
1056-
DBG_INF("fast path failed, doing full auth without SSL");
1103+
DBG_INF("fast path failed, doing full auth via insecure transport");
10571104
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);
10581105
PACKET_WRITE(conn, &result_packet);
10591106
efree(result_packet.password);
10601107
}
1061-
DBG_VOID_RETURN;
1108+
DBG_RETURN(PASS);
10621109
case 2:
10631110
// The server tried to send a key, which we didn't expect
10641111
// fall-through
10651112
default:
10661113
php_error_docref(NULL, E_WARNING, "Unexpected server response while doing caching_sha2 auth: %i", result_packet.response_code);
10671114
}
10681115

1069-
DBG_VOID_RETURN;
1116+
DBG_RETURN(PASS);
10701117
}
10711118
/* }}} */
10721119

ext/mysqlnd/mysqlnd_auth.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,9 @@ mysqlnd_auth_change_user(MYSQLND_CONN_DATA * const conn,
5151
const zend_bool silent,
5252
const zend_bool use_full_blown_auth_packet,
5353
const char * const auth_protocol,
54+
struct st_mysqlnd_authentication_plugin * auth_plugin,
55+
const zend_uchar * const orig_auth_plugin_data,
56+
const size_t orig_auth_plugin_data_len,
5457
const zend_uchar * auth_plugin_data,
5558
const size_t auth_plugin_data_len,
5659
char ** switch_to_auth_protocol,

ext/mysqlnd/mysqlnd_connection.c

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -669,13 +669,9 @@ MYSQLND_METHOD(mysqlnd_conn_data, connect)(MYSQLND_CONN_DATA * conn,
669669

670670
{
671671
const MYSQLND_CSTRING scheme = { transport.s, transport.l };
672-
/* This will be overwritten below with a copy, but we can use it during authentication */
673-
conn->unix_socket.s = (char *)socket_or_pipe.s;
674672
if (FAIL == conn->m->connect_handshake(conn, &scheme, &username, &password, &database, mysql_flags)) {
675-
conn->unix_socket.s = NULL;
676673
goto err;
677674
}
678-
conn->unix_socket.s = NULL;
679675
}
680676

681677
{

ext/mysqlnd/mysqlnd_structs.h

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1381,11 +1381,14 @@ typedef zend_uchar * (*func_auth_plugin__get_auth_data)(struct st_mysqlnd_authen
13811381
const MYSQLND_PFC_DATA * const pfc_data, const zend_ulong mysql_flags
13821382
);
13831383

1384-
typedef void (*func_auth_plugin__handle_server_response)(struct st_mysqlnd_authentication_plugin * self,
1384+
typedef enum_func_status (*func_auth_plugin__handle_server_response)(struct st_mysqlnd_authentication_plugin * self,
13851385
MYSQLND_CONN_DATA * conn,
13861386
const zend_uchar * auth_plugin_data, size_t auth_plugin_data_len,
13871387
const char * const passwd,
1388-
const size_t passwd_len);
1388+
const size_t passwd_len,
1389+
char **new_auth_protocol, size_t *new_auth_protocol_len,
1390+
zend_uchar **new_auth_protocol_data, size_t *new_auth_protocol_data_len
1391+
);
13891392

13901393
struct st_mysqlnd_authentication_plugin
13911394
{

ext/mysqlnd/mysqlnd_wireprotocol.c

Lines changed: 34 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2183,11 +2183,44 @@ php_mysqlnd_cached_sha2_result_read(MYSQLND_CONN_DATA * conn, void * _packet)
21832183
}
21842184
BAIL_IF_NO_MORE_DATA;
21852185

2186-
p++;
21872186
packet->response_code = uint1korr(p);
2187+
p++;
21882188
BAIL_IF_NO_MORE_DATA;
21892189

2190+
if (ERROR_MARKER == packet->response_code) {
2191+
php_mysqlnd_read_error_from_line(p, packet->header.size - 1,
2192+
packet->error, sizeof(packet->error),
2193+
&packet->error_no, packet->sqlstate
2194+
);
2195+
DBG_RETURN(PASS);
2196+
}
2197+
if (0xFE == packet->response_code) {
2198+
/* Authentication Switch Response */
2199+
if (packet->header.size > (size_t) (p - buf)) {
2200+
packet->new_auth_protocol = mnd_pestrdup((char *)p, FALSE);
2201+
packet->new_auth_protocol_len = strlen(packet->new_auth_protocol);
2202+
p+= packet->new_auth_protocol_len + 1; /* +1 for the \0 */
2203+
2204+
packet->new_auth_protocol_data_len = packet->header.size - (size_t) (p - buf);
2205+
if (packet->new_auth_protocol_data_len) {
2206+
packet->new_auth_protocol_data = mnd_emalloc(packet->new_auth_protocol_data_len);
2207+
memcpy(packet->new_auth_protocol_data, p, packet->new_auth_protocol_data_len);
2208+
}
2209+
DBG_INF_FMT("The server requested switching auth plugin to : %s", packet->new_auth_protocol);
2210+
DBG_INF_FMT("Server salt : [%d][%.*s]", packet->new_auth_protocol_data_len, packet->new_auth_protocol_data_len, packet->new_auth_protocol_data);
2211+
}
2212+
DBG_RETURN(PASS);
2213+
}
2214+
2215+
if (0x1 != packet->response_code) {
2216+
DBG_ERR_FMT("Unexpected response code %d", packet->response_code);
2217+
}
2218+
2219+
/* This is not really the response code, but we reuse the field. */
2220+
packet->response_code = uint1korr(p);
21902221
p++;
2222+
BAIL_IF_NO_MORE_DATA;
2223+
21912224
packet->result = uint1korr(p);
21922225
BAIL_IF_NO_MORE_DATA;
21932226

ext/mysqlnd/mysqlnd_wireprotocol.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -286,6 +286,15 @@ typedef struct st_mysqlnd_packet_cached_sha2_result {
286286
uint8_t request;
287287
zend_uchar * password;
288288
size_t password_len;
289+
/* Used for auth switch request */
290+
char *new_auth_protocol;
291+
size_t new_auth_protocol_len;
292+
zend_uchar *new_auth_protocol_data;
293+
size_t new_auth_protocol_data_len;
294+
/* Used for error result */
295+
char error[MYSQLND_ERRMSG_SIZE+1];
296+
char sqlstate[MYSQLND_SQLSTATE_LENGTH + 1];
297+
unsigned int error_no;
289298
} MYSQLND_PACKET_CACHED_SHA2_RESULT;
290299

291300

0 commit comments

Comments
 (0)