summaryrefslogtreecommitdiff
path: root/ext/mysqlnd/mysqlnd_wireprotocol.c
diff options
context:
space:
mode:
authorAndrey Hristov <andrey@php.net>2011-01-12 21:40:05 +0000
committerAndrey Hristov <andrey@php.net>2011-01-12 21:40:05 +0000
commit429e07bba242e99799300fa61b517af7cac24267 (patch)
tree36fd89941a21f712a200d589aaeef2632c440c74 /ext/mysqlnd/mysqlnd_wireprotocol.c
parent8e73b7080614b4e82177aa6faedb16b028f71937 (diff)
downloadphp-git-429e07bba242e99799300fa61b517af7cac24267.tar.gz
grok the MySQL 5.5 extended handshake.
Move the authentication routines, the native ones, to separate file and encapsulate them in a plugin. Depending on the server version and what the server requests (or doesn't in old versions) load the authentication plugin to handle it. Currently only the 4.1+ authentication is supported. More to come
Diffstat (limited to 'ext/mysqlnd/mysqlnd_wireprotocol.c')
-rw-r--r--ext/mysqlnd/mysqlnd_wireprotocol.c65
1 files changed, 59 insertions, 6 deletions
diff --git a/ext/mysqlnd/mysqlnd_wireprotocol.c b/ext/mysqlnd/mysqlnd_wireprotocol.c
index f3a4ba4c1e..2ee894f639 100644
--- a/ext/mysqlnd/mysqlnd_wireprotocol.c
+++ b/ext/mysqlnd/mysqlnd_wireprotocol.c
@@ -306,6 +306,7 @@ php_mysqlnd_greet_read(void *_packet, MYSQLND *conn TSRMLS_DC)
zend_uchar buf[2048];
zend_uchar *p = buf;
zend_uchar *begin = buf;
+ zend_uchar *pad_start = NULL;
MYSQLND_PACKET_GREET *packet= (MYSQLND_PACKET_GREET *) _packet;
DBG_ENTER("php_mysqlnd_greet_read");
@@ -313,6 +314,17 @@ php_mysqlnd_greet_read(void *_packet, MYSQLND *conn TSRMLS_DC)
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);
+
+ if (packet->header.size < sizeof(buf)) {
+ /*
+ Null-terminate the string, so strdup can work even if the packets have a string at the end,
+ which is not ASCIIZ
+ */
+ buf[packet->header.size] = '\0';
+ }
+
packet->protocol_version = uint1korr(p);
p++;
BAIL_IF_NO_MORE_DATA;
@@ -342,7 +354,7 @@ php_mysqlnd_greet_read(void *_packet, MYSQLND *conn TSRMLS_DC)
BAIL_IF_NO_MORE_DATA;
memcpy(packet->scramble_buf, p, SCRAMBLE_LENGTH_323);
- p+= 8;
+ p+= SCRAMBLE_LENGTH_323;
BAIL_IF_NO_MORE_DATA;
/* pad1 */
@@ -362,22 +374,56 @@ php_mysqlnd_greet_read(void *_packet, MYSQLND *conn TSRMLS_DC)
BAIL_IF_NO_MORE_DATA;
/* pad2 */
+ pad_start = p;
p+= 13;
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);
+ memcpy(packet->scramble_buf + 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 {
packet->pre41 = TRUE;
}
+ /* Is this a 5.5+ server ? */
+ if ((size_t) (p - buf) < packet->header.size) {
+ /* backtrack one byte, the 0x0 at the end of the scramble in 5.1 and previous */
+ p--;
+
+ /* 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) {
+ /* more data*/
+ char * new_scramble_buf = emalloc(packet->scramble_buf_len);
+ if (!new_scramble_buf) {
+ goto premature_end;
+ }
+ /* copy what we already have */
+ memcpy(new_scramble_buf, packet->scramble_buf, 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;
+ }
+ }
+
+ if (packet->server_capabilities & CLIENT_PLUGIN_AUTH) {
+ BAIL_IF_NO_MORE_DATA;
+ /* The server is 5.5.x and supports authentication plugins */
+ packet->auth_protocol = estrdup((char *)p);
+ p+= strlen(packet->auth_protocol) + 1; /* eat the '\0' */
+ }
+
DBG_INF_FMT("proto=%u server=%s thread_id=%u",
packet->protocol_version, packet->server_version, packet->thread_id);
- DBG_INF_FMT("server_capabilities=%u charset_no=%u server_status=%i",
- packet->server_capabilities, packet->charset_no, packet->server_status);
+ 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);
DBG_RETURN(PASS);
premature_end:
@@ -398,6 +444,14 @@ void php_mysqlnd_greet_free_mem(void *_packet, zend_bool stack_allocation TSRMLS
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_protocol) {
+ efree(p->auth_protocol);
+ p->auth_protocol = NULL;
+ }
if (!stack_allocation) {
mnd_pefree(p, p->header.persistent);
}
@@ -424,7 +478,6 @@ void php_mysqlnd_scramble(zend_uchar * const buffer, const zend_uchar * const sc
zend_uchar sha1[SHA1_MAX_LENGTH];
zend_uchar sha2[SHA1_MAX_LENGTH];
-
/* Phase 1: hash password */
PHP_SHA1Init(&context);
PHP_SHA1Update(&context, password, strlen((char *)password));