/* {{{ mysqlnd_conn::simple_command */
static enum_func_status
MYSQLND_METHOD(mysqlnd_conn, simple_command)(MYSQLND * conn, enum php_mysqlnd_server_command command,
- const char * const arg, size_t arg_len, enum mysqlnd_packet_type ok_packet, zend_bool silent,
+ const zend_uchar * const arg, size_t arg_len, enum mysqlnd_packet_type ok_packet, zend_bool silent,
zend_bool ignore_upsert_status TSRMLS_DC)
{
enum_func_status ret = PASS;
MYSQLND_METHOD(mysqlnd_conn, set_server_option)(MYSQLND * const conn, enum_mysqlnd_server_option option TSRMLS_DC)
{
enum_func_status ret;
- char buffer[2];
+ zend_uchar buffer[2];
DBG_ENTER("mysqlnd_conn::set_server_option");
int2store(buffer, (unsigned int) option);
ret = mysqlnd_switch_to_ssl_if_needed(conn, greet_packet, options, mysql_flags TSRMLS_CC);
if (PASS == ret) {
+ zend_bool first_call = TRUE;
+
char * switch_to_auth_protocol = NULL;
+ size_t switch_to_auth_protocol_len = 0;
char * requested_protocol = NULL;
+ zend_uchar * plugin_data;
+ size_t plugin_data_len;
+
+ plugin_data_len = greet_packet->auth_plugin_data_len;
+ plugin_data = mnd_emalloc(plugin_data_len);
+ if (!plugin_data) {
+ ret = FAIL;
+ goto end;
+ }
+ memcpy(plugin_data, greet_packet->auth_plugin_data, plugin_data_len);
+
+ requested_protocol = mnd_pestrdup(greet_packet->auth_protocol? greet_packet->auth_protocol: "mysql_native_password", FALSE);
+ if (!requested_protocol) {
+ ret = FAIL;
+ goto end;
+ }
do {
struct st_mysqlnd_authentication_plugin * auth_plugin;
- char * plugin_name = NULL;
- requested_protocol = switch_to_auth_protocol? switch_to_auth_protocol:
- (greet_packet->auth_protocol?
- greet_packet->auth_protocol:
- "mysql_native_password"
- );
- spprintf(&plugin_name, 0, "auth_plugin_%s", requested_protocol);
- DBG_INF_FMT("looking for %s auth plugin", plugin_name);
- auth_plugin = mysqlnd_plugin_find(plugin_name);
- efree(plugin_name);
- if (!auth_plugin) {
- php_error_docref(NULL TSRMLS_CC, E_WARNING, "The server requested authentication method uknown to the client [%s]", requested_protocol);
- SET_CLIENT_ERROR(conn->error_info, CR_NOT_IMPLEMENTED, UNKNOWN_SQLSTATE, "The server requested authentication method uknown to the client");
- break;
- }
+ {
+ char * plugin_name = NULL;
+ spprintf(&plugin_name, 0, "auth_plugin_%s", requested_protocol);
+
+ DBG_INF_FMT("looking for %s auth plugin", plugin_name);
+ auth_plugin = mysqlnd_plugin_find(plugin_name);
+ efree(plugin_name);
+
+ if (!auth_plugin) {
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "The server requested authentication method unknown to the client [%s]", requested_protocol);
+ SET_CLIENT_ERROR(conn->error_info, CR_NOT_IMPLEMENTED, UNKNOWN_SQLSTATE, "The server requested authentication method umknown to the client");
+ break;
+ }
+ }
DBG_INF("plugin found");
- ret = mysqlnd_auth_handshake(conn, user, passwd, db, db_len, passwd_len, greet_packet, options, mysql_flags,
- auth_plugin, &switch_to_auth_protocol TSRMLS_CC);
- DBG_INF_FMT("switch_to_auth_protocol=%s", switch_to_auth_protocol? switch_to_auth_protocol:"n/a");
- } while (ret == FAIL && switch_to_auth_protocol != NULL);
+ {
+ zend_uchar * switch_to_auth_protocol_data = NULL;
+ size_t switch_to_auth_protocol_data_len = 0;
+ zend_uchar * scrambled_data = NULL;
+ size_t scrambled_data_len = 0;
+
+ switch_to_auth_protocol = NULL;
+ switch_to_auth_protocol_len = 0;
+
+ if (conn->auth_plugin_data) {
+ mnd_pefree(conn->auth_plugin_data, conn->persistent);
+ conn->auth_plugin_data = NULL;
+ }
+ conn->auth_plugin_data_len = plugin_data_len;
+ conn->auth_plugin_data = mnd_pemalloc(conn->auth_plugin_data_len, conn->persistent);
+ if (!conn->auth_plugin_data) {
+ SET_OOM_ERROR(conn->error_info);
+ goto end;
+ }
+ memcpy(conn->auth_plugin_data, plugin_data, plugin_data_len);
+
+ DBG_INF_FMT("salt=[%*s]", plugin_data_len - 1, plugin_data);
+ /* The data should be allocated with malloc() */
+ scrambled_data =
+ auth_plugin->methods.get_auth_data(NULL, &scrambled_data_len, conn, user, passwd, passwd_len,
+ plugin_data, plugin_data_len, options, mysql_flags TSRMLS_CC);
+
+
+ ret = mysqlnd_auth_handshake(conn, user, passwd, db, db_len, passwd_len, options, mysql_flags, greet_packet->charset_no,
+ first_call,
+ requested_protocol,
+ 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
+ TSRMLS_CC);
+ first_call = FALSE;
+ free(scrambled_data);
+
+ DBG_INF_FMT("switch_to_auth_protocol=%s", switch_to_auth_protocol? switch_to_auth_protocol:"n/a");
+ if (requested_protocol) {
+ mnd_efree(requested_protocol);
+ }
+ requested_protocol = switch_to_auth_protocol;
+ if (plugin_data) {
+ mnd_efree(plugin_data);
+ }
+ plugin_data_len = switch_to_auth_protocol_data_len;
+ plugin_data = switch_to_auth_protocol_data;
+ }
+ DBG_INF_FMT("conn->error_info.error_no = %d", conn->error_info.error_no);
+ } while (ret == FAIL && conn->error_info.error_no == 0 && switch_to_auth_protocol != NULL);
+ if (plugin_data) {
+ mnd_efree(plugin_data);
+ }
+
if (ret == PASS) {
conn->m->set_client_option(conn, MYSQLND_OPT_AUTH_PROTOCOL, requested_protocol TSRMLS_CC);
}
- if (switch_to_auth_protocol) {
- mnd_efree(switch_to_auth_protocol);
- switch_to_auth_protocol = NULL;
+ if (requested_protocol) {
+ mnd_efree(requested_protocol);
}
}
+end:
DBG_RETURN(ret);
}
/* }}} */
DBG_ENTER("mysqlnd_conn::query");
DBG_INF_FMT("conn=%llu query=%s", conn->thread_id, query);
- if (PASS != conn->m->simple_command(conn, COM_QUERY, query, query_len,
+ if (PASS != conn->m->simple_command(conn, COM_QUERY, (zend_uchar *) query, query_len,
PROT_LAST /* we will handle the OK packet*/,
FALSE, FALSE TSRMLS_CC)) {
DBG_RETURN(FAIL);
DBG_ENTER("mysqlnd_conn::send_query");
DBG_INF_FMT("conn=%llu query=%s", conn->thread_id, query);
- ret = conn->m->simple_command(conn, COM_QUERY, query, query_len,
+ ret = conn->m->simple_command(conn, COM_QUERY, (zend_uchar *) query, query_len,
PROT_LAST /* we will handle the OK packet*/,
FALSE, FALSE TSRMLS_CC);
CONN_SET_STATE(conn, CONN_QUERY_SENT);
MYSQLND_METHOD(mysqlnd_conn, list_fields)(MYSQLND * conn, const char *table, const char *achtung_wild TSRMLS_DC)
{
/* db + \0 + wild + \0 (for wild) */
- char buff[MYSQLND_MAX_ALLOWED_DB_LEN * 2 + 1 + 1], *p;
+ zend_uchar buff[MYSQLND_MAX_ALLOWED_DB_LEN * 2 + 1 + 1], *p;
size_t table_len, wild_len;
MYSQLND_RES *result = NULL;
DBG_ENTER("mysqlnd_conn::list_fields");
DBG_ENTER("mysqlnd_conn::select_db");
DBG_INF_FMT("conn=%llu db=%s", conn->thread_id, db);
- ret = conn->m->simple_command(conn, COM_INIT_DB, db, db_len, PROT_OK_PACKET, FALSE, TRUE TSRMLS_CC);
+ ret = conn->m->simple_command(conn, COM_INIT_DB, (zend_uchar*) db, db_len, PROT_OK_PACKET, FALSE, TRUE TSRMLS_CC);
/*
The server sends 0 but libmysql doesn't read it and has established
a protocol of giving back -1. Thus we have to follow it :(
MYSQLND_METHOD(mysqlnd_conn, kill)(MYSQLND * conn, unsigned int pid TSRMLS_DC)
{
enum_func_status ret;
- char buff[4];
+ zend_uchar buff[4];
DBG_ENTER("mysqlnd_conn::kill");
DBG_INF_FMT("conn=%llu pid=%lu", conn->thread_id, pid);
int1store(bits, options);
- DBG_RETURN(conn->m->simple_command(conn, COM_REFRESH, (char *)bits, 1, PROT_OK_PACKET, FALSE, TRUE TSRMLS_CC));
+ DBG_RETURN(conn->m->simple_command(conn, COM_REFRESH, bits, 1, PROT_OK_PACKET, FALSE, TRUE TSRMLS_CC));
}
/* }}} */
int1store(bits, level);
- DBG_RETURN(conn->m->simple_command(conn, COM_SHUTDOWN, (char *)bits, 1, PROT_OK_PACKET, FALSE, TRUE TSRMLS_CC));
+ DBG_RETURN(conn->m->simple_command(conn, COM_SHUTDOWN, bits, 1, PROT_OK_PACKET, FALSE, TRUE TSRMLS_CC));
}
/* }}} */
DBG_INF_FMT("conn=%llu user=%s passwd=%s db=%s silent=%u",
conn->thread_id, user?user:"", passwd?"***":"null", db?db:"", (silent == TRUE)?1:0 );
+ SET_EMPTY_ERROR(conn->error_info);
SET_ERROR_AFF_ROWS(conn);
if (!user) {
{
+ zend_bool first_call = TRUE;
char * switch_to_auth_protocol = NULL;
- const char * requested_protocol = NULL;
+ size_t switch_to_auth_protocol_len = 0;
+ char * requested_protocol = NULL;
+ zend_uchar * plugin_data;
+ size_t plugin_data_len;
+
+ plugin_data_len = conn->auth_plugin_data_len;
+ plugin_data = mnd_emalloc(plugin_data_len);
+ if (!plugin_data) {
+ ret = FAIL;
+ goto end;
+ }
+ memcpy(plugin_data, conn->auth_plugin_data, plugin_data_len);
+
+ requested_protocol = mnd_pestrdup(conn->options.auth_protocol? conn->options.auth_protocol:"mysql_native_password", FALSE);
+ if (!requested_protocol) {
+ ret = FAIL;
+ goto end;
+ }
do {
struct st_mysqlnd_authentication_plugin * auth_plugin;
- char * plugin_name = NULL;
- requested_protocol = switch_to_auth_protocol? switch_to_auth_protocol:
- ((conn->server_capabilities & CLIENT_PLUGIN_AUTH)?
- conn->options.auth_protocol:
- "mysql_native_password"
- );
-
- spprintf(&plugin_name, 0, "auth_plugin_%s", requested_protocol);
- DBG_INF_FMT("looking for %s auth plugin", plugin_name);
- auth_plugin = mysqlnd_plugin_find(plugin_name);
- efree(plugin_name);
- if (!auth_plugin) {
- if (!silent) {
- php_error_docref(NULL TSRMLS_CC, E_WARNING, "The server requested authentication method uknown to the client [%s]", requested_protocol);
+ {
+ char * plugin_name = NULL;
+
+ spprintf(&plugin_name, 0, "auth_plugin_%s", requested_protocol);
+
+ DBG_INF_FMT("looking for %s auth plugin", plugin_name);
+ auth_plugin = mysqlnd_plugin_find(plugin_name);
+ efree(plugin_name);
+
+ if (!auth_plugin) {
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "The server requested authentication method unknown to the client [%s]", requested_protocol);
+ SET_CLIENT_ERROR(conn->error_info, CR_NOT_IMPLEMENTED, UNKNOWN_SQLSTATE, "The server requested authentication method umknown to the client");
+ break;
}
- SET_CLIENT_ERROR(conn->error_info, CR_NOT_IMPLEMENTED, UNKNOWN_SQLSTATE, "The server requested authentication method uknown to the client");
- break;
- }
+ }
DBG_INF("plugin found");
- ret = mysqlnd_auth_change_user(conn, user, strlen(user), passwd, db, strlen(db), passwd_len, silent,
- auth_plugin, &switch_to_auth_protocol TSRMLS_CC);
- DBG_INF_FMT("switch_to_auth_protocol=%s", switch_to_auth_protocol? switch_to_auth_protocol:"n/a");
- } while (ret == FAIL && switch_to_auth_protocol != NULL);
+ {
+ zend_uchar * switch_to_auth_protocol_data = NULL;
+ size_t switch_to_auth_protocol_data_len = 0;
+ zend_uchar * scrambled_data = NULL;
+ size_t scrambled_data_len = 0;
+
+ switch_to_auth_protocol = NULL;
+ switch_to_auth_protocol_len = 0;
+
+ if (conn->auth_plugin_data) {
+ mnd_pefree(conn->auth_plugin_data, conn->persistent);
+ conn->auth_plugin_data = NULL;
+ }
+ conn->auth_plugin_data_len = plugin_data_len;
+ conn->auth_plugin_data = mnd_pemalloc(conn->auth_plugin_data_len, conn->persistent);
+ if (!conn->auth_plugin_data) {
+ SET_OOM_ERROR(conn->error_info);
+ ret = FAIL;
+ goto end;
+ }
+ memcpy(conn->auth_plugin_data, plugin_data, plugin_data_len);
+
+ DBG_INF_FMT("salt=[%*s]", plugin_data_len - 1, plugin_data);
+
+ /* The data should be allocated with malloc() */
+ scrambled_data =
+ auth_plugin->methods.get_auth_data(NULL, &scrambled_data_len, conn, user, passwd, passwd_len,
+ plugin_data, plugin_data_len, 0, conn->server_capabilities TSRMLS_CC);
+
+
+ ret = mysqlnd_auth_change_user(conn, user, strlen(user), passwd, db, strlen(db), passwd_len, silent,
+ first_call,
+ requested_protocol,
+ 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
+ TSRMLS_CC);
+
+ first_call = FALSE;
+ free(scrambled_data);
+
+ DBG_INF_FMT("switch_to_auth_protocol=%s", switch_to_auth_protocol? switch_to_auth_protocol:"n/a");
+ if (requested_protocol) {
+ mnd_efree(requested_protocol);
+ }
+ requested_protocol = switch_to_auth_protocol;
+
+ if (plugin_data) {
+ mnd_efree(plugin_data);
+ }
+ plugin_data_len = switch_to_auth_protocol_data_len;
+ plugin_data = switch_to_auth_protocol_data;
+ }
+ DBG_INF_FMT("conn->error_info.error_no = %d", conn->error_info.error_no);
+ } while (ret == FAIL && conn->error_info.error_no == 0 && switch_to_auth_protocol != NULL);
+ if (plugin_data) {
+ mnd_efree(plugin_data);
+ }
if (ret == PASS) {
conn->m->set_client_option(conn, MYSQLND_OPT_AUTH_PROTOCOL, requested_protocol TSRMLS_CC);
}
- if (switch_to_auth_protocol) {
- mnd_efree(switch_to_auth_protocol);
- switch_to_auth_protocol = NULL;
+ if (requested_protocol) {
+ mnd_efree(requested_protocol);
}
}
/*
Here we should close all statements. Unbuffered queries should not be a
problem as we won't allow sending COM_CHANGE_USER.
*/
+end:
DBG_INF(ret == PASS? "PASS":"FAIL");
DBG_RETURN(ret);
}
break;
case MYSQLND_OPT_AUTH_PROTOCOL:
{
- char * new_auth_protocol = mnd_pestrdup(value, conn->persistent);
+ char * new_auth_protocol = value? mnd_pestrdup(value, conn->persistent) : NULL;
DBG_INF("MYSQLND_OPT_AUTH_PROTOCOL");
- if (!new_auth_protocol) {
+ if (value && !new_auth_protocol) {
goto oom;
}
if (conn->options.auth_protocol) {
}
mysqlnd_example_plugin_register(TSRMLS_C);
mysqlnd_debug_trace_plugin_register(TSRMLS_C);
- mysqlnd_native_authentication_plugin_register(TSRMLS_C);
+ mysqlnd_register_builtin_authentication_plugins(TSRMLS_C);
}
}
/* }}} */
#include "mysqlnd_debug.h"
-/* {{{ mysqlnd_native_auth_handshake */
+/* {{{ mysqlnd_auth_handshake */
enum_func_status
mysqlnd_auth_handshake(MYSQLND * conn,
const char * const user,
const char * const db,
const size_t db_len,
const size_t passwd_len,
- const MYSQLND_PACKET_GREET * const greet_packet,
const MYSQLND_OPTIONS * const options,
unsigned long mysql_flags,
- struct st_mysqlnd_authentication_plugin * auth_plugin,
- char ** switch_to_auth_protocol
+ unsigned int server_charset_no,
+ zend_bool use_full_blown_auth_packet,
+ const char * const auth_protocol,
+ const zend_uchar * const auth_plugin_data,
+ const size_t auth_plugin_data_len,
+ char ** switch_to_auth_protocol,
+ size_t * switch_to_auth_protocol_len,
+ zend_uchar ** switch_to_auth_protocol_data,
+ size_t * switch_to_auth_protocol_data_len
TSRMLS_DC)
{
enum_func_status ret = FAIL;
const MYSQLND_CHARSET * charset = NULL;
- MYSQLND_PACKET_OK * ok_packet = NULL;
+ MYSQLND_PACKET_CHANGE_AUTH_RESPONSE * change_auth_resp_packet = NULL;
+ MYSQLND_PACKET_AUTH_RESPONSE * auth_resp_packet = NULL;
MYSQLND_PACKET_AUTH * auth_packet = NULL;
- DBG_ENTER("mysqlnd_native_auth_handshake");
+ DBG_ENTER("mysqlnd_auth_handshake");
- ok_packet = conn->protocol->m.get_ok_packet(conn->protocol, FALSE TSRMLS_CC);
- auth_packet = conn->protocol->m.get_auth_packet(conn->protocol, FALSE TSRMLS_CC);
+ auth_resp_packet = conn->protocol->m.get_auth_response_packet(conn->protocol, FALSE TSRMLS_CC);
- if (!ok_packet || !auth_packet) {
+ if (!auth_resp_packet) {
SET_OOM_ERROR(conn->error_info);
goto end;
}
- auth_packet->client_flags = mysql_flags;
- auth_packet->max_packet_size = options->max_allowed_packet;
- if (options->charset_name && (charset = mysqlnd_find_charset_name(options->charset_name))) {
- auth_packet->charset_no = charset->nr;
+ if (use_full_blown_auth_packet != TRUE) {
+ change_auth_resp_packet = conn->protocol->m.get_change_auth_response_packet(conn->protocol, FALSE TSRMLS_CC);
+ if (!change_auth_resp_packet) {
+ SET_OOM_ERROR(conn->error_info);
+ goto end;
+ }
+
+ change_auth_resp_packet->auth_data = auth_plugin_data;
+ change_auth_resp_packet->auth_data_len = auth_plugin_data_len;
+
+ if (!PACKET_WRITE(change_auth_resp_packet, conn)) {
+ CONN_SET_STATE(conn, CONN_QUIT_SENT);
+ SET_CLIENT_ERROR(conn->error_info, CR_SERVER_GONE_ERROR, UNKNOWN_SQLSTATE, mysqlnd_server_gone);
+ goto end;
+ }
} else {
+ auth_packet = conn->protocol->m.get_auth_packet(conn->protocol, FALSE TSRMLS_CC);
+
+ auth_packet->client_flags = mysql_flags;
+ auth_packet->max_packet_size = options->max_allowed_packet;
+ if (options->charset_name && (charset = mysqlnd_find_charset_name(options->charset_name))) {
+ auth_packet->charset_no = charset->nr;
+ } else {
#if MYSQLND_UNICODE
- auth_packet->charset_no = 200;/* utf8 - swedish collation, check mysqlnd_charset.c */
+ auth_packet->charset_no = 200;/* utf8 - swedish collation, check mysqlnd_charset.c */
#else
- auth_packet->charset_no = greet_packet->charset_no;
+ auth_packet->charset_no = server_charset_no;
#endif
- }
-
- auth_packet->send_auth_data = TRUE;
- auth_packet->user = user;
- auth_packet->db = db;
- auth_packet->db_len = db_len;
+ }
- conn->auth_plugin_data_len = greet_packet->auth_plugin_data_len;
- conn->auth_plugin_data = mnd_pemalloc(conn->auth_plugin_data_len, conn->persistent);
- if (!conn->auth_plugin_data) {
- SET_OOM_ERROR(conn->error_info);
- goto end;
- }
- memcpy(conn->auth_plugin_data, greet_packet->auth_plugin_data, greet_packet->auth_plugin_data_len);
+ auth_packet->send_auth_data = TRUE;
+ auth_packet->user = user;
+ auth_packet->db = db;
+ auth_packet->db_len = db_len;
- auth_packet->auth_data =
- auth_plugin->methods.get_auth_data(NULL, &auth_packet->auth_data_len, conn, user, passwd, passwd_len,
- conn->auth_plugin_data, conn->auth_plugin_data_len, options, mysql_flags TSRMLS_CC);
-
+ auth_packet->auth_data = auth_plugin_data;
+ auth_packet->auth_data_len = auth_plugin_data_len;
+ auth_packet->auth_plugin_name = auth_protocol;
- if (!PACKET_WRITE(auth_packet, conn)) {
- CONN_SET_STATE(conn, CONN_QUIT_SENT);
- SET_CLIENT_ERROR(conn->error_info, CR_SERVER_GONE_ERROR, UNKNOWN_SQLSTATE, mysqlnd_server_gone);
- goto end;
+ if (!PACKET_WRITE(auth_packet, conn)) {
+ CONN_SET_STATE(conn, CONN_QUIT_SENT);
+ SET_CLIENT_ERROR(conn->error_info, CR_SERVER_GONE_ERROR, UNKNOWN_SQLSTATE, mysqlnd_server_gone);
+ goto end;
+ }
}
- if (FAIL == PACKET_READ(ok_packet, conn) || ok_packet->field_count >= 0xFE) {
- if (ok_packet->field_count == 0xFE) {
+ if (FAIL == PACKET_READ(auth_resp_packet, conn) || auth_resp_packet->response_code >= 0xFE) {
+ if (auth_resp_packet->response_code == 0xFE) {
/* old authentication with new server !*/
- DBG_ERR(mysqlnd_old_passwd);
- SET_CLIENT_ERROR(conn->error_info, CR_UNKNOWN_ERROR, UNKNOWN_SQLSTATE, mysqlnd_old_passwd);
- } else if (ok_packet->field_count == 0xFF) {
- if (ok_packet->sqlstate[0]) {
- strlcpy(conn->error_info.sqlstate, ok_packet->sqlstate, sizeof(conn->error_info.sqlstate));
- DBG_ERR_FMT("ERROR:%u [SQLSTATE:%s] %s", ok_packet->error_no, ok_packet->sqlstate, ok_packet->error);
+ if (!auth_resp_packet->new_auth_protocol) {
+ DBG_ERR(mysqlnd_old_passwd);
+ SET_CLIENT_ERROR(conn->error_info, CR_UNKNOWN_ERROR, UNKNOWN_SQLSTATE, mysqlnd_old_passwd);
+ } else {
+ *switch_to_auth_protocol = mnd_pestrndup(auth_resp_packet->new_auth_protocol, auth_resp_packet->new_auth_protocol_len, FALSE);
+ *switch_to_auth_protocol_len = auth_resp_packet->new_auth_protocol_len;
+ if (auth_resp_packet->new_auth_protocol_data) {
+ *switch_to_auth_protocol_data_len = auth_resp_packet->new_auth_protocol_data_len;
+ *switch_to_auth_protocol_data = mnd_emalloc(*switch_to_auth_protocol_data_len);
+ memcpy(*switch_to_auth_protocol_data, auth_resp_packet->new_auth_protocol_data, *switch_to_auth_protocol_data_len);
+ } else {
+ *switch_to_auth_protocol_data = NULL;
+ *switch_to_auth_protocol_data_len = 0;
+ }
}
- conn->error_info.error_no = ok_packet->error_no;
- strlcpy(conn->error_info.error, ok_packet->error, sizeof(conn->error_info.error));
+ } else if (auth_resp_packet->response_code == 0xFF) {
+ if (auth_resp_packet->sqlstate[0]) {
+ strlcpy(conn->error_info.sqlstate, auth_resp_packet->sqlstate, sizeof(conn->error_info.sqlstate));
+ DBG_ERR_FMT("ERROR:%u [SQLSTATE:%s] %s", auth_resp_packet->error_no, auth_resp_packet->sqlstate, auth_resp_packet->error);
+ }
+ conn->error_info.error_no = auth_resp_packet->error_no;
+ strlcpy(conn->error_info.error, auth_resp_packet->error, sizeof(conn->error_info.error));
}
goto end;
}
- SET_NEW_MESSAGE(conn->last_message, conn->last_message_len, ok_packet->message, ok_packet->message_len, conn->persistent);
+ SET_NEW_MESSAGE(conn->last_message, conn->last_message_len, auth_resp_packet->message, auth_resp_packet->message_len, conn->persistent);
conn->charset = mysqlnd_find_charset_nr(auth_packet->charset_no);
ret = PASS;
end:
- mnd_efree(auth_packet->auth_data);
+ PACKET_FREE(change_auth_resp_packet);
PACKET_FREE(auth_packet);
- PACKET_FREE(ok_packet);
+ PACKET_FREE(auth_resp_packet);
DBG_RETURN(ret);
}
/* }}} */
-/* {{{ mysqlnd_native_auth_change_user */
+/* {{{ mysqlnd_auth_change_user */
enum_func_status
mysqlnd_auth_change_user(MYSQLND * const conn,
const char * const user,
const size_t db_len,
const size_t passwd_len,
const zend_bool silent,
- struct st_mysqlnd_authentication_plugin * auth_plugin,
- char ** switch_to_auth_protocol
+ zend_bool use_full_blown_auth_packet,
+ const char * const auth_protocol,
+ zend_uchar * auth_plugin_data,
+ size_t auth_plugin_data_len,
+ char ** switch_to_auth_protocol,
+ size_t * switch_to_auth_protocol_len,
+ zend_uchar ** switch_to_auth_protocol_data,
+ size_t * switch_to_auth_protocol_data_len
TSRMLS_DC)
{
/*
char buffer[MYSQLND_MAX_ALLOWED_USER_LEN + 1 + SCRAMBLE_LENGTH + MYSQLND_MAX_ALLOWED_DB_LEN + 1 + 2 /* charset*/ ];
char *p = buffer;
const MYSQLND_CHARSET * old_cs = conn->charset;
- MYSQLND_PACKET_AUTH * auth_packet = conn->protocol->m.get_auth_packet(conn->protocol, FALSE TSRMLS_CC);
- MYSQLND_PACKET_CHG_USER_RESPONSE * chg_user_resp = conn->protocol->m.get_change_user_response_packet(conn->protocol, FALSE TSRMLS_CC);
+ MYSQLND_PACKET_CHANGE_AUTH_RESPONSE * change_auth_resp_packet = NULL;
+ MYSQLND_PACKET_CHG_USER_RESPONSE * chg_user_resp = NULL;
+ MYSQLND_PACKET_AUTH * auth_packet = NULL;
+
+ DBG_ENTER("mysqlnd_auth_change_user");
- DBG_ENTER("mysqlnd_native_auth_change_user");
+ chg_user_resp = conn->protocol->m.get_change_user_response_packet(conn->protocol, FALSE TSRMLS_CC);
- if (!auth_packet || !chg_user_resp) {
+ if (!chg_user_resp) {
SET_OOM_ERROR(conn->error_info);
goto end;
}
- auth_packet->is_change_user_packet = TRUE;
- auth_packet->user = user;
- auth_packet->db = db;
- auth_packet->db_len = db_len;
- auth_packet->silent = silent;
+ if (use_full_blown_auth_packet != TRUE) {
+ change_auth_resp_packet = conn->protocol->m.get_change_auth_response_packet(conn->protocol, FALSE TSRMLS_CC);
+ if (!change_auth_resp_packet) {
+ SET_OOM_ERROR(conn->error_info);
+ goto end;
+ }
- auth_packet->auth_data =
- auth_plugin->methods.get_auth_data(NULL, &auth_packet->auth_data_len, conn, user, passwd, passwd_len,
- conn->auth_plugin_data, conn->auth_plugin_data_len, NULL /* options */, 0 /* mysql_flags */ TSRMLS_CC);
+ change_auth_resp_packet->auth_data = auth_plugin_data;
+ change_auth_resp_packet->auth_data_len = auth_plugin_data_len;
- if (mysqlnd_get_server_version(conn) >= 50123) {
- auth_packet->charset_no = conn->charset->nr;
- p+=2;
- }
+ if (!PACKET_WRITE(change_auth_resp_packet, conn)) {
+ CONN_SET_STATE(conn, CONN_QUIT_SENT);
+ SET_CLIENT_ERROR(conn->error_info, CR_SERVER_GONE_ERROR, UNKNOWN_SQLSTATE, mysqlnd_server_gone);
+ goto end;
+ }
+ } else {
+ auth_packet = conn->protocol->m.get_auth_packet(conn->protocol, FALSE TSRMLS_CC);
+
+ if (!auth_packet) {
+ SET_OOM_ERROR(conn->error_info);
+ goto end;
+ }
+
+ auth_packet->is_change_user_packet = TRUE;
+ auth_packet->user = user;
+ auth_packet->db = db;
+ auth_packet->db_len = db_len;
+ auth_packet->silent = silent;
+
+ auth_packet->auth_data = auth_plugin_data;
+ auth_packet->auth_data_len = auth_plugin_data_len;
+ auth_packet->auth_plugin_name = auth_protocol;
+
+
+ if (mysqlnd_get_server_version(conn) >= 50123) {
+ auth_packet->charset_no = conn->charset->nr;
+ p+=2;
+ }
- if (!PACKET_WRITE(auth_packet, conn)) {
- CONN_SET_STATE(conn, CONN_QUIT_SENT);
- SET_CLIENT_ERROR(conn->error_info, CR_SERVER_GONE_ERROR, UNKNOWN_SQLSTATE, mysqlnd_server_gone);
- goto end;
+ if (!PACKET_WRITE(auth_packet, conn)) {
+ CONN_SET_STATE(conn, CONN_QUIT_SENT);
+ SET_CLIENT_ERROR(conn->error_info, CR_SERVER_GONE_ERROR, UNKNOWN_SQLSTATE, mysqlnd_server_gone);
+ goto end;
+ }
}
ret = PACKET_READ(chg_user_resp, conn);
conn->error_info = chg_user_resp->error_info;
+ if (0xFE == chg_user_resp->response_code) {
+ ret = FAIL;
+ if (!chg_user_resp->new_auth_protocol) {
+ DBG_ERR(mysqlnd_old_passwd);
+ SET_CLIENT_ERROR(conn->error_info, CR_UNKNOWN_ERROR, UNKNOWN_SQLSTATE, mysqlnd_old_passwd);
+ } else {
+ *switch_to_auth_protocol = mnd_pestrndup(chg_user_resp->new_auth_protocol, chg_user_resp->new_auth_protocol_len, FALSE);
+ *switch_to_auth_protocol_len = chg_user_resp->new_auth_protocol_len;
+ if (chg_user_resp->new_auth_protocol_data) {
+ *switch_to_auth_protocol_data_len = chg_user_resp->new_auth_protocol_data_len;
+ *switch_to_auth_protocol_data = mnd_emalloc(*switch_to_auth_protocol_data_len);
+ memcpy(*switch_to_auth_protocol_data, chg_user_resp->new_auth_protocol_data, *switch_to_auth_protocol_data_len);
+ } else {
+ *switch_to_auth_protocol_data = NULL;
+ *switch_to_auth_protocol_data_len = 0;
+ }
+ }
+ }
+
if (conn->error_info.error_no) {
ret = FAIL;
/*
SET_CLIENT_ERROR(conn->error_info, CR_UNKNOWN_ERROR, UNKNOWN_SQLSTATE, mysqlnd_old_passwd);
}
end:
- mnd_efree(auth_packet->auth_data);
+ PACKET_FREE(change_auth_resp_packet);
PACKET_FREE(auth_packet);
PACKET_FREE(chg_user_resp);
DBG_RETURN(ret);
/* }}} */
+/******************************************* MySQL Native Password ***********************************/
+
+#include "ext/standard/sha1.h"
+
+/* {{{ php_mysqlnd_crypt */
+static void
+php_mysqlnd_crypt(zend_uchar *buffer, const zend_uchar *s1, const zend_uchar *s2, size_t len)
+{
+ const zend_uchar *s1_end = s1 + len;
+ while (s1 < s1_end) {
+ *buffer++= *s1++ ^ *s2++;
+ }
+}
+/* }}} */
+
+
+/* {{{ php_mysqlnd_scramble */
+void php_mysqlnd_scramble(zend_uchar * const buffer, const zend_uchar * const scramble, const zend_uchar * const password, size_t password_len)
+{
+ PHP_SHA1_CTX context;
+ zend_uchar sha1[SHA1_MAX_LENGTH];
+ zend_uchar sha2[SHA1_MAX_LENGTH];
+
+ /* Phase 1: hash password */
+ PHP_SHA1Init(&context);
+ PHP_SHA1Update(&context, password, password_len);
+ PHP_SHA1Final(sha1, &context);
+
+ /* Phase 2: hash sha1 */
+ PHP_SHA1Init(&context);
+ PHP_SHA1Update(&context, (zend_uchar*)sha1, SHA1_MAX_LENGTH);
+ PHP_SHA1Final(sha2, &context);
+
+ /* Phase 3: hash scramble + sha2 */
+ PHP_SHA1Init(&context);
+ PHP_SHA1Update(&context, scramble, SCRAMBLE_LENGTH);
+ PHP_SHA1Update(&context, (zend_uchar*)sha2, SHA1_MAX_LENGTH);
+ PHP_SHA1Final(buffer, &context);
+
+ /* let's crypt buffer now */
+ php_mysqlnd_crypt(buffer, (const zend_uchar *)buffer, (const zend_uchar *)sha1, SHA1_MAX_LENGTH);
+}
+/* }}} */
+
+
/* {{{ mysqlnd_native_auth_get_auth_data */
static zend_uchar *
mysqlnd_native_auth_get_auth_data(struct st_mysqlnd_authentication_plugin * self,
*auth_data_len = 0;
/* 5.5.x reports 21 as scramble length because it needs to show the length of the data before the plugin name */
- if (auth_plugin_data_len != SCRAMBLE_LENGTH && (auth_plugin_data_len != 21)) {
+ if (auth_plugin_data_len < SCRAMBLE_LENGTH) {
/* mysql_native_password only works with SCRAMBLE_LENGTH scramble */
SET_CLIENT_ERROR(conn->error_info, CR_MALFORMED_PACKET, UNKNOWN_SQLSTATE, "The server sent wrong length for scramble");
DBG_ERR_FMT("The server sent wrong length for scramble %u. Expected %u", auth_plugin_data_len, SCRAMBLE_LENGTH);
/* copy scrambled pass*/
if (passwd && passwd_len) {
- ret = mnd_emalloc(SCRAMBLE_LENGTH);
+ ret = malloc(SCRAMBLE_LENGTH);
*auth_data_len = SCRAMBLE_LENGTH;
/* In 4.1 we use CLIENT_SECURE_CONNECTION and thus the len of the buf should be passed */
php_mysqlnd_scramble((zend_uchar*)ret, auth_plugin_data, (zend_uchar*)passwd, passwd_len);
};
-/* {{{ mysqlnd_native_authentication_plugin_register */
+/******************************************* PAM Authentication ***********************************/
+
+/* {{{ mysqlnd_pam_auth_get_auth_data */
+static zend_uchar *
+mysqlnd_pam_auth_get_auth_data(struct st_mysqlnd_authentication_plugin * self,
+ size_t * auth_data_len,
+ MYSQLND * conn, const char * const user, const char * const passwd,
+ const size_t passwd_len, zend_uchar * auth_plugin_data, size_t auth_plugin_data_len,
+ const MYSQLND_OPTIONS * const options, unsigned long mysql_flags
+ TSRMLS_DC)
+{
+ zend_uchar * ret = NULL;
+
+ /* copy pass*/
+ if (passwd && passwd_len) {
+ ret = (zend_uchar*) strndup(passwd, passwd_len);
+ }
+ *auth_data_len = passwd_len;
+
+ return ret;
+}
+/* }}} */
+
+
+static struct st_mysqlnd_authentication_plugin mysqlnd_pam_authentication_plugin =
+{
+ {
+ MYSQLND_PLUGIN_API_VERSION,
+ "auth_plugin_authentication_pam",
+ MYSQLND_VERSION_ID,
+ MYSQLND_VERSION,
+ "Proprietatry",
+ "Andrey Hristov <andrey@mysql.com>, Ulf Wendel <uwendel@mysql.com>, Georg Richter <georg@mysql.com>",
+ {
+ NULL, /* no statistics , will be filled later if there are some */
+ NULL, /* no statistics */
+ },
+ {
+ NULL /* plugin shutdown */
+ }
+ },
+ {/* methods */
+ mysqlnd_pam_auth_get_auth_data
+ }
+};
+
+
+/* {{{ mysqlnd_register_builtin_authentication_plugins */
void
-mysqlnd_native_authentication_plugin_register(TSRMLS_D)
+mysqlnd_register_builtin_authentication_plugins(TSRMLS_D)
{
mysqlnd_plugin_register_ex((struct st_mysqlnd_plugin_header *) &mysqlnd_native_auth_plugin TSRMLS_CC);
+ mysqlnd_plugin_register_ex((struct st_mysqlnd_plugin_header *) &mysqlnd_pam_authentication_plugin TSRMLS_CC);
}
/* }}} */
#define MYSQLND_CAPABILITIES (CLIENT_LONG_PASSWORD | CLIENT_LONG_FLAG | CLIENT_TRANSACTIONS | \
CLIENT_PROTOCOL_41 | CLIENT_SECURE_CONNECTION | \
- CLIENT_MULTI_RESULTS | CLIENT_PS_MULTI_RESULTS | CLIENT_LOCAL_FILES)
+ CLIENT_MULTI_RESULTS | CLIENT_PS_MULTI_RESULTS | CLIENT_LOCAL_FILES | CLIENT_PLUGIN_AUTH)
#define MYSQLND_NET_FLAG_USE_COMPRESSION 1
{
PROT_GREET_PACKET= 0,
PROT_AUTH_PACKET,
+ PROT_AUTH_RESP_PACKET,
+ PROT_CHANGE_AUTH_RESP_PACKET,
PROT_OK_PACKET,
PROT_EOF_PACKET,
PROT_CMD_PACKET,
count + MYSQLND_HEADER_SIZE = sizeof(buf) (not the pointer but the actual buffer)
*/
size_t
-MYSQLND_METHOD(mysqlnd_net, send)(MYSQLND * const conn, char * const buf, size_t count TSRMLS_DC)
+MYSQLND_METHOD(mysqlnd_net, send)(MYSQLND * const conn, zend_uchar * const buf, size_t count TSRMLS_DC)
{
zend_uchar safe_buf[((MYSQLND_HEADER_SIZE) + (sizeof(zend_uchar)) - 1) / (sizeof(zend_uchar))];
zend_uchar *safe_storage = safe_buf;
void mysqlnd_plugin_subsystem_init(TSRMLS_D);
void mysqlnd_plugin_subsystem_end(TSRMLS_D);
-void mysqlnd_native_authentication_plugin_register(TSRMLS_D);
+void mysqlnd_register_builtin_authentication_plugins(TSRMLS_D);
void mysqlnd_example_plugin_register(TSRMLS_D);
const char * const db,
const size_t db_len,
const size_t passwd_len,
- const struct st_mysqlnd_packet_greet * const greet_packet,
const MYSQLND_OPTIONS * const options,
unsigned long mysql_flags,
- struct st_mysqlnd_authentication_plugin * auth_plugin,
- char ** switch_to_auth_protocol
+ unsigned int server_charset_no,
+ zend_bool use_full_blown_auth_packet,
+ const char * const auth_protocol,
+ const zend_uchar * const auth_plugin_data,
+ const size_t auth_plugin_data_len,
+ char ** switch_to_auth_protocol,
+ size_t * switch_to_auth_protocol_len,
+ zend_uchar ** switch_to_auth_protocol_data,
+ size_t * switch_to_auth_protocol_data_len
TSRMLS_DC);
enum_func_status
const size_t db_len,
const size_t passwd_len,
const zend_bool silent,
- struct st_mysqlnd_authentication_plugin * auth_plugin,
- char ** switch_to_auth_protocol
+ zend_bool use_full_blown_auth_packet,
+ const char * const auth_protocol,
+ zend_uchar * auth_plugin_data,
+ size_t auth_plugin_data_len,
+ char ** switch_to_auth_protocol,
+ size_t * switch_to_auth_protocol_len,
+ zend_uchar ** switch_to_auth_protocol_data,
+ size_t * switch_to_auth_protocol_data_len
TSRMLS_DC);
#endif /* MYSQLND_PRIV_H */
typedef enum_func_status (*func_mysqlnd_net__connect)(MYSQLND_NET * net, const char * const scheme, size_t scheme_len, zend_bool persistent, char **errstr, int * errcode TSRMLS_DC);
-typedef size_t (*func_mysqlnd_net__send)(MYSQLND * const conn, char * const buf, size_t count TSRMLS_DC);
+typedef size_t (*func_mysqlnd_net__send)(MYSQLND * const conn, zend_uchar * const buf, size_t count TSRMLS_DC);
typedef enum_func_status (*func_mysqlnd_net__receive)(MYSQLND * conn, zend_uchar * buffer, size_t count TSRMLS_DC);
typedef enum_func_status (*func_mysqlnd_net__set_client_option)(MYSQLND_NET * const net, enum_mysqlnd_option option, const char * const value TSRMLS_DC);
typedef enum_func_status (*func_mysqlnd_net__network_read)(MYSQLND * conn, zend_uchar * buffer, size_t count TSRMLS_DC);
typedef struct st_mysqlnd_packet_greet * (*func_mysqlnd_protocol__get_greet_packet)(MYSQLND_PROTOCOL * const protocol, zend_bool persistent TSRMLS_DC);
typedef struct st_mysqlnd_packet_auth * (*func_mysqlnd_protocol__get_auth_packet)(MYSQLND_PROTOCOL * const protocol, zend_bool persistent TSRMLS_DC);
+typedef struct st_mysqlnd_packet_auth_response *(*func_mysqlnd_protocol__get_auth_response_packet)(MYSQLND_PROTOCOL * const protocol, zend_bool persistent TSRMLS_DC);
+typedef struct st_mysqlnd_packet_change_auth_response * (*func_mysqlnd_protocol__get_change_auth_response_packet)(MYSQLND_PROTOCOL * const protocol, zend_bool persistent TSRMLS_DC);
typedef struct st_mysqlnd_packet_ok * (*func_mysqlnd_protocol__get_ok_packet)(MYSQLND_PROTOCOL * const protocol, zend_bool persistent TSRMLS_DC);
typedef struct st_mysqlnd_packet_command * (*func_mysqlnd_protocol__get_command_packet)(MYSQLND_PROTOCOL * const protocol, zend_bool persistent TSRMLS_DC);
typedef struct st_mysqlnd_packet_eof * (*func_mysqlnd_protocol__get_eof_packet)(MYSQLND_PROTOCOL * const protocol, zend_bool persistent TSRMLS_DC);
{
func_mysqlnd_protocol__get_greet_packet get_greet_packet;
func_mysqlnd_protocol__get_auth_packet get_auth_packet;
+ func_mysqlnd_protocol__get_auth_response_packet get_auth_response_packet;
+ func_mysqlnd_protocol__get_change_auth_response_packet get_change_auth_response_packet;
func_mysqlnd_protocol__get_ok_packet get_ok_packet;
func_mysqlnd_protocol__get_command_packet get_command_packet;
func_mysqlnd_protocol__get_eof_packet get_eof_packet;
typedef enum mysqlnd_connection_state (*func_mysqlnd_conn__get_state)(MYSQLND * const conn TSRMLS_DC);
typedef void (*func_mysqlnd_conn__set_state)(MYSQLND * const conn, enum mysqlnd_connection_state new_state TSRMLS_DC);
-typedef enum_func_status (*func_mysqlnd_conn__simple_command)(MYSQLND *conn, enum php_mysqlnd_server_command command, const char * const arg, size_t arg_len, enum mysqlnd_packet_type ok_packet, zend_bool silent, zend_bool ignore_upsert_status TSRMLS_DC);
+typedef enum_func_status (*func_mysqlnd_conn__simple_command)(MYSQLND *conn, enum php_mysqlnd_server_command command, const zend_uchar * const arg, size_t arg_len, enum mysqlnd_packet_type ok_packet, zend_bool silent, zend_bool ignore_upsert_status TSRMLS_DC);
typedef enum_func_status (*func_mysqlnd_conn__simple_command_handle_response)(MYSQLND *conn, enum mysqlnd_packet_type ok_packet, zend_bool silent, enum php_mysqlnd_server_command command, zend_bool ignore_upsert_status TSRMLS_DC);
typedef enum_func_status (*func_mysqlnd_conn__restart_psession)(MYSQLND *conn TSRMLS_DC);
#include "mysqlnd_statistics.h"
#include "mysqlnd_debug.h"
#include "mysqlnd_block_alloc.h"
-#include "ext/standard/sha1.h"
#include "zend_ini.h"
#define MYSQLND_SILENT 1
/* }}} */
-/* {{{ php_mysqlnd_crypt */
-static void
-php_mysqlnd_crypt(zend_uchar *buffer, const zend_uchar *s1, const zend_uchar *s2, size_t len)
-{
- const zend_uchar *s1_end = s1 + len;
- while (s1 < s1_end) {
- *buffer++= *s1++ ^ *s2++;
- }
-}
-/* }}} */
-
-
-/* {{{ php_mysqlnd_scramble */
-void php_mysqlnd_scramble(zend_uchar * const buffer, const zend_uchar * const scramble, const zend_uchar * const password, size_t password_len)
-{
- PHP_SHA1_CTX context;
- zend_uchar sha1[SHA1_MAX_LENGTH];
- zend_uchar sha2[SHA1_MAX_LENGTH];
-
- /* Phase 1: hash password */
- PHP_SHA1Init(&context);
- PHP_SHA1Update(&context, password, password_len);
- PHP_SHA1Final(sha1, &context);
-
- /* Phase 2: hash sha1 */
- PHP_SHA1Init(&context);
- PHP_SHA1Update(&context, (zend_uchar*)sha1, SHA1_MAX_LENGTH);
- PHP_SHA1Final(sha2, &context);
-
- /* Phase 3: hash scramble + sha2 */
- PHP_SHA1Init(&context);
- PHP_SHA1Update(&context, scramble, SCRAMBLE_LENGTH);
- PHP_SHA1Update(&context, (zend_uchar*)sha2, SHA1_MAX_LENGTH);
- PHP_SHA1Final(buffer, &context);
-
- /* let's crypt buffer now */
- php_mysqlnd_crypt(buffer, (const zend_uchar *)buffer, (const zend_uchar *)sha1, SHA1_MAX_LENGTH);
-}
-/* }}} */
-
-
#define AUTH_WRITE_BUFFER_LEN (MYSQLND_HEADER_SIZE + MYSQLND_MAX_ALLOWED_USER_LEN + SCRAMBLE_LENGTH + MYSQLND_MAX_ALLOWED_DB_LEN + 1 + 1024)
/* {{{ php_mysqlnd_auth_write */
static
size_t php_mysqlnd_auth_write(void *_packet, MYSQLND * conn TSRMLS_DC)
{
- char buffer[AUTH_WRITE_BUFFER_LEN];
- register char *p= buffer + MYSQLND_HEADER_SIZE; /* start after the header */
+ zend_uchar buffer[AUTH_WRITE_BUFFER_LEN];
+ zend_uchar *p = buffer + MYSQLND_HEADER_SIZE; /* start after the header */
int len;
- register MYSQLND_PACKET_AUTH *packet= (MYSQLND_PACKET_AUTH *) _packet;
+ MYSQLND_PACKET_AUTH * packet= (MYSQLND_PACKET_AUTH *) _packet;
DBG_ENTER("php_mysqlnd_auth_write");
*p++ = '\0';
/* defensive coding */
- if (!packet->auth_data) {
- packet->auth_data = 0;
+ if (packet->auth_data == NULL) {
+ packet->auth_data_len = 0;
}
int1store(p, packet->auth_data_len);
++p;
memcpy(p, packet->db, real_db_len);
p+= real_db_len;
*p++= '\0';
+ } else if (packet->is_change_user_packet) {
+ *p++= '\0';
}
/* no \0 for no DB */
int2store(p, packet->charset_no);
p+= 2;
}
- } else {
- if (packet->auth_plugin_name) {
- size_t len = MIN(strlen(packet->auth_plugin_name), sizeof(buffer) - (p - buffer) - 1);
- memcpy(p, packet->auth_plugin_name, len);
- p+= len;
- *p++= '\0';
- }
+ }
+
+ if (packet->auth_plugin_name) {
+ size_t len = MIN(strlen(packet->auth_plugin_name), sizeof(buffer) - (p - buffer) - 1);
+ memcpy(p, packet->auth_plugin_name, len);
+ p+= len;
+ *p++= '\0';
}
}
if (packet->is_change_user_packet) {
/* }}} */
+#define AUTH_RESP_BUFFER_SIZE 2048
+
+/* {{{ php_mysqlnd_auth_response_read */
+static enum_func_status
+php_mysqlnd_auth_response_read(void *_packet, MYSQLND *conn TSRMLS_DC)
+{
+ zend_uchar local_buf[AUTH_RESP_BUFFER_SIZE];
+ size_t buf_len = conn->net->cmd_buffer.buffer? conn->net->cmd_buffer.length: AUTH_RESP_BUFFER_SIZE;
+ zend_uchar *buf = conn->net->cmd_buffer.buffer? (zend_uchar *) conn->net->cmd_buffer.buffer : local_buf;
+ zend_uchar *p = buf;
+ zend_uchar *begin = buf;
+ unsigned long i;
+ register MYSQLND_PACKET_AUTH_RESPONSE * packet= (MYSQLND_PACKET_AUTH_RESPONSE *) _packet;
+
+ DBG_ENTER("php_mysqlnd_auth_response_read");
+
+ /* leave space for terminating safety \0 */
+ buf_len--;
+ PACKET_READ_HEADER_AND_BODY(packet, conn, buf, buf_len, "OK", PROT_OK_PACKET);
+ BAIL_IF_NO_MORE_DATA;
+
+ /*
+ zero-terminate the buffer for safety. We are sure there is place for the \0
+ because buf_len is -1 the size of the buffer pointed
+ */
+ buf[packet->header.size] = '\0';
+
+ /* Should be always 0x0 or ERROR_MARKER for error */
+ 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
+ TSRMLS_CC);
+ 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 : [%*s]", packet->new_auth_protocol_data_len, packet->new_auth_protocol_data);
+ }
+ } else {
+ /* Everything was fine! */
+ packet->affected_rows = php_mysqlnd_net_field_length_ll(&p);
+ BAIL_IF_NO_MORE_DATA;
+
+ packet->last_insert_id = php_mysqlnd_net_field_length_ll(&p);
+ BAIL_IF_NO_MORE_DATA;
+
+ packet->server_status = uint2korr(p);
+ p+= 2;
+ BAIL_IF_NO_MORE_DATA;
+
+ packet->warning_count = uint2korr(p);
+ p+= 2;
+ BAIL_IF_NO_MORE_DATA;
+
+ /* There is a message */
+ if (packet->header.size > (size_t) (p - buf) && (i = php_mysqlnd_net_field_length(&p))) {
+ packet->message_len = MIN(i, buf_len - (p - begin));
+ packet->message = mnd_pestrndup((char *)p, packet->message_len, FALSE);
+ } else {
+ packet->message = NULL;
+ packet->message_len = 0;
+ }
+
+ DBG_INF_FMT("OK packet: aff_rows=%lld last_ins_id=%ld server_status=%u warnings=%u",
+ packet->affected_rows, packet->last_insert_id, packet->server_status,
+ packet->warning_count);
+ }
+
+ DBG_RETURN(PASS);
+premature_end:
+ DBG_ERR_FMT("OK packet %d bytes shorter than expected", p - begin - packet->header.size);
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "AUTH_RESPONSE packet "MYSQLND_SZ_T_SPEC" bytes shorter than expected",
+ p - begin - packet->header.size);
+ DBG_RETURN(FAIL);
+}
+/* }}} */
+
+
+/* {{{ php_mysqlnd_auth_response_free_mem */
+static void
+php_mysqlnd_auth_response_free_mem(void *_packet, zend_bool stack_allocation TSRMLS_DC)
+{
+ MYSQLND_PACKET_AUTH_RESPONSE * p = (MYSQLND_PACKET_AUTH_RESPONSE *) _packet;
+ if (p->message) {
+ mnd_efree(p->message);
+ p->message = NULL;
+ }
+ if (p->new_auth_protocol) {
+ mnd_efree(p->new_auth_protocol);
+ p->new_auth_protocol = NULL;
+ }
+ p->new_auth_protocol_len = 0;
+
+ if (p->new_auth_protocol_data) {
+ mnd_efree(p->new_auth_protocol_data);
+ p->new_auth_protocol_data = NULL;
+ }
+ p->new_auth_protocol_data_len = 0;
+
+ if (!stack_allocation) {
+ mnd_pefree(p, p->header.persistent);
+ }
+}
+/* }}} */
+
+
+/* {{{ php_mysqlnd_change_auth_response_write */
+static
+size_t php_mysqlnd_change_auth_response_write(void *_packet, MYSQLND * conn TSRMLS_DC)
+{
+ MYSQLND_PACKET_CHANGE_AUTH_RESPONSE *packet= (MYSQLND_PACKET_CHANGE_AUTH_RESPONSE *) _packet;
+ zend_uchar * buffer = conn->net->cmd_buffer.length >= packet->auth_data_len? conn->net->cmd_buffer.buffer : mnd_emalloc(packet->auth_data_len);
+ zend_uchar *p = buffer + MYSQLND_HEADER_SIZE; /* start after the header */
+
+ DBG_ENTER("php_mysqlnd_change_auth_response_write");
+
+ if (packet->auth_data_len) {
+ memcpy(p, packet->auth_data, packet->auth_data_len);
+ p+= packet->auth_data_len;
+ }
+
+ {
+ size_t ret = conn->net->m.send(conn, buffer, p - buffer - MYSQLND_HEADER_SIZE TSRMLS_CC);
+ if (buffer != conn->net->cmd_buffer.buffer) {
+ mnd_efree(buffer);
+ }
+ DBG_RETURN(ret);
+ }
+}
+/* }}} */
+
+
+/* {{{ php_mysqlnd_change_auth_response_free_mem */
+static
+void php_mysqlnd_change_auth_response_free_mem(void *_packet, zend_bool stack_allocation TSRMLS_DC)
+{
+ if (!stack_allocation) {
+ MYSQLND_PACKET_CHANGE_AUTH_RESPONSE * p = (MYSQLND_PACKET_CHANGE_AUTH_RESPONSE *) _packet;
+ mnd_pefree(p, p->header.persistent);
+ }
+}
+/* }}} */
+
+
#define OK_BUFFER_SIZE 2048
/* {{{ php_mysqlnd_ok_read */
#endif
if (!packet->argument || !packet->arg_len) {
- char buffer[MYSQLND_HEADER_SIZE + 1];
+ zend_uchar buffer[MYSQLND_HEADER_SIZE + 1];
int1store(buffer + MYSQLND_HEADER_SIZE, packet->command);
written = conn->net->m.send(conn, buffer, 1 TSRMLS_CC);
memcpy(p, packet->argument, packet->arg_len);
- ret = conn->net->m.send(conn, (char *)tmp, tmp_len - MYSQLND_HEADER_SIZE TSRMLS_CC);
+ ret = conn->net->m.send(conn, tmp, tmp_len - MYSQLND_HEADER_SIZE TSRMLS_CC);
if (tmp != net->cmd_buffer.buffer) {
MYSQLND_INC_CONN_STATISTIC(conn->stats, STAT_CMD_BUFFER_TOO_SMALL);
mnd_efree(tmp);
*/
/* Should be always 0x0 or ERROR_MARKER for error */
- packet->field_count= uint1korr(p);
+ packet->response_code = uint1korr(p);
p++;
if (packet->header.size == 1 && buf[0] == EODATA_MARKER && packet->server_capabilities & CLIENT_SECURE_CONNECTION) {
DBG_RETURN(FAIL);
}
- if (ERROR_MARKER == packet->field_count) {
+ if (ERROR_MARKER == packet->response_code) {
php_mysqlnd_read_error_from_line(p, packet->header.size - 1,
packet->error_info.error,
sizeof(packet->error_info.error),
TSRMLS_CC);
}
BAIL_IF_NO_MORE_DATA;
+ if (packet->response_code == 0xFE && 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 : [%*s]", packet->new_auth_protocol_data_len, packet->new_auth_protocol_data);
+ }
DBG_RETURN(PASS);
premature_end:
static void
php_mysqlnd_chg_user_free_mem(void *_packet, zend_bool stack_allocation TSRMLS_DC)
{
+ MYSQLND_PACKET_CHG_USER_RESPONSE * p = (MYSQLND_PACKET_CHG_USER_RESPONSE *) _packet;
+
+ if (p->new_auth_protocol) {
+ mnd_efree(p->new_auth_protocol);
+ p->new_auth_protocol = NULL;
+ }
+ p->new_auth_protocol_len = 0;
+
+ if (p->new_auth_protocol_data) {
+ mnd_efree(p->new_auth_protocol_data);
+ p->new_auth_protocol_data = NULL;
+ }
+ p->new_auth_protocol_data_len = 0;
+
if (!stack_allocation) {
- mnd_pefree(_packet, ((MYSQLND_PACKET_CHG_USER_RESPONSE *)_packet)->header.persistent);
+ mnd_pefree(p, p->header.persistent);
}
}
/* }}} */
php_mysqlnd_auth_write,
php_mysqlnd_auth_free_mem,
}, /* PROT_AUTH_PACKET */
+ {
+ sizeof(MYSQLND_PACKET_AUTH_RESPONSE),
+ php_mysqlnd_auth_response_read, /* read */
+ NULL, /* write */
+ php_mysqlnd_auth_response_free_mem,
+ }, /* PROT_AUTH_RESP_PACKET */
+ {
+ sizeof(MYSQLND_PACKET_CHANGE_AUTH_RESPONSE),
+ NULL, /* read */
+ php_mysqlnd_change_auth_response_write, /* write */
+ php_mysqlnd_change_auth_response_free_mem,
+ }, /* PROT_CHANGE_AUTH_RESP_PACKET */
{
sizeof(MYSQLND_PACKET_OK),
php_mysqlnd_ok_read, /* read */
/* }}} */
+/* {{{ mysqlnd_protocol::get_auth_response_packet */
+static struct st_mysqlnd_packet_auth_response *
+MYSQLND_METHOD(mysqlnd_protocol, get_auth_response_packet)(MYSQLND_PROTOCOL * const protocol, zend_bool persistent TSRMLS_DC)
+{
+ struct st_mysqlnd_packet_auth_response * packet = mnd_pecalloc(1, packet_methods[PROT_AUTH_RESP_PACKET].struct_size, persistent);
+ DBG_ENTER("mysqlnd_protocol::get_auth_response_packet");
+ if (packet) {
+ packet->header.m = &packet_methods[PROT_AUTH_RESP_PACKET];
+ packet->header.persistent = persistent;
+ }
+ DBG_RETURN(packet);
+}
+/* }}} */
+
+
+/* {{{ mysqlnd_protocol::get_change_auth_response_packet */
+static struct st_mysqlnd_packet_change_auth_response *
+MYSQLND_METHOD(mysqlnd_protocol, get_change_auth_response_packet)(MYSQLND_PROTOCOL * const protocol, zend_bool persistent TSRMLS_DC)
+{
+ struct st_mysqlnd_packet_change_auth_response * packet = mnd_pecalloc(1, packet_methods[PROT_CHANGE_AUTH_RESP_PACKET].struct_size, persistent);
+ DBG_ENTER("mysqlnd_protocol::get_change_auth_response_packet");
+ if (packet) {
+ packet->header.m = &packet_methods[PROT_CHANGE_AUTH_RESP_PACKET];
+ packet->header.persistent = persistent;
+ }
+ DBG_RETURN(packet);
+}
+/* }}} */
+
+
/* {{{ mysqlnd_protocol::get_ok_packet */
static struct st_mysqlnd_packet_ok *
MYSQLND_METHOD(mysqlnd_protocol, get_ok_packet)(MYSQLND_PROTOCOL * const protocol, zend_bool persistent TSRMLS_DC)
MYSQLND_CLASS_METHODS_START(mysqlnd_protocol)
MYSQLND_METHOD(mysqlnd_protocol, get_greet_packet),
MYSQLND_METHOD(mysqlnd_protocol, get_auth_packet),
+ MYSQLND_METHOD(mysqlnd_protocol, get_auth_response_packet),
+ MYSQLND_METHOD(mysqlnd_protocol, get_change_auth_response_packet),
MYSQLND_METHOD(mysqlnd_protocol, get_ok_packet),
MYSQLND_METHOD(mysqlnd_protocol, get_command_packet),
MYSQLND_METHOD(mysqlnd_protocol, get_eof_packet),
/* If error packet, we use these */
char error[MYSQLND_ERRMSG_SIZE+1];
char sqlstate[MYSQLND_SQLSTATE_LENGTH + 1];
- unsigned int error_no;
+ unsigned int error_no;
char *auth_protocol;
} MYSQLND_PACKET_GREET;
uint32_t max_packet_size;
uint8_t charset_no;
const char *user;
- zend_uchar *auth_data;
+ const zend_uchar *auth_data;
size_t auth_data_len;
const char *db;
- char *auth_plugin_name;
+ const char *auth_plugin_name;
/* Here the packet ends. This is user supplied data */
size_t db_len;
zend_bool send_auth_data;
} MYSQLND_PACKET_AUTH;
+/* Auth response packet */
+typedef struct st_mysqlnd_packet_auth_response {
+ MYSQLND_PACKET_HEADER header;
+ uint8_t response_code;
+ uint64_t affected_rows;
+ uint64_t last_insert_id;
+ uint16_t server_status;
+ uint16_t warning_count;
+ char *message;
+ size_t message_len;
+ /* If error packet, we use these */
+ char error[MYSQLND_ERRMSG_SIZE+1];
+ char sqlstate[MYSQLND_SQLSTATE_LENGTH + 1];
+ unsigned int error_no;
+
+ char *new_auth_protocol;
+ size_t new_auth_protocol_len;
+ zend_uchar *new_auth_protocol_data;
+ size_t new_auth_protocol_data_len;
+} MYSQLND_PACKET_AUTH_RESPONSE;
+
+
+/* Auth response packet */
+typedef struct st_mysqlnd_packet_change_auth_response {
+ MYSQLND_PACKET_HEADER header;
+ const zend_uchar *auth_data;
+ size_t auth_data_len;
+} MYSQLND_PACKET_CHANGE_AUTH_RESPONSE;
+
+
/* OK packet */
typedef struct st_mysqlnd_packet_ok {
MYSQLND_PACKET_HEADER header;
typedef struct st_mysqlnd_packet_command {
MYSQLND_PACKET_HEADER header;
enum php_mysqlnd_server_command command;
- const char *argument;
+ const zend_uchar *argument;
size_t arg_len;
} MYSQLND_PACKET_COMMAND;
/* Statistics packet */
typedef struct st_mysqlnd_packet_chg_user_resp {
MYSQLND_PACKET_HEADER header;
- uint32_t field_count;
+ uint32_t response_code;
/* message_len is not part of the packet*/
uint16_t server_capabilities;
/* If error packet, we use these */
MYSQLND_ERROR_INFO error_info;
zend_bool server_asked_323_auth;
+
+ char *new_auth_protocol;
+ size_t new_auth_protocol_len;
+ zend_uchar *new_auth_protocol_data;
+ size_t new_auth_protocol_data_len;
} MYSQLND_PACKET_CHG_USER_RESPONSE;