structure and where they load themselves.
0xFE packets (method switch) needs to be done, additional
wire-level packet to be created to be parsed and the packet
doesn't fit the PACKET_OK structure anymore.
mnd_pefree(conn->host_info, pers);
conn->host_info = NULL;
}
- if (conn->scramble) {
- DBG_INF("Freeing scramble");
- mnd_pefree(conn->scramble, pers);
- conn->scramble = NULL;
+ if (conn->auth_plugin_data) {
+ DBG_INF("Freeing auth_plugin_data");
+ mnd_pefree(conn->auth_plugin_data, pers);
+ conn->auth_plugin_data = NULL;
}
if (conn->last_message) {
mnd_pefree(conn->last_message, pers);
auth_plugin = mysqlnd_plugin_find(plugin_name);
efree(plugin_name);
if (!auth_plugin) {
- php_error_docref(NULL TSRMLS_CC, E_WARNING, "Server requested authentication method uknown to the client [%s]", requested_protocol);
- SET_CLIENT_ERROR(conn->error_info, CR_NOT_IMPLEMENTED, UNKNOWN_SQLSTATE, "Server requested authentication method uknown to the client");
+ 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;
}
DBG_INF("plugin found");
- ret = auth_plugin->methods.auth_handshake(conn, user, passwd, db, db_len, passwd_len, greet_packet, options, mysql_flags,
- &switch_to_auth_protocol TSRMLS_CC);
+ 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);
db = "";
}
+
{
char * switch_to_auth_protocol = NULL;
const char * requested_protocol = NULL;
efree(plugin_name);
if (!auth_plugin) {
if (!silent) {
- php_error_docref(NULL TSRMLS_CC, E_WARNING, "Server requested authentication method uknown to the client [%s]", requested_protocol);
+ 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, "Server requested authentication method uknown to the client");
+ 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 = auth_plugin->methods.auth_change_user(conn, user, strlen(user), passwd, db, strlen(db), passwd_len, silent, &switch_to_auth_protocol TSRMLS_CC);
+ 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);
if (ret == PASS) {
/* {{{ mysqlnd_native_auth_handshake */
-static enum_func_status
-mysqlnd_native_auth_handshake(MYSQLND * conn,
+enum_func_status
+mysqlnd_auth_handshake(MYSQLND * conn,
const char * const user,
const char * const passwd,
const char * const db,
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
TSRMLS_DC)
{
DBG_ENTER("mysqlnd_native_auth_handshake");
- /* 5.5.x reports 21 as scramble length because it needs to show the length of the data before the plugin name */
- if (greet_packet->scramble_buf_len != SCRAMBLE_LENGTH && (greet_packet->scramble_buf_len != 21)) {
- /* 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", greet_packet->scramble_buf_len, SCRAMBLE_LENGTH);
- goto end;
- }
-
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_packet->send_auth_data = TRUE;
auth_packet->user = user;
- auth_packet->password = passwd;
auth_packet->db = db;
auth_packet->db_len = db_len;
- auth_packet->server_scramble_buf_len = greet_packet->scramble_buf_len;
- conn->scramble = auth_packet->server_scramble_buf = mnd_pemalloc(auth_packet->server_scramble_buf_len, conn->persistent);
- if (!conn->scramble) {
+ 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(auth_packet->server_scramble_buf, greet_packet->scramble_buf, greet_packet->scramble_buf_len);
+ memcpy(conn->auth_plugin_data, greet_packet->auth_plugin_data, greet_packet->auth_plugin_data_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);
+
if (!PACKET_WRITE(auth_packet, conn)) {
CONN_SET_STATE(conn, CONN_QUIT_SENT);
conn->charset = mysqlnd_find_charset_nr(auth_packet->charset_no);
ret = PASS;
end:
+ mnd_efree(auth_packet->auth_data);
PACKET_FREE(auth_packet);
PACKET_FREE(ok_packet);
DBG_RETURN(ret);
/* {{{ mysqlnd_native_auth_change_user */
-static enum_func_status
-mysqlnd_native_auth_change_user(MYSQLND * const conn,
+enum_func_status
+mysqlnd_auth_change_user(MYSQLND * const conn,
const char * const user,
const size_t user_len,
const char * const passwd,
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
TSRMLS_DC)
{
SET_OOM_ERROR(conn->error_info);
goto end;
}
+
auth_packet->is_change_user_packet = TRUE;
auth_packet->user = user;
- auth_packet->password = passwd;
auth_packet->db = db;
auth_packet->db_len = db_len;
- auth_packet->server_scramble_buf = conn->scramble;
auth_packet->silent = silent;
+
+ 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);
+
if (mysqlnd_get_server_version(conn) >= 50123) {
auth_packet->charset_no = conn->charset->nr;
p+=2;
SET_CLIENT_ERROR(conn->error_info, CR_UNKNOWN_ERROR, UNKNOWN_SQLSTATE, mysqlnd_old_passwd);
}
end:
+ mnd_efree(auth_packet->auth_data);
PACKET_FREE(auth_packet);
PACKET_FREE(chg_user_resp);
DBG_RETURN(ret);
}
/* }}} */
+
+/* {{{ mysqlnd_native_auth_get_auth_data */
+static zend_uchar *
+mysqlnd_native_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;
+ DBG_ENTER("mysqlnd_native_auth_get_auth_data");
+ *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)) {
+ /* 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);
+ DBG_RETURN(NULL);
+ }
+
+ /* copy scrambled pass*/
+ if (passwd && passwd_len) {
+ ret = mnd_emalloc(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);
+ }
+ DBG_RETURN(ret);
+}
+/* }}} */
+
+
static struct st_mysqlnd_authentication_plugin mysqlnd_native_auth_plugin =
{
{
}
},
{/* methods */
- mysqlnd_native_auth_handshake,
- mysqlnd_native_auth_change_user
+ mysqlnd_native_auth_get_auth_data
}
};
+
/* {{{ mysqlnd_native_authentication_plugin_register */
void
mysqlnd_native_authentication_plugin_register(TSRMLS_D)
void mysqlnd_example_plugin_register(TSRMLS_D);
+struct st_mysqlnd_packet_greet;
+struct st_mysqlnd_authentication_plugin;
+
+enum_func_status
+mysqlnd_auth_handshake(MYSQLND * conn,
+ const char * const user,
+ const char * const passwd,
+ 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
+ TSRMLS_DC);
+
+enum_func_status
+mysqlnd_auth_change_user(MYSQLND * const conn,
+ const char * const user,
+ const size_t user_len,
+ const char * const passwd,
+ const char * const db,
+ 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
+ TSRMLS_DC);
+
#endif /* MYSQLND_PRIV_H */
uint64_t thread_id;
char *server_version;
char *host_info;
- unsigned char *scramble;
+ zend_uchar *auth_plugin_data;
+ size_t auth_plugin_data_len;
const MYSQLND_CHARSET *charset;
const MYSQLND_CHARSET *greet_charset;
char *connect_or_select_db;
unsigned int counter;
};
-struct st_mysqlnd_packet_greet;
+struct st_mysqlnd_authentication_plugin;
+
+typedef zend_uchar * (*func_auth_plugin__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);
struct st_mysqlnd_authentication_plugin
{
struct st_mysqlnd_plugin_header plugin_header;
struct {
- enum_func_status (*auth_handshake)(MYSQLND * conn, const char * const user, const char * const passwd, 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,
- char ** switch_to_auth_protocol TSRMLS_DC);
-
- enum_func_status (*auth_change_user)(MYSQLND * const conn, const char * const user, const size_t user_len, const char * const passwd,
- const char * const db, const size_t db_len, const size_t passwd_len, const zend_bool silent,
- char ** switch_to_auth_protocol TSRMLS_DC);
+ func_auth_plugin__get_auth_data get_auth_data;
} methods;
};
+
#endif /* MYSQLND_STRUCTS_H */
PACKET_READ_HEADER_AND_BODY(packet, conn, buf, sizeof(buf), "greeting", PROT_GREET_PACKET);
BAIL_IF_NO_MORE_DATA;
- packet->scramble_buf = &packet->intern_scramble_buf;
- packet->scramble_buf_len = sizeof(packet->intern_scramble_buf);
+ packet->auth_plugin_data = packet->intern_auth_plugin_data;
+ packet->auth_plugin_data_len = sizeof(packet->intern_auth_plugin_data);
if (packet->header.size < sizeof(buf)) {
/*
p+=4;
BAIL_IF_NO_MORE_DATA;
- memcpy(packet->scramble_buf, p, SCRAMBLE_LENGTH_323);
+ memcpy(packet->auth_plugin_data, p, SCRAMBLE_LENGTH_323);
p+= SCRAMBLE_LENGTH_323;
BAIL_IF_NO_MORE_DATA;
BAIL_IF_NO_MORE_DATA;
if ((size_t) (p - buf) < packet->header.size) {
- /* scramble_buf is split into two parts */
- memcpy(packet->scramble_buf + SCRAMBLE_LENGTH_323, p, SCRAMBLE_LENGTH - SCRAMBLE_LENGTH_323);
+ /* auth_plugin_data is split into two parts */
+ memcpy(packet->auth_plugin_data + SCRAMBLE_LENGTH_323, p, SCRAMBLE_LENGTH - SCRAMBLE_LENGTH_323);
p+= SCRAMBLE_LENGTH - SCRAMBLE_LENGTH_323;
p++; /* 0x0 at the end of the scramble and thus last byte in the packet in 5.1 and previous */
} else {
/* Additional 16 bits for server capabilities */
packet->server_capabilities |= uint2korr(pad_start) << 16;
/* And a length of the server scramble in one byte */
- packet->scramble_buf_len = uint1korr(pad_start + 2);
- if (packet->scramble_buf_len > SCRAMBLE_LENGTH) {
+ packet->auth_plugin_data_len = uint1korr(pad_start + 2);
+ if (packet->auth_plugin_data_len > SCRAMBLE_LENGTH) {
/* more data*/
- char * new_scramble_buf = emalloc(packet->scramble_buf_len);
- if (!new_scramble_buf) {
+ zend_uchar * new_auth_plugin_data = emalloc(packet->auth_plugin_data_len);
+ if (!new_auth_plugin_data) {
goto premature_end;
}
/* copy what we already have */
- memcpy(new_scramble_buf, packet->scramble_buf, SCRAMBLE_LENGTH);
+ memcpy(new_auth_plugin_data, packet->auth_plugin_data, SCRAMBLE_LENGTH);
/* add additional scramble data 5.5+ sent us */
- memcpy(new_scramble_buf + SCRAMBLE_LENGTH, p, packet->scramble_buf_len - SCRAMBLE_LENGTH);
- p+= (packet->scramble_buf_len - SCRAMBLE_LENGTH);
- packet->scramble_buf = new_scramble_buf;
+ memcpy(new_auth_plugin_data + SCRAMBLE_LENGTH, p, packet->auth_plugin_data_len - SCRAMBLE_LENGTH);
+ p+= (packet->auth_plugin_data_len - SCRAMBLE_LENGTH);
+ packet->auth_plugin_data = new_auth_plugin_data;
}
}
DBG_INF_FMT("server_capabilities=%u charset_no=%u server_status=%i auth_protocol=%s scramble_length=%u",
packet->server_capabilities, packet->charset_no, packet->server_status,
- packet->auth_protocol? packet->auth_protocol:"n/a", packet->scramble_buf_len);
+ packet->auth_protocol? packet->auth_protocol:"n/a", packet->auth_plugin_data_len);
DBG_RETURN(PASS);
premature_end:
efree(p->server_version);
p->server_version = NULL;
}
- if (p->scramble_buf && p->scramble_buf != &p->intern_scramble_buf) {
- efree(p->scramble_buf);
- p->scramble_buf = NULL;
+ if (p->auth_plugin_data && p->auth_plugin_data != p->intern_auth_plugin_data) {
+ efree(p->auth_plugin_data);
+ p->auth_plugin_data = NULL;
}
if (p->auth_protocol) {
efree(p->auth_protocol);
/* {{{ php_mysqlnd_scramble */
-void php_mysqlnd_scramble(zend_uchar * const buffer, const zend_uchar * const scramble, const zend_uchar * const password)
+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];
/* Phase 1: hash password */
PHP_SHA1Init(&context);
- PHP_SHA1Update(&context, password, strlen((char *)password));
+ PHP_SHA1Update(&context, password, password_len);
PHP_SHA1Final(sha1, &context);
/* Phase 2: hash sha1 */
/* }}} */
-#define AUTH_WRITE_BUFFER_LEN (MYSQLND_HEADER_SIZE + MYSQLND_MAX_ALLOWED_USER_LEN + SCRAMBLE_LENGTH + MYSQLND_MAX_ALLOWED_DB_LEN + 1 + 128)
+#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
p+= len;
*p++ = '\0';
- /* copy scrambled pass*/
- if (packet->password && packet->password[0]) {
- /* In 4.1 we use CLIENT_SECURE_CONNECTION and thus the len of the buf should be passed */
- int1store(p, SCRAMBLE_LENGTH);
- p++;
- php_mysqlnd_scramble((zend_uchar*)p, packet->server_scramble_buf, (zend_uchar*)packet->password);
- p+= SCRAMBLE_LENGTH;
- } else {
- /* Zero length */
- int1store(p, 0);
- p++;
+ /* defensive coding */
+ if (!packet->auth_data) {
+ packet->auth_data = 0;
+ }
+ int1store(p, packet->auth_data_len);
+ ++p;
+/*!!!!! is the buffer big enough ??? */
+ if ((sizeof(buffer) - (p - buffer)) < packet->auth_data_len) {
+ DBG_ERR("the stack buffer was not enough!!");
+ DBG_RETURN(0);
+ }
+ if (packet->auth_data_len) {
+ memcpy(p, packet->auth_data, packet->auth_data_len);
+ p+= packet->auth_data_len;
}
if (packet->db) {
}
/* no \0 for no DB */
- if (packet->is_change_user_packet && packet->charset_no) {
- int2store(p, packet->charset_no);
- p+= 2;
+ if (packet->is_change_user_packet) {
+ if (packet->charset_no) {
+ 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->is_change_user_packet) {
uint8_t protocol_version;
char *server_version;
uint32_t thread_id;
- zend_uchar intern_scramble_buf[SCRAMBLE_LENGTH];
- zend_uchar * scramble_buf;
- size_t scramble_buf_len;
+ zend_uchar intern_auth_plugin_data[SCRAMBLE_LENGTH];
+ zend_uchar * auth_plugin_data;
+ size_t auth_plugin_data_len;
/* 1 byte pad */
uint32_t server_capabilities;
uint8_t charset_no;
MYSQLND_PACKET_HEADER header;
uint32_t client_flags;
uint32_t max_packet_size;
- uint8_t charset_no;
- /* 23 byte pad */
+ uint8_t charset_no;
const char *user;
- /* 8 byte scramble */
+ zend_uchar *auth_data;
+ size_t auth_data_len;
const char *db;
- /* 12 byte scramble */
-
+ char *auth_plugin_name;
/* Here the packet ends. This is user supplied data */
- const char *password;
- /* +1 for \0 because of scramble() */
- unsigned char *server_scramble_buf;
- size_t server_scramble_buf_len;
- size_t db_len;
- zend_bool send_auth_data;
- zend_bool is_change_user_packet;
- zend_bool silent;
+ size_t db_len;
+ zend_bool send_auth_data;
+ zend_bool is_change_user_packet;
+ zend_bool silent;
+
} MYSQLND_PACKET_AUTH;
/* OK packet */
} MYSQLND_PACKET_CHG_USER_RESPONSE;
-PHPAPI void php_mysqlnd_scramble(zend_uchar * const buffer, const zend_uchar * const scramble, const zend_uchar * const pass);
+PHPAPI void php_mysqlnd_scramble(zend_uchar * const buffer, const zend_uchar * const scramble, const zend_uchar * const pass, size_t pass_len);
unsigned long php_mysqlnd_net_field_length(zend_uchar **packet);
zend_uchar * php_mysqlnd_net_store_length(zend_uchar *packet, uint64_t length);