1 /*
2 +----------------------------------------------------------------------+
3 | PHP Version 7 |
4 +----------------------------------------------------------------------+
5 | Copyright (c) 2006-2017 The PHP Group |
6 +----------------------------------------------------------------------+
7 | This source file is subject to version 3.01 of the PHP license, |
8 | that is bundled with this package in the file LICENSE, and is |
9 | available through the world-wide-web at the following url: |
10 | http://www.php.net/license/3_01.txt |
11 | If you did not receive a copy of the PHP license and are unable to |
12 | obtain it through the world-wide-web, please send a note to |
13 | license@php.net so we can mail you a copy immediately. |
14 +----------------------------------------------------------------------+
15 | Authors: Andrey Hristov <andrey@php.net> |
16 | Ulf Wendel <uw@php.net> |
17 | Georg Richter <georg@php.net> |
18 +----------------------------------------------------------------------+
19 */
20
21 #include "php.h"
22 #include "php_globals.h"
23 #include "mysqlnd.h"
24 #include "mysqlnd_priv.h"
25 #include "mysqlnd_wireprotocol.h"
26 #include "mysqlnd_statistics.h"
27 #include "mysqlnd_debug.h"
28 #include "zend_ini.h"
29
30 #define MYSQLND_SILENT 1
31
32 #define MYSQLND_DUMP_HEADER_N_BODY
33
34 #define PACKET_READ_HEADER_AND_BODY(packet, conn, buf, buf_size, packet_type_as_text, packet_type) \
35 { \
36 DBG_INF_FMT("buf=%p size=%u", (buf), (buf_size)); \
37 if (FAIL == mysqlnd_read_header((conn)->net, &((packet)->header), (conn)->stats, ((conn)->error_info))) {\
38 CONN_SET_STATE(conn, CONN_QUIT_SENT); \
39 SET_CLIENT_ERROR(*conn->error_info, CR_SERVER_GONE_ERROR, UNKNOWN_SQLSTATE, mysqlnd_server_gone);\
40 php_error_docref(NULL, E_WARNING, "%s", mysqlnd_server_gone); \
41 DBG_ERR_FMT("Can't read %s's header", (packet_type_as_text)); \
42 DBG_RETURN(FAIL);\
43 }\
44 if ((buf_size) < (packet)->header.size) { \
45 DBG_ERR_FMT("Packet buffer %u wasn't big enough %u, %u bytes will be unread", \
46 (buf_size), (packet)->header.size, (packet)->header.size - (buf_size)); \
47 DBG_RETURN(FAIL); \
48 }\
49 if (FAIL == conn->net->data->m.receive_ex((conn)->net, (buf), (packet)->header.size, (conn)->stats, ((conn)->error_info))) { \
50 CONN_SET_STATE(conn, CONN_QUIT_SENT); \
51 SET_CLIENT_ERROR(*conn->error_info, CR_SERVER_GONE_ERROR, UNKNOWN_SQLSTATE, mysqlnd_server_gone);\
52 php_error_docref(NULL, E_WARNING, "%s", mysqlnd_server_gone); \
53 DBG_ERR_FMT("Empty '%s' packet body", (packet_type_as_text)); \
54 DBG_RETURN(FAIL);\
55 } \
56 MYSQLND_INC_CONN_STATISTIC_W_VALUE2(conn->stats, packet_type_to_statistic_byte_count[packet_type], \
57 MYSQLND_HEADER_SIZE + (packet)->header.size, \
58 packet_type_to_statistic_packet_count[packet_type], \
59 1); \
60 }
61
62
63 #define BAIL_IF_NO_MORE_DATA \
64 if ((size_t)(p - begin) > packet->header.size) { \
65 php_error_docref(NULL, E_WARNING, "Premature end of data (mysqlnd_wireprotocol.c:%u)", __LINE__); \
66 goto premature_end; \
67 } \
68
69
70 static const char *unknown_sqlstate= "HY000";
71 const char * const mysqlnd_empty_string = "";
72
73 /* Used in mysqlnd_debug.c */
74 const char mysqlnd_read_header_name[] = "mysqlnd_read_header";
75 const char mysqlnd_read_body_name[] = "mysqlnd_read_body";
76
77 #define ERROR_MARKER 0xFF
78 #define EODATA_MARKER 0xFE
79
80 /* {{{ mysqlnd_command_to_text
81 */
82 const char * const mysqlnd_command_to_text[COM_END] =
83 {
84 "SLEEP", "QUIT", "INIT_DB", "QUERY", "FIELD_LIST",
85 "CREATE_DB", "DROP_DB", "REFRESH", "SHUTDOWN", "STATISTICS",
86 "PROCESS_INFO", "CONNECT", "PROCESS_KILL", "DEBUG", "PING",
87 "TIME", "DELAYED_INSERT", "CHANGE_USER", "BINLOG_DUMP",
88 "TABLE_DUMP", "CONNECT_OUT", "REGISTER_SLAVE",
89 "STMT_PREPARE", "STMT_EXECUTE", "STMT_SEND_LONG_DATA", "STMT_CLOSE",
90 "STMT_RESET", "SET_OPTION", "STMT_FETCH", "DAEMON", "BINLOG_DUMP_GTID",
91 "RESET_CONNECTION"
92 };
93 /* }}} */
94
95
96
97 static enum_mysqlnd_collected_stats packet_type_to_statistic_byte_count[PROT_LAST] =
98 {
99 STAT_LAST,
100 STAT_LAST,
101 STAT_BYTES_RECEIVED_OK,
102 STAT_BYTES_RECEIVED_EOF,
103 STAT_LAST,
104 STAT_BYTES_RECEIVED_RSET_HEADER,
105 STAT_BYTES_RECEIVED_RSET_FIELD_META,
106 STAT_BYTES_RECEIVED_RSET_ROW,
107 STAT_BYTES_RECEIVED_PREPARE_RESPONSE,
108 STAT_BYTES_RECEIVED_CHANGE_USER,
109 };
110
111 static enum_mysqlnd_collected_stats packet_type_to_statistic_packet_count[PROT_LAST] =
112 {
113 STAT_LAST,
114 STAT_LAST,
115 STAT_PACKETS_RECEIVED_OK,
116 STAT_PACKETS_RECEIVED_EOF,
117 STAT_LAST,
118 STAT_PACKETS_RECEIVED_RSET_HEADER,
119 STAT_PACKETS_RECEIVED_RSET_FIELD_META,
120 STAT_PACKETS_RECEIVED_RSET_ROW,
121 STAT_PACKETS_RECEIVED_PREPARE_RESPONSE,
122 STAT_PACKETS_RECEIVED_CHANGE_USER,
123 };
124
125
126 /* {{{ php_mysqlnd_net_field_length
127 Get next field's length */
128 zend_ulong
php_mysqlnd_net_field_length(zend_uchar ** packet)129 php_mysqlnd_net_field_length(zend_uchar **packet)
130 {
131 register zend_uchar *p= (zend_uchar *)*packet;
132
133 if (*p < 251) {
134 (*packet)++;
135 return (zend_ulong) *p;
136 }
137
138 switch (*p) {
139 case 251:
140 (*packet)++;
141 return MYSQLND_NULL_LENGTH;
142 case 252:
143 (*packet) += 3;
144 return (zend_ulong) uint2korr(p+1);
145 case 253:
146 (*packet) += 4;
147 return (zend_ulong) uint3korr(p+1);
148 default:
149 (*packet) += 9;
150 return (zend_ulong) uint4korr(p+1);
151 }
152 }
153 /* }}} */
154
155
156 /* {{{ php_mysqlnd_net_field_length_ll
157 Get next field's length */
158 uint64_t
php_mysqlnd_net_field_length_ll(zend_uchar ** packet)159 php_mysqlnd_net_field_length_ll(zend_uchar **packet)
160 {
161 register zend_uchar *p = (zend_uchar *)*packet;
162
163 if (*p < 251) {
164 (*packet)++;
165 return (uint64_t) *p;
166 }
167
168 switch (*p) {
169 case 251:
170 (*packet)++;
171 return (uint64_t) MYSQLND_NULL_LENGTH;
172 case 252:
173 (*packet) += 3;
174 return (uint64_t) uint2korr(p + 1);
175 case 253:
176 (*packet) += 4;
177 return (uint64_t) uint3korr(p + 1);
178 default:
179 (*packet) += 9;
180 return (uint64_t) uint8korr(p + 1);
181 }
182 }
183 /* }}} */
184
185
186 /* {{{ php_mysqlnd_net_store_length */
187 zend_uchar *
php_mysqlnd_net_store_length(zend_uchar * packet,uint64_t length)188 php_mysqlnd_net_store_length(zend_uchar *packet, uint64_t length)
189 {
190 if (length < (uint64_t) L64(251)) {
191 *packet = (zend_uchar) length;
192 return packet + 1;
193 }
194
195 if (length < (uint64_t) L64(65536)) {
196 *packet++ = 252;
197 int2store(packet,(unsigned int) length);
198 return packet + 2;
199 }
200
201 if (length < (uint64_t) L64(16777216)) {
202 *packet++ = 253;
203 int3store(packet,(zend_ulong) length);
204 return packet + 3;
205 }
206 *packet++ = 254;
207 int8store(packet, length);
208 return packet + 8;
209 }
210 /* }}} */
211
212
213 /* {{{ php_mysqlnd_net_store_length_size */
214 size_t
php_mysqlnd_net_store_length_size(uint64_t length)215 php_mysqlnd_net_store_length_size(uint64_t length)
216 {
217 if (length < (uint64_t) L64(251)) {
218 return 1;
219 }
220 if (length < (uint64_t) L64(65536)) {
221 return 3;
222 }
223 if (length < (uint64_t) L64(16777216)) {
224 return 4;
225 }
226 return 9;
227 }
228 /* }}} */
229
230
231 /* {{{ php_mysqlnd_read_error_from_line */
232 static enum_func_status
php_mysqlnd_read_error_from_line(zend_uchar * buf,size_t buf_len,char * error,int error_buf_len,unsigned int * error_no,char * sqlstate)233 php_mysqlnd_read_error_from_line(zend_uchar *buf, size_t buf_len,
234 char *error, int error_buf_len,
235 unsigned int *error_no, char *sqlstate)
236 {
237 zend_uchar *p = buf;
238 int error_msg_len= 0;
239
240 DBG_ENTER("php_mysqlnd_read_error_from_line");
241
242 *error_no = CR_UNKNOWN_ERROR;
243 memcpy(sqlstate, unknown_sqlstate, MYSQLND_SQLSTATE_LENGTH);
244
245 if (buf_len > 2) {
246 *error_no = uint2korr(p);
247 p+= 2;
248 /*
249 sqlstate is following. No need to check for buf_left_len as we checked > 2 above,
250 if it was >=2 then we would need a check
251 */
252 if (*p == '#') {
253 ++p;
254 if ((buf_len - (p - buf)) >= MYSQLND_SQLSTATE_LENGTH) {
255 memcpy(sqlstate, p, MYSQLND_SQLSTATE_LENGTH);
256 p+= MYSQLND_SQLSTATE_LENGTH;
257 } else {
258 goto end;
259 }
260 }
261 if ((buf_len - (p - buf)) > 0) {
262 error_msg_len = MIN((int)((buf_len - (p - buf))), (int) (error_buf_len - 1));
263 memcpy(error, p, error_msg_len);
264 }
265 }
266 end:
267 sqlstate[MYSQLND_SQLSTATE_LENGTH] = '\0';
268 error[error_msg_len]= '\0';
269
270 DBG_RETURN(FAIL);
271 }
272 /* }}} */
273
274
275 /* {{{ mysqlnd_read_header */
276 static enum_func_status
mysqlnd_read_header(MYSQLND_NET * net,MYSQLND_PACKET_HEADER * header,MYSQLND_STATS * conn_stats,MYSQLND_ERROR_INFO * error_info)277 mysqlnd_read_header(MYSQLND_NET * net, MYSQLND_PACKET_HEADER * header,
278 MYSQLND_STATS * conn_stats, MYSQLND_ERROR_INFO * error_info)
279 {
280 zend_uchar buffer[MYSQLND_HEADER_SIZE];
281
282 DBG_ENTER(mysqlnd_read_header_name);
283 DBG_INF_FMT("compressed=%u", net->data->compressed);
284 if (FAIL == net->data->m.receive_ex(net, buffer, MYSQLND_HEADER_SIZE, conn_stats, error_info)) {
285 DBG_RETURN(FAIL);
286 }
287
288 header->size = uint3korr(buffer);
289 header->packet_no = uint1korr(buffer + 3);
290
291 #ifdef MYSQLND_DUMP_HEADER_N_BODY
292 DBG_INF_FMT("HEADER: prot_packet_no=%u size=%3u", header->packet_no, header->size);
293 #endif
294 MYSQLND_INC_CONN_STATISTIC_W_VALUE2(conn_stats,
295 STAT_PROTOCOL_OVERHEAD_IN, MYSQLND_HEADER_SIZE,
296 STAT_PACKETS_RECEIVED, 1);
297
298 if (net->data->compressed || net->packet_no == header->packet_no) {
299 /*
300 Have to increase the number, so we can send correct number back. It will
301 round at 255 as this is unsigned char. The server needs this for simple
302 flow control checking.
303 */
304 net->packet_no++;
305 DBG_RETURN(PASS);
306 }
307
308 DBG_ERR_FMT("Logical link: packets out of order. Expected %u received %u. Packet size="MYSQLND_SZ_T_SPEC,
309 net->packet_no, header->packet_no, header->size);
310
311 php_error(E_WARNING, "Packets out of order. Expected %u received %u. Packet size="MYSQLND_SZ_T_SPEC,
312 net->packet_no, header->packet_no, header->size);
313 DBG_RETURN(FAIL);
314 }
315 /* }}} */
316
317
318 /* {{{ php_mysqlnd_greet_read */
319 static enum_func_status
php_mysqlnd_greet_read(void * _packet,MYSQLND_CONN_DATA * conn)320 php_mysqlnd_greet_read(void * _packet, MYSQLND_CONN_DATA * conn)
321 {
322 zend_uchar buf[2048];
323 zend_uchar *p = buf;
324 zend_uchar *begin = buf;
325 zend_uchar *pad_start = NULL;
326 MYSQLND_PACKET_GREET *packet= (MYSQLND_PACKET_GREET *) _packet;
327
328 DBG_ENTER("php_mysqlnd_greet_read");
329
330 PACKET_READ_HEADER_AND_BODY(packet, conn, buf, sizeof(buf), "greeting", PROT_GREET_PACKET);
331 BAIL_IF_NO_MORE_DATA;
332
333 packet->auth_plugin_data = packet->intern_auth_plugin_data;
334 packet->auth_plugin_data_len = sizeof(packet->intern_auth_plugin_data);
335
336 if (packet->header.size < sizeof(buf)) {
337 /*
338 Null-terminate the string, so strdup can work even if the packets have a string at the end,
339 which is not ASCIIZ
340 */
341 buf[packet->header.size] = '\0';
342 }
343
344 packet->protocol_version = uint1korr(p);
345 p++;
346 BAIL_IF_NO_MORE_DATA;
347
348 if (ERROR_MARKER == packet->protocol_version) {
349 php_mysqlnd_read_error_from_line(p, packet->header.size - 1,
350 packet->error, sizeof(packet->error),
351 &packet->error_no, packet->sqlstate
352 );
353 /*
354 The server doesn't send sqlstate in the greet packet.
355 It's a bug#26426 , so we have to set it correctly ourselves.
356 It's probably "Too many connections, which has SQL state 08004".
357 */
358 if (packet->error_no == 1040) {
359 memcpy(packet->sqlstate, "08004", MYSQLND_SQLSTATE_LENGTH);
360 }
361 DBG_RETURN(PASS);
362 }
363
364 packet->server_version = estrdup((char *)p);
365 p+= strlen(packet->server_version) + 1; /* eat the '\0' */
366 BAIL_IF_NO_MORE_DATA;
367
368 packet->thread_id = uint4korr(p);
369 p+=4;
370 BAIL_IF_NO_MORE_DATA;
371
372 memcpy(packet->auth_plugin_data, p, SCRAMBLE_LENGTH_323);
373 p+= SCRAMBLE_LENGTH_323;
374 BAIL_IF_NO_MORE_DATA;
375
376 /* pad1 */
377 p++;
378 BAIL_IF_NO_MORE_DATA;
379
380 packet->server_capabilities = uint2korr(p);
381 p+= 2;
382 BAIL_IF_NO_MORE_DATA;
383
384 packet->charset_no = uint1korr(p);
385 p++;
386 BAIL_IF_NO_MORE_DATA;
387
388 packet->server_status = uint2korr(p);
389 p+= 2;
390 BAIL_IF_NO_MORE_DATA;
391
392 /* pad2 */
393 pad_start = p;
394 p+= 13;
395 BAIL_IF_NO_MORE_DATA;
396
397 if ((size_t) (p - buf) < packet->header.size) {
398 /* auth_plugin_data is split into two parts */
399 memcpy(packet->auth_plugin_data + SCRAMBLE_LENGTH_323, p, SCRAMBLE_LENGTH - SCRAMBLE_LENGTH_323);
400 p+= SCRAMBLE_LENGTH - SCRAMBLE_LENGTH_323;
401 p++; /* 0x0 at the end of the scramble and thus last byte in the packet in 5.1 and previous */
402 } else {
403 packet->pre41 = TRUE;
404 }
405
406 /* Is this a 5.5+ server ? */
407 if ((size_t) (p - buf) < packet->header.size) {
408 /* backtrack one byte, the 0x0 at the end of the scramble in 5.1 and previous */
409 p--;
410
411 /* Additional 16 bits for server capabilities */
412 packet->server_capabilities |= uint2korr(pad_start) << 16;
413 /* And a length of the server scramble in one byte */
414 packet->auth_plugin_data_len = uint1korr(pad_start + 2);
415 if (packet->auth_plugin_data_len > SCRAMBLE_LENGTH) {
416 /* more data*/
417 zend_uchar * new_auth_plugin_data = emalloc(packet->auth_plugin_data_len);
418 if (!new_auth_plugin_data) {
419 goto premature_end;
420 }
421 /* copy what we already have */
422 memcpy(new_auth_plugin_data, packet->auth_plugin_data, SCRAMBLE_LENGTH);
423 /* add additional scramble data 5.5+ sent us */
424 memcpy(new_auth_plugin_data + SCRAMBLE_LENGTH, p, packet->auth_plugin_data_len - SCRAMBLE_LENGTH);
425 p+= (packet->auth_plugin_data_len - SCRAMBLE_LENGTH);
426 packet->auth_plugin_data = new_auth_plugin_data;
427 }
428 }
429
430 if (packet->server_capabilities & CLIENT_PLUGIN_AUTH) {
431 BAIL_IF_NO_MORE_DATA;
432 /* The server is 5.5.x and supports authentication plugins */
433 packet->auth_protocol = estrdup((char *)p);
434 p+= strlen(packet->auth_protocol) + 1; /* eat the '\0' */
435 }
436
437 DBG_INF_FMT("proto=%u server=%s thread_id=%u",
438 packet->protocol_version, packet->server_version, packet->thread_id);
439
440 DBG_INF_FMT("server_capabilities=%u charset_no=%u server_status=%i auth_protocol=%s scramble_length=%u",
441 packet->server_capabilities, packet->charset_no, packet->server_status,
442 packet->auth_protocol? packet->auth_protocol:"n/a", packet->auth_plugin_data_len);
443
444 DBG_RETURN(PASS);
445 premature_end:
446 DBG_ERR_FMT("GREET packet %d bytes shorter than expected", p - begin - packet->header.size);
447 php_error_docref(NULL, E_WARNING, "GREET packet "MYSQLND_SZ_T_SPEC" bytes shorter than expected",
448 p - begin - packet->header.size);
449 DBG_RETURN(FAIL);
450 }
451 /* }}} */
452
453
454 /* {{{ php_mysqlnd_greet_free_mem */
455 static
php_mysqlnd_greet_free_mem(void * _packet,zend_bool stack_allocation)456 void php_mysqlnd_greet_free_mem(void * _packet, zend_bool stack_allocation)
457 {
458 MYSQLND_PACKET_GREET *p= (MYSQLND_PACKET_GREET *) _packet;
459 if (p->server_version) {
460 efree(p->server_version);
461 p->server_version = NULL;
462 }
463 if (p->auth_plugin_data && p->auth_plugin_data != p->intern_auth_plugin_data) {
464 efree(p->auth_plugin_data);
465 p->auth_plugin_data = NULL;
466 }
467 if (p->auth_protocol) {
468 efree(p->auth_protocol);
469 p->auth_protocol = NULL;
470 }
471 if (!stack_allocation) {
472 mnd_pefree(p, p->header.persistent);
473 }
474 }
475 /* }}} */
476
477
478 #define AUTH_WRITE_BUFFER_LEN (MYSQLND_HEADER_SIZE + MYSQLND_MAX_ALLOWED_USER_LEN + SCRAMBLE_LENGTH + MYSQLND_MAX_ALLOWED_DB_LEN + 1 + 4096)
479
480 /* {{{ php_mysqlnd_auth_write */
481 static
php_mysqlnd_auth_write(void * _packet,MYSQLND_CONN_DATA * conn)482 size_t php_mysqlnd_auth_write(void * _packet, MYSQLND_CONN_DATA * conn)
483 {
484 zend_uchar buffer[AUTH_WRITE_BUFFER_LEN];
485 zend_uchar *p = buffer + MYSQLND_HEADER_SIZE; /* start after the header */
486 int len;
487 MYSQLND_PACKET_AUTH * packet= (MYSQLND_PACKET_AUTH *) _packet;
488
489 DBG_ENTER("php_mysqlnd_auth_write");
490
491 if (!packet->is_change_user_packet) {
492 int4store(p, packet->client_flags);
493 p+= 4;
494
495 int4store(p, packet->max_packet_size);
496 p+= 4;
497
498 int1store(p, packet->charset_no);
499 p++;
500
501 memset(p, 0, 23); /* filler */
502 p+= 23;
503 }
504
505 if (packet->send_auth_data || packet->is_change_user_packet) {
506 len = MIN(strlen(packet->user), MYSQLND_MAX_ALLOWED_USER_LEN);
507 memcpy(p, packet->user, len);
508 p+= len;
509 *p++ = '\0';
510
511 /* defensive coding */
512 if (packet->auth_data == NULL) {
513 packet->auth_data_len = 0;
514 }
515 if (packet->auth_data_len > 0xFF) {
516 const char * const msg = "Authentication data too long. "
517 "Won't fit into the buffer and will be truncated. Authentication will thus fail";
518 SET_CLIENT_ERROR(*conn->error_info, CR_UNKNOWN_ERROR, UNKNOWN_SQLSTATE, msg);
519 php_error_docref(NULL, E_WARNING, "%s", msg);
520 DBG_RETURN(0);
521 }
522
523 int1store(p, packet->auth_data_len);
524 ++p;
525 /*!!!!! is the buffer big enough ??? */
526 if (sizeof(buffer) < (packet->auth_data_len + (p - buffer))) {
527 DBG_ERR("the stack buffer was not enough!!");
528 DBG_RETURN(0);
529 }
530 if (packet->auth_data_len) {
531 memcpy(p, packet->auth_data, packet->auth_data_len);
532 p+= packet->auth_data_len;
533 }
534
535 if (packet->db) {
536 /* CLIENT_CONNECT_WITH_DB should have been set */
537 size_t real_db_len = MIN(MYSQLND_MAX_ALLOWED_DB_LEN, packet->db_len);
538 memcpy(p, packet->db, real_db_len);
539 p+= real_db_len;
540 *p++= '\0';
541 } else if (packet->is_change_user_packet) {
542 *p++= '\0';
543 }
544 /* no \0 for no DB */
545
546 if (packet->is_change_user_packet) {
547 if (packet->charset_no) {
548 int2store(p, packet->charset_no);
549 p+= 2;
550 }
551 }
552
553 if (packet->auth_plugin_name) {
554 size_t len = MIN(strlen(packet->auth_plugin_name), sizeof(buffer) - (p - buffer) - 1);
555 memcpy(p, packet->auth_plugin_name, len);
556 p+= len;
557 *p++= '\0';
558 }
559
560 if (packet->connect_attr && zend_hash_num_elements(packet->connect_attr)) {
561 size_t ca_payload_len = 0;
562 #ifdef OLD_CODE
563 HashPosition pos_value;
564 const char ** entry_value;
565 zend_hash_internal_pointer_reset_ex(packet->connect_attr, &pos_value);
566 while (SUCCESS == zend_hash_get_current_data_ex(packet->connect_attr, (void **)&entry_value, &pos_value)) {
567 char *s_key;
568 unsigned int s_len;
569 zend_ulong num_key;
570 size_t value_len = strlen(*entry_value);
571
572 if (HASH_KEY_IS_STRING == zend_hash_get_current_key_ex(packet->connect_attr, &s_key, &s_len, &num_key, &pos_value)) {
573 ca_payload_len += php_mysqlnd_net_store_length_size(s_len);
574 ca_payload_len += s_len;
575 ca_payload_len += php_mysqlnd_net_store_length_size(value_len);
576 ca_payload_len += value_len;
577 }
578 zend_hash_move_forward_ex(conn->options->connect_attr, &pos_value);
579 }
580 #else
581
582 {
583 zend_string * key;
584 zval * entry_value;
585 ZEND_HASH_FOREACH_STR_KEY_VAL(packet->connect_attr, key, entry_value) {
586 if (key) { /* HASH_KEY_IS_STRING */
587 size_t value_len = Z_STRLEN_P(entry_value);
588
589 ca_payload_len += php_mysqlnd_net_store_length_size(ZSTR_LEN(key));
590 ca_payload_len += ZSTR_LEN(key);
591 ca_payload_len += php_mysqlnd_net_store_length_size(value_len);
592 ca_payload_len += value_len;
593 }
594 } ZEND_HASH_FOREACH_END();
595 }
596 #endif
597 if (sizeof(buffer) >= (ca_payload_len + php_mysqlnd_net_store_length_size(ca_payload_len) + (p - buffer))) {
598 p = php_mysqlnd_net_store_length(p, ca_payload_len);
599
600 #ifdef OLD_CODE
601 zend_hash_internal_pointer_reset_ex(packet->connect_attr, &pos_value);
602 while (SUCCESS == zend_hash_get_current_data_ex(packet->connect_attr, (void **)&entry_value, &pos_value)) {
603 char *s_key;
604 unsigned int s_len;
605 zend_ulong num_key;
606 size_t value_len = strlen(*entry_value);
607 if (HASH_KEY_IS_STRING == zend_hash_get_current_key_ex(packet->connect_attr, &s_key, &s_len, &num_key, &pos_value)) {
608 /* copy key */
609 p = php_mysqlnd_net_store_length(p, s_len);
610 memcpy(p, s_key, s_len);
611 p+= s_len;
612 /* copy value */
613 p = php_mysqlnd_net_store_length(p, value_len);
614 memcpy(p, *entry_value, value_len);
615 p+= value_len;
616 }
617 zend_hash_move_forward_ex(conn->options->connect_attr, &pos_value);
618 }
619 #else
620 {
621 zend_string * key;
622 zval * entry_value;
623 ZEND_HASH_FOREACH_STR_KEY_VAL(packet->connect_attr, key, entry_value) {
624 if (key) { /* HASH_KEY_IS_STRING */
625 size_t value_len = Z_STRLEN_P(entry_value);
626
627 /* copy key */
628 p = php_mysqlnd_net_store_length(p, ZSTR_LEN(key));
629 memcpy(p, ZSTR_VAL(key), ZSTR_LEN(key));
630 p+= ZSTR_LEN(key);
631 /* copy value */
632 p = php_mysqlnd_net_store_length(p, value_len);
633 memcpy(p, Z_STRVAL_P(entry_value), value_len);
634 p+= value_len;
635 }
636 } ZEND_HASH_FOREACH_END();
637 }
638 #endif
639 } else {
640 /* cannot put the data - skip */
641 }
642 }
643 }
644 if (packet->is_change_user_packet) {
645 if (PASS != conn->m->simple_command(conn, COM_CHANGE_USER, buffer + MYSQLND_HEADER_SIZE, p - buffer - MYSQLND_HEADER_SIZE,
646 PROT_LAST /* the caller will handle the OK packet */,
647 packet->silent, TRUE)) {
648 DBG_RETURN(0);
649 }
650 DBG_RETURN(p - buffer - MYSQLND_HEADER_SIZE);
651 } else {
652 size_t sent = conn->net->data->m.send_ex(conn->net, buffer, p - buffer - MYSQLND_HEADER_SIZE, conn->stats, conn->error_info);
653 if (!sent) {
654 CONN_SET_STATE(conn, CONN_QUIT_SENT);
655 }
656 DBG_RETURN(sent);
657 }
658 }
659 /* }}} */
660
661
662 /* {{{ php_mysqlnd_auth_free_mem */
663 static
php_mysqlnd_auth_free_mem(void * _packet,zend_bool stack_allocation)664 void php_mysqlnd_auth_free_mem(void * _packet, zend_bool stack_allocation)
665 {
666 if (!stack_allocation) {
667 MYSQLND_PACKET_AUTH * p = (MYSQLND_PACKET_AUTH *) _packet;
668 mnd_pefree(p, p->header.persistent);
669 }
670 }
671 /* }}} */
672
673
674 #define AUTH_RESP_BUFFER_SIZE 2048
675
676 /* {{{ php_mysqlnd_auth_response_read */
677 static enum_func_status
php_mysqlnd_auth_response_read(void * _packet,MYSQLND_CONN_DATA * conn)678 php_mysqlnd_auth_response_read(void * _packet, MYSQLND_CONN_DATA * conn)
679 {
680 zend_uchar local_buf[AUTH_RESP_BUFFER_SIZE];
681 size_t buf_len = conn->net->cmd_buffer.buffer? conn->net->cmd_buffer.length: AUTH_RESP_BUFFER_SIZE;
682 zend_uchar *buf = conn->net->cmd_buffer.buffer? (zend_uchar *) conn->net->cmd_buffer.buffer : local_buf;
683 zend_uchar *p = buf;
684 zend_uchar *begin = buf;
685 zend_ulong i;
686 register MYSQLND_PACKET_AUTH_RESPONSE * packet= (MYSQLND_PACKET_AUTH_RESPONSE *) _packet;
687
688 DBG_ENTER("php_mysqlnd_auth_response_read");
689
690 /* leave space for terminating safety \0 */
691 buf_len--;
692 PACKET_READ_HEADER_AND_BODY(packet, conn, buf, buf_len, "OK", PROT_OK_PACKET);
693 BAIL_IF_NO_MORE_DATA;
694
695 /*
696 zero-terminate the buffer for safety. We are sure there is place for the \0
697 because buf_len is -1 the size of the buffer pointed
698 */
699 buf[packet->header.size] = '\0';
700
701 /* Should be always 0x0 or ERROR_MARKER for error */
702 packet->response_code = uint1korr(p);
703 p++;
704 BAIL_IF_NO_MORE_DATA;
705
706 if (ERROR_MARKER == packet->response_code) {
707 php_mysqlnd_read_error_from_line(p, packet->header.size - 1,
708 packet->error, sizeof(packet->error),
709 &packet->error_no, packet->sqlstate
710 );
711 DBG_RETURN(PASS);
712 }
713 if (0xFE == packet->response_code) {
714 /* Authentication Switch Response */
715 if (packet->header.size > (size_t) (p - buf)) {
716 packet->new_auth_protocol = mnd_pestrdup((char *)p, FALSE);
717 packet->new_auth_protocol_len = strlen(packet->new_auth_protocol);
718 p+= packet->new_auth_protocol_len + 1; /* +1 for the \0 */
719
720 packet->new_auth_protocol_data_len = packet->header.size - (size_t) (p - buf);
721 if (packet->new_auth_protocol_data_len) {
722 packet->new_auth_protocol_data = mnd_emalloc(packet->new_auth_protocol_data_len);
723 memcpy(packet->new_auth_protocol_data, p, packet->new_auth_protocol_data_len);
724 }
725 DBG_INF_FMT("The server requested switching auth plugin to : %s", packet->new_auth_protocol);
726 DBG_INF_FMT("Server salt : [%d][%.*s]", packet->new_auth_protocol_data_len, packet->new_auth_protocol_data_len, packet->new_auth_protocol_data);
727 }
728 } else {
729 /* Everything was fine! */
730 packet->affected_rows = php_mysqlnd_net_field_length_ll(&p);
731 BAIL_IF_NO_MORE_DATA;
732
733 packet->last_insert_id = php_mysqlnd_net_field_length_ll(&p);
734 BAIL_IF_NO_MORE_DATA;
735
736 packet->server_status = uint2korr(p);
737 p+= 2;
738 BAIL_IF_NO_MORE_DATA;
739
740 packet->warning_count = uint2korr(p);
741 p+= 2;
742 BAIL_IF_NO_MORE_DATA;
743
744 /* There is a message */
745 if (packet->header.size > (size_t) (p - buf) && (i = php_mysqlnd_net_field_length(&p))) {
746 packet->message_len = MIN(i, buf_len - (p - begin));
747 packet->message = mnd_pestrndup((char *)p, packet->message_len, FALSE);
748 } else {
749 packet->message = NULL;
750 packet->message_len = 0;
751 }
752
753 DBG_INF_FMT("OK packet: aff_rows=%lld last_ins_id=%pd server_status=%u warnings=%u",
754 packet->affected_rows, packet->last_insert_id, packet->server_status,
755 packet->warning_count);
756 }
757
758 DBG_RETURN(PASS);
759 premature_end:
760 DBG_ERR_FMT("OK packet %d bytes shorter than expected", p - begin - packet->header.size);
761 php_error_docref(NULL, E_WARNING, "AUTH_RESPONSE packet "MYSQLND_SZ_T_SPEC" bytes shorter than expected",
762 p - begin - packet->header.size);
763 DBG_RETURN(FAIL);
764 }
765 /* }}} */
766
767
768 /* {{{ php_mysqlnd_auth_response_free_mem */
769 static void
php_mysqlnd_auth_response_free_mem(void * _packet,zend_bool stack_allocation)770 php_mysqlnd_auth_response_free_mem(void * _packet, zend_bool stack_allocation)
771 {
772 MYSQLND_PACKET_AUTH_RESPONSE * p = (MYSQLND_PACKET_AUTH_RESPONSE *) _packet;
773 if (p->message) {
774 mnd_efree(p->message);
775 p->message = NULL;
776 }
777 if (p->new_auth_protocol) {
778 mnd_efree(p->new_auth_protocol);
779 p->new_auth_protocol = NULL;
780 }
781 p->new_auth_protocol_len = 0;
782
783 if (p->new_auth_protocol_data) {
784 mnd_efree(p->new_auth_protocol_data);
785 p->new_auth_protocol_data = NULL;
786 }
787 p->new_auth_protocol_data_len = 0;
788
789 if (!stack_allocation) {
790 mnd_pefree(p, p->header.persistent);
791 }
792 }
793 /* }}} */
794
795
796 /* {{{ php_mysqlnd_change_auth_response_write */
797 static size_t
php_mysqlnd_change_auth_response_write(void * _packet,MYSQLND_CONN_DATA * conn)798 php_mysqlnd_change_auth_response_write(void * _packet, MYSQLND_CONN_DATA * conn)
799 {
800 MYSQLND_PACKET_CHANGE_AUTH_RESPONSE *packet= (MYSQLND_PACKET_CHANGE_AUTH_RESPONSE *) _packet;
801 zend_uchar * buffer = conn->net->cmd_buffer.length >= packet->auth_data_len? conn->net->cmd_buffer.buffer : mnd_emalloc(packet->auth_data_len);
802 zend_uchar *p = buffer + MYSQLND_HEADER_SIZE; /* start after the header */
803
804 DBG_ENTER("php_mysqlnd_change_auth_response_write");
805
806 if (packet->auth_data_len) {
807 memcpy(p, packet->auth_data, packet->auth_data_len);
808 p+= packet->auth_data_len;
809 }
810
811 {
812 size_t sent = conn->net->data->m.send_ex(conn->net, buffer, p - buffer - MYSQLND_HEADER_SIZE, conn->stats, conn->error_info);
813 if (buffer != conn->net->cmd_buffer.buffer) {
814 mnd_efree(buffer);
815 }
816 if (!sent) {
817 CONN_SET_STATE(conn, CONN_QUIT_SENT);
818 }
819 DBG_RETURN(sent);
820 }
821 }
822 /* }}} */
823
824
825 /* {{{ php_mysqlnd_change_auth_response_free_mem */
826 static void
php_mysqlnd_change_auth_response_free_mem(void * _packet,zend_bool stack_allocation)827 php_mysqlnd_change_auth_response_free_mem(void * _packet, zend_bool stack_allocation)
828 {
829 if (!stack_allocation) {
830 MYSQLND_PACKET_CHANGE_AUTH_RESPONSE * p = (MYSQLND_PACKET_CHANGE_AUTH_RESPONSE *) _packet;
831 mnd_pefree(p, p->header.persistent);
832 }
833 }
834 /* }}} */
835
836
837 #define OK_BUFFER_SIZE 2048
838
839 /* {{{ php_mysqlnd_ok_read */
840 static enum_func_status
php_mysqlnd_ok_read(void * _packet,MYSQLND_CONN_DATA * conn)841 php_mysqlnd_ok_read(void * _packet, MYSQLND_CONN_DATA * conn)
842 {
843 zend_uchar local_buf[OK_BUFFER_SIZE];
844 size_t buf_len = conn->net->cmd_buffer.buffer? conn->net->cmd_buffer.length : OK_BUFFER_SIZE;
845 zend_uchar *buf = conn->net->cmd_buffer.buffer? (zend_uchar *) conn->net->cmd_buffer.buffer : local_buf;
846 zend_uchar *p = buf;
847 zend_uchar *begin = buf;
848 zend_ulong i;
849 register MYSQLND_PACKET_OK *packet= (MYSQLND_PACKET_OK *) _packet;
850
851 DBG_ENTER("php_mysqlnd_ok_read");
852
853 PACKET_READ_HEADER_AND_BODY(packet, conn, buf, buf_len, "OK", PROT_OK_PACKET);
854 BAIL_IF_NO_MORE_DATA;
855
856 /* Should be always 0x0 or ERROR_MARKER for error */
857 packet->field_count = uint1korr(p);
858 p++;
859 BAIL_IF_NO_MORE_DATA;
860
861 if (ERROR_MARKER == packet->field_count) {
862 php_mysqlnd_read_error_from_line(p, packet->header.size - 1,
863 packet->error, sizeof(packet->error),
864 &packet->error_no, packet->sqlstate
865 );
866 DBG_INF_FMT("conn->server_status=%u", conn->upsert_status->server_status);
867 DBG_RETURN(PASS);
868 }
869 /* Everything was fine! */
870 packet->affected_rows = php_mysqlnd_net_field_length_ll(&p);
871 BAIL_IF_NO_MORE_DATA;
872
873 packet->last_insert_id = php_mysqlnd_net_field_length_ll(&p);
874 BAIL_IF_NO_MORE_DATA;
875
876 packet->server_status = uint2korr(p);
877 p+= 2;
878 BAIL_IF_NO_MORE_DATA;
879
880 packet->warning_count = uint2korr(p);
881 p+= 2;
882 BAIL_IF_NO_MORE_DATA;
883
884 /* There is a message */
885 if (packet->header.size > (size_t) (p - buf) && (i = php_mysqlnd_net_field_length(&p))) {
886 packet->message_len = MIN(i, buf_len - (p - begin));
887 packet->message = mnd_pestrndup((char *)p, packet->message_len, FALSE);
888 } else {
889 packet->message = NULL;
890 packet->message_len = 0;
891 }
892
893 DBG_INF_FMT("OK packet: aff_rows=%lld last_ins_id=%ld server_status=%u warnings=%u",
894 packet->affected_rows, packet->last_insert_id, packet->server_status,
895 packet->warning_count);
896
897 BAIL_IF_NO_MORE_DATA;
898
899 DBG_RETURN(PASS);
900 premature_end:
901 DBG_ERR_FMT("OK packet %d bytes shorter than expected", p - begin - packet->header.size);
902 php_error_docref(NULL, E_WARNING, "OK packet "MYSQLND_SZ_T_SPEC" bytes shorter than expected",
903 p - begin - packet->header.size);
904 DBG_RETURN(FAIL);
905 }
906 /* }}} */
907
908
909 /* {{{ php_mysqlnd_ok_free_mem */
910 static void
php_mysqlnd_ok_free_mem(void * _packet,zend_bool stack_allocation)911 php_mysqlnd_ok_free_mem(void * _packet, zend_bool stack_allocation)
912 {
913 MYSQLND_PACKET_OK *p= (MYSQLND_PACKET_OK *) _packet;
914 if (p->message) {
915 mnd_efree(p->message);
916 p->message = NULL;
917 }
918 if (!stack_allocation) {
919 mnd_pefree(p, p->header.persistent);
920 }
921 }
922 /* }}} */
923
924
925 /* {{{ php_mysqlnd_eof_read */
926 static enum_func_status
php_mysqlnd_eof_read(void * _packet,MYSQLND_CONN_DATA * conn)927 php_mysqlnd_eof_read(void * _packet, MYSQLND_CONN_DATA * conn)
928 {
929 /*
930 EOF packet is since 4.1 five bytes long,
931 but we can get also an error, make it bigger.
932
933 Error : error_code + '#' + sqlstate + MYSQLND_ERRMSG_SIZE
934 */
935 MYSQLND_PACKET_EOF *packet= (MYSQLND_PACKET_EOF *) _packet;
936 size_t buf_len = conn->net->cmd_buffer.length;
937 zend_uchar *buf = (zend_uchar *) conn->net->cmd_buffer.buffer;
938 zend_uchar *p = buf;
939 zend_uchar *begin = buf;
940
941 DBG_ENTER("php_mysqlnd_eof_read");
942
943 PACKET_READ_HEADER_AND_BODY(packet, conn, buf, buf_len, "EOF", PROT_EOF_PACKET);
944 BAIL_IF_NO_MORE_DATA;
945
946 /* Should be always EODATA_MARKER */
947 packet->field_count = uint1korr(p);
948 p++;
949 BAIL_IF_NO_MORE_DATA;
950
951 if (ERROR_MARKER == packet->field_count) {
952 php_mysqlnd_read_error_from_line(p, packet->header.size - 1,
953 packet->error, sizeof(packet->error),
954 &packet->error_no, packet->sqlstate
955 );
956 DBG_RETURN(PASS);
957 }
958
959 /*
960 4.1 sends 1 byte EOF packet after metadata of
961 PREPARE/EXECUTE but 5 bytes after the result. This is not
962 according to the Docs@Forge!!!
963 */
964 if (packet->header.size > 1) {
965 packet->warning_count = uint2korr(p);
966 p+= 2;
967 BAIL_IF_NO_MORE_DATA;
968
969 packet->server_status = uint2korr(p);
970 p+= 2;
971 BAIL_IF_NO_MORE_DATA;
972 } else {
973 packet->warning_count = 0;
974 packet->server_status = 0;
975 }
976
977 BAIL_IF_NO_MORE_DATA;
978
979 DBG_INF_FMT("EOF packet: fields=%u status=%u warnings=%u",
980 packet->field_count, packet->server_status, packet->warning_count);
981
982 DBG_RETURN(PASS);
983 premature_end:
984 DBG_ERR_FMT("EOF packet %d bytes shorter than expected", p - begin - packet->header.size);
985 php_error_docref(NULL, E_WARNING, "EOF packet "MYSQLND_SZ_T_SPEC" bytes shorter than expected",
986 p - begin - packet->header.size);
987 DBG_RETURN(FAIL);
988 }
989 /* }}} */
990
991
992 /* {{{ php_mysqlnd_eof_free_mem */
993 static
php_mysqlnd_eof_free_mem(void * _packet,zend_bool stack_allocation)994 void php_mysqlnd_eof_free_mem(void * _packet, zend_bool stack_allocation)
995 {
996 if (!stack_allocation) {
997 mnd_pefree(_packet, ((MYSQLND_PACKET_EOF *)_packet)->header.persistent);
998 }
999 }
1000 /* }}} */
1001
1002
1003 /* {{{ php_mysqlnd_cmd_write */
php_mysqlnd_cmd_write(void * _packet,MYSQLND_CONN_DATA * conn)1004 size_t php_mysqlnd_cmd_write(void * _packet, MYSQLND_CONN_DATA * conn)
1005 {
1006 /* Let's have some space, which we can use, if not enough, we will allocate new buffer */
1007 MYSQLND_PACKET_COMMAND * packet= (MYSQLND_PACKET_COMMAND *) _packet;
1008 MYSQLND_NET * net = conn->net;
1009 unsigned int error_reporting = EG(error_reporting);
1010 size_t sent = 0;
1011
1012 DBG_ENTER("php_mysqlnd_cmd_write");
1013 /*
1014 Reset packet_no, or we will get bad handshake!
1015 Every command starts a new TX and packet numbers are reset to 0.
1016 */
1017 net->packet_no = 0;
1018 net->compressed_envelope_packet_no = 0; /* this is for the response */
1019
1020 if (error_reporting) {
1021 EG(error_reporting) = 0;
1022 }
1023
1024 MYSQLND_INC_CONN_STATISTIC(conn->stats, STAT_PACKETS_SENT_CMD);
1025
1026 #ifdef MYSQLND_DO_WIRE_CHECK_BEFORE_COMMAND
1027 net->data->m.consume_uneaten_data(net, packet->command);
1028 #endif
1029
1030 if (!packet->argument || !packet->arg_len) {
1031 zend_uchar buffer[MYSQLND_HEADER_SIZE + 1];
1032
1033 int1store(buffer + MYSQLND_HEADER_SIZE, packet->command);
1034 sent = net->data->m.send_ex(net, buffer, 1, conn->stats, conn->error_info);
1035 } else {
1036 size_t tmp_len = packet->arg_len + 1 + MYSQLND_HEADER_SIZE;
1037 zend_uchar *tmp, *p;
1038 tmp = (tmp_len > net->cmd_buffer.length)? mnd_emalloc(tmp_len):net->cmd_buffer.buffer;
1039 if (!tmp) {
1040 goto end;
1041 }
1042 p = tmp + MYSQLND_HEADER_SIZE; /* skip the header */
1043
1044 int1store(p, packet->command);
1045 p++;
1046
1047 memcpy(p, packet->argument, packet->arg_len);
1048
1049 sent = net->data->m.send_ex(net, tmp, tmp_len - MYSQLND_HEADER_SIZE, conn->stats, conn->error_info);
1050 if (tmp != net->cmd_buffer.buffer) {
1051 MYSQLND_INC_CONN_STATISTIC(conn->stats, STAT_CMD_BUFFER_TOO_SMALL);
1052 mnd_efree(tmp);
1053 }
1054 }
1055 end:
1056 if (error_reporting) {
1057 /* restore error reporting */
1058 EG(error_reporting) = error_reporting;
1059 }
1060 if (!sent) {
1061 CONN_SET_STATE(conn, CONN_QUIT_SENT);
1062 }
1063 DBG_RETURN(sent);
1064 }
1065 /* }}} */
1066
1067
1068 /* {{{ php_mysqlnd_cmd_free_mem */
1069 static
php_mysqlnd_cmd_free_mem(void * _packet,zend_bool stack_allocation)1070 void php_mysqlnd_cmd_free_mem(void * _packet, zend_bool stack_allocation)
1071 {
1072 if (!stack_allocation) {
1073 MYSQLND_PACKET_COMMAND * p = (MYSQLND_PACKET_COMMAND *) _packet;
1074 mnd_pefree(p, p->header.persistent);
1075 }
1076 }
1077 /* }}} */
1078
1079
1080 /* {{{ php_mysqlnd_rset_header_read */
1081 static enum_func_status
php_mysqlnd_rset_header_read(void * _packet,MYSQLND_CONN_DATA * conn)1082 php_mysqlnd_rset_header_read(void * _packet, MYSQLND_CONN_DATA * conn)
1083 {
1084 enum_func_status ret = PASS;
1085 size_t buf_len = conn->net->cmd_buffer.length;
1086 zend_uchar *buf = (zend_uchar *) conn->net->cmd_buffer.buffer;
1087 zend_uchar *p = buf;
1088 zend_uchar *begin = buf;
1089 size_t len;
1090 MYSQLND_PACKET_RSET_HEADER *packet= (MYSQLND_PACKET_RSET_HEADER *) _packet;
1091
1092 DBG_ENTER("php_mysqlnd_rset_header_read");
1093
1094 PACKET_READ_HEADER_AND_BODY(packet, conn, buf, buf_len, "resultset header", PROT_RSET_HEADER_PACKET);
1095 BAIL_IF_NO_MORE_DATA;
1096
1097 /*
1098 Don't increment. First byte is ERROR_MARKER on error, but otherwise is starting byte
1099 of encoded sequence for length.
1100 */
1101 if (ERROR_MARKER == *p) {
1102 /* Error */
1103 p++;
1104 BAIL_IF_NO_MORE_DATA;
1105 php_mysqlnd_read_error_from_line(p, packet->header.size - 1,
1106 packet->error_info.error, sizeof(packet->error_info.error),
1107 &packet->error_info.error_no, packet->error_info.sqlstate
1108 );
1109 DBG_INF_FMT("conn->server_status=%u", conn->upsert_status->server_status);
1110 DBG_RETURN(PASS);
1111 }
1112
1113 packet->field_count = php_mysqlnd_net_field_length(&p);
1114 BAIL_IF_NO_MORE_DATA;
1115
1116 switch (packet->field_count) {
1117 case MYSQLND_NULL_LENGTH:
1118 DBG_INF("LOAD LOCAL");
1119 /*
1120 First byte in the packet is the field count.
1121 Thus, the name is size - 1. And we add 1 for a trailing \0.
1122 Because we have BAIL_IF_NO_MORE_DATA before the switch, we are guaranteed
1123 that packet->header.size is > 0. Which means that len can't underflow, that
1124 would lead to 0 byte allocation but 2^32 or 2^64 bytes copied.
1125 */
1126 len = packet->header.size - 1;
1127 packet->info_or_local_file = mnd_emalloc(len + 1);
1128 if (packet->info_or_local_file) {
1129 memcpy(packet->info_or_local_file, p, len);
1130 packet->info_or_local_file[len] = '\0';
1131 packet->info_or_local_file_len = len;
1132 } else {
1133 SET_OOM_ERROR(*conn->error_info);
1134 ret = FAIL;
1135 }
1136 break;
1137 case 0x00:
1138 DBG_INF("UPSERT");
1139 packet->affected_rows = php_mysqlnd_net_field_length_ll(&p);
1140 BAIL_IF_NO_MORE_DATA;
1141
1142 packet->last_insert_id = php_mysqlnd_net_field_length_ll(&p);
1143 BAIL_IF_NO_MORE_DATA;
1144
1145 packet->server_status = uint2korr(p);
1146 p+=2;
1147 BAIL_IF_NO_MORE_DATA;
1148
1149 packet->warning_count = uint2korr(p);
1150 p+=2;
1151 BAIL_IF_NO_MORE_DATA;
1152 /* Check for additional textual data */
1153 if (packet->header.size > (size_t) (p - buf) && (len = php_mysqlnd_net_field_length(&p))) {
1154 packet->info_or_local_file = mnd_emalloc(len + 1);
1155 if (packet->info_or_local_file) {
1156 memcpy(packet->info_or_local_file, p, len);
1157 packet->info_or_local_file[len] = '\0';
1158 packet->info_or_local_file_len = len;
1159 } else {
1160 SET_OOM_ERROR(*conn->error_info);
1161 ret = FAIL;
1162 }
1163 }
1164 DBG_INF_FMT("affected_rows=%llu last_insert_id=%llu server_status=%u warning_count=%u",
1165 packet->affected_rows, packet->last_insert_id,
1166 packet->server_status, packet->warning_count);
1167 break;
1168 default:
1169 DBG_INF("SELECT");
1170 /* Result set */
1171 break;
1172 }
1173 BAIL_IF_NO_MORE_DATA;
1174
1175 DBG_RETURN(ret);
1176 premature_end:
1177 DBG_ERR_FMT("RSET_HEADER packet %d bytes shorter than expected", p - begin - packet->header.size);
1178 php_error_docref(NULL, E_WARNING, "RSET_HEADER packet "MYSQLND_SZ_T_SPEC" bytes shorter than expected",
1179 p - begin - packet->header.size);
1180 DBG_RETURN(FAIL);
1181 }
1182 /* }}} */
1183
1184
1185 /* {{{ php_mysqlnd_rset_header_free_mem */
1186 static
php_mysqlnd_rset_header_free_mem(void * _packet,zend_bool stack_allocation)1187 void php_mysqlnd_rset_header_free_mem(void * _packet, zend_bool stack_allocation)
1188 {
1189 MYSQLND_PACKET_RSET_HEADER *p= (MYSQLND_PACKET_RSET_HEADER *) _packet;
1190 DBG_ENTER("php_mysqlnd_rset_header_free_mem");
1191 if (p->info_or_local_file) {
1192 mnd_efree(p->info_or_local_file);
1193 p->info_or_local_file = NULL;
1194 }
1195 if (!stack_allocation) {
1196 mnd_pefree(p, p->header.persistent);
1197 }
1198 DBG_VOID_RETURN;
1199 }
1200 /* }}} */
1201
1202 static size_t rset_field_offsets[] =
1203 {
1204 STRUCT_OFFSET(MYSQLND_FIELD, catalog),
1205 STRUCT_OFFSET(MYSQLND_FIELD, catalog_length),
1206 STRUCT_OFFSET(MYSQLND_FIELD, db),
1207 STRUCT_OFFSET(MYSQLND_FIELD, db_length),
1208 STRUCT_OFFSET(MYSQLND_FIELD, table),
1209 STRUCT_OFFSET(MYSQLND_FIELD, table_length),
1210 STRUCT_OFFSET(MYSQLND_FIELD, org_table),
1211 STRUCT_OFFSET(MYSQLND_FIELD, org_table_length),
1212 STRUCT_OFFSET(MYSQLND_FIELD, name),
1213 STRUCT_OFFSET(MYSQLND_FIELD, name_length),
1214 STRUCT_OFFSET(MYSQLND_FIELD, org_name),
1215 STRUCT_OFFSET(MYSQLND_FIELD, org_name_length),
1216 };
1217
1218
1219 /* {{{ php_mysqlnd_rset_field_read */
1220 static enum_func_status
php_mysqlnd_rset_field_read(void * _packet,MYSQLND_CONN_DATA * conn)1221 php_mysqlnd_rset_field_read(void * _packet, MYSQLND_CONN_DATA * conn)
1222 {
1223 /* Should be enough for the metadata of a single row */
1224 MYSQLND_PACKET_RES_FIELD *packet = (MYSQLND_PACKET_RES_FIELD *) _packet;
1225 size_t buf_len = conn->net->cmd_buffer.length, total_len = 0;
1226 zend_uchar *buf = (zend_uchar *) conn->net->cmd_buffer.buffer;
1227 zend_uchar *p = buf;
1228 zend_uchar *begin = buf;
1229 char *root_ptr;
1230 zend_ulong len;
1231 MYSQLND_FIELD *meta;
1232 unsigned int i, field_count = sizeof(rset_field_offsets)/sizeof(size_t);
1233
1234 DBG_ENTER("php_mysqlnd_rset_field_read");
1235
1236 PACKET_READ_HEADER_AND_BODY(packet, conn, buf, buf_len, "field", PROT_RSET_FLD_PACKET);
1237
1238 if (packet->skip_parsing) {
1239 DBG_RETURN(PASS);
1240 }
1241
1242 BAIL_IF_NO_MORE_DATA;
1243 if (ERROR_MARKER == *p) {
1244 /* Error */
1245 p++;
1246 BAIL_IF_NO_MORE_DATA;
1247 php_mysqlnd_read_error_from_line(p, packet->header.size - 1,
1248 packet->error_info.error, sizeof(packet->error_info.error),
1249 &packet->error_info.error_no, packet->error_info.sqlstate
1250 );
1251 DBG_ERR_FMT("Server error : (%u) %s", packet->error_info.error_no, packet->error_info.error);
1252 DBG_RETURN(PASS);
1253 } else if (EODATA_MARKER == *p && packet->header.size < 8) {
1254 /* Premature EOF. That should be COM_FIELD_LIST */
1255 DBG_INF("Premature EOF. That should be COM_FIELD_LIST");
1256 packet->stupid_list_fields_eof = TRUE;
1257 DBG_RETURN(PASS);
1258 }
1259
1260 meta = packet->metadata;
1261
1262 for (i = 0; i < field_count; i += 2) {
1263 len = php_mysqlnd_net_field_length(&p);
1264 BAIL_IF_NO_MORE_DATA;
1265 switch ((len)) {
1266 case 0:
1267 *(const char **)(((char*)meta) + rset_field_offsets[i]) = mysqlnd_empty_string;
1268 *(unsigned int *)(((char*)meta) + rset_field_offsets[i+1]) = 0;
1269 break;
1270 case MYSQLND_NULL_LENGTH:
1271 goto faulty_or_fake;
1272 default:
1273 *(const char **)(((char *)meta) + rset_field_offsets[i]) = (const char *)p;
1274 *(unsigned int *)(((char*)meta) + rset_field_offsets[i+1]) = len;
1275 p += len;
1276 total_len += len + 1;
1277 break;
1278 }
1279 BAIL_IF_NO_MORE_DATA;
1280 }
1281
1282 /* 1 byte length */
1283 if (12 != *p) {
1284 DBG_ERR_FMT("Protocol error. Server sent false length. Expected 12 got %d", (int) *p);
1285 php_error_docref(NULL, E_WARNING, "Protocol error. Server sent false length. Expected 12");
1286 }
1287
1288 p++;
1289 BAIL_IF_NO_MORE_DATA;
1290
1291 meta->charsetnr = uint2korr(p);
1292 p += 2;
1293 BAIL_IF_NO_MORE_DATA;
1294
1295 meta->length = uint4korr(p);
1296 p += 4;
1297 BAIL_IF_NO_MORE_DATA;
1298
1299 meta->type = uint1korr(p);
1300 p += 1;
1301 BAIL_IF_NO_MORE_DATA;
1302
1303 meta->flags = uint2korr(p);
1304 p += 2;
1305 BAIL_IF_NO_MORE_DATA;
1306
1307 meta->decimals = uint1korr(p);
1308 p += 1;
1309 BAIL_IF_NO_MORE_DATA;
1310
1311 /* 2 byte filler */
1312 p +=2;
1313 BAIL_IF_NO_MORE_DATA;
1314
1315 /* Should we set NUM_FLAG (libmysql does it) ? */
1316 if (
1317 (meta->type <= MYSQL_TYPE_INT24 &&
1318 (meta->type != MYSQL_TYPE_TIMESTAMP || meta->length == 14 || meta->length == 8)
1319 ) || meta->type == MYSQL_TYPE_YEAR)
1320 {
1321 meta->flags |= NUM_FLAG;
1322 }
1323
1324
1325 /*
1326 def could be empty, thus don't allocate on the root.
1327 NULL_LENGTH (0xFB) comes from COM_FIELD_LIST when the default value is NULL.
1328 Otherwise the string is length encoded.
1329 */
1330 if (packet->header.size > (size_t) (p - buf) &&
1331 (len = php_mysqlnd_net_field_length(&p)) &&
1332 len != MYSQLND_NULL_LENGTH)
1333 {
1334 BAIL_IF_NO_MORE_DATA;
1335 DBG_INF_FMT("Def found, length %lu, persistent=%u", len, packet->persistent_alloc);
1336 meta->def = mnd_pemalloc(len + 1, packet->persistent_alloc);
1337 if (!meta->def) {
1338 SET_OOM_ERROR(*conn->error_info);
1339 DBG_RETURN(FAIL);
1340 }
1341 memcpy(meta->def, p, len);
1342 meta->def[len] = '\0';
1343 meta->def_length = len;
1344 p += len;
1345 }
1346
1347 root_ptr = meta->root = mnd_pemalloc(total_len, packet->persistent_alloc);
1348 if (!root_ptr) {
1349 SET_OOM_ERROR(*conn->error_info);
1350 DBG_RETURN(FAIL);
1351 }
1352
1353 meta->root_len = total_len;
1354
1355 if (meta->name != mysqlnd_empty_string) {
1356 meta->sname = zend_string_init(meta->name, meta->name_length, packet->persistent_alloc);
1357 } else {
1358 meta->sname = ZSTR_EMPTY_ALLOC();
1359 }
1360 meta->name = ZSTR_VAL(meta->sname);
1361 meta->name_length = ZSTR_LEN(meta->sname);
1362
1363 /* Now do allocs */
1364 if (meta->catalog && meta->catalog != mysqlnd_empty_string) {
1365 len = meta->catalog_length;
1366 meta->catalog = memcpy(root_ptr, meta->catalog, len);
1367 *(root_ptr +=len) = '\0';
1368 root_ptr++;
1369 }
1370
1371 if (meta->db && meta->db != mysqlnd_empty_string) {
1372 len = meta->db_length;
1373 meta->db = memcpy(root_ptr, meta->db, len);
1374 *(root_ptr +=len) = '\0';
1375 root_ptr++;
1376 }
1377
1378 if (meta->table && meta->table != mysqlnd_empty_string) {
1379 len = meta->table_length;
1380 meta->table = memcpy(root_ptr, meta->table, len);
1381 *(root_ptr +=len) = '\0';
1382 root_ptr++;
1383 }
1384
1385 if (meta->org_table && meta->org_table != mysqlnd_empty_string) {
1386 len = meta->org_table_length;
1387 meta->org_table = memcpy(root_ptr, meta->org_table, len);
1388 *(root_ptr +=len) = '\0';
1389 root_ptr++;
1390 }
1391
1392 if (meta->org_name && meta->org_name != mysqlnd_empty_string) {
1393 len = meta->org_name_length;
1394 meta->org_name = memcpy(root_ptr, meta->org_name, len);
1395 *(root_ptr +=len) = '\0';
1396 root_ptr++;
1397 }
1398
1399 DBG_INF_FMT("allocing root. persistent=%u", packet->persistent_alloc);
1400
1401 DBG_INF_FMT("FIELD=[%s.%s.%s]", meta->db? meta->db:"*NA*", meta->table? meta->table:"*NA*",
1402 meta->name? meta->name:"*NA*");
1403
1404 DBG_RETURN(PASS);
1405
1406 faulty_or_fake:
1407 DBG_ERR_FMT("Protocol error. Server sent NULL_LENGTH. The server is faulty");
1408 php_error_docref(NULL, E_WARNING, "Protocol error. Server sent NULL_LENGTH."
1409 " The server is faulty");
1410 DBG_RETURN(FAIL);
1411 premature_end:
1412 DBG_ERR_FMT("RSET field packet %d bytes shorter than expected", p - begin - packet->header.size);
1413 php_error_docref(NULL, E_WARNING, "Result set field packet "MYSQLND_SZ_T_SPEC" bytes "
1414 "shorter than expected", p - begin - packet->header.size);
1415 DBG_RETURN(FAIL);
1416 }
1417 /* }}} */
1418
1419
1420 /* {{{ php_mysqlnd_rset_field_free_mem */
1421 static
php_mysqlnd_rset_field_free_mem(void * _packet,zend_bool stack_allocation)1422 void php_mysqlnd_rset_field_free_mem(void * _packet, zend_bool stack_allocation)
1423 {
1424 MYSQLND_PACKET_RES_FIELD *p = (MYSQLND_PACKET_RES_FIELD *) _packet;
1425 /* p->metadata was passed to us as temporal buffer */
1426 if (!stack_allocation) {
1427 mnd_pefree(p, p->header.persistent);
1428 }
1429 }
1430 /* }}} */
1431
1432
1433 /* {{{ php_mysqlnd_read_row_ex */
1434 static enum_func_status
php_mysqlnd_read_row_ex(MYSQLND_CONN_DATA * conn,MYSQLND_MEMORY_POOL * result_set_memory_pool,MYSQLND_MEMORY_POOL_CHUNK ** buffer,size_t * data_size,zend_bool persistent_alloc,unsigned int prealloc_more_bytes)1435 php_mysqlnd_read_row_ex(MYSQLND_CONN_DATA * conn, MYSQLND_MEMORY_POOL * result_set_memory_pool,
1436 MYSQLND_MEMORY_POOL_CHUNK ** buffer,
1437 size_t * data_size, zend_bool persistent_alloc,
1438 unsigned int prealloc_more_bytes)
1439 {
1440 enum_func_status ret = PASS;
1441 MYSQLND_PACKET_HEADER header;
1442 zend_uchar * p = NULL;
1443 zend_bool first_iteration = TRUE;
1444
1445 DBG_ENTER("php_mysqlnd_read_row_ex");
1446
1447 /*
1448 * We're allocating 1 extra byte, as php_mysqlnd_rowp_read_text_protocol_aux
1449 * needs to be able to add a terminating \0 for atoi/atof.
1450 */
1451 prealloc_more_bytes++;
1452
1453 /*
1454 To ease the process the server splits everything in packets up to 2^24 - 1.
1455 Even in the case the payload is evenly divisible by this value, the last
1456 packet will be empty, namely 0 bytes. Thus, we can read every packet and ask
1457 for next one if they have 2^24 - 1 sizes. But just read the header of a
1458 zero-length byte, don't read the body, there is no such.
1459 */
1460
1461 *data_size = 0;
1462 while (1) {
1463 if (FAIL == mysqlnd_read_header(conn->net, &header, conn->stats, conn->error_info)) {
1464 ret = FAIL;
1465 break;
1466 }
1467
1468 *data_size += header.size;
1469
1470 if (first_iteration) {
1471 first_iteration = FALSE;
1472 *buffer = result_set_memory_pool->get_chunk(
1473 result_set_memory_pool, *data_size + prealloc_more_bytes);
1474 if (!*buffer) {
1475 ret = FAIL;
1476 break;
1477 }
1478 p = (*buffer)->ptr;
1479 } else if (!first_iteration) {
1480 /* Empty packet after MYSQLND_MAX_PACKET_SIZE packet. That's ok, break */
1481 if (!header.size) {
1482 break;
1483 }
1484
1485 /*
1486 We have to realloc the buffer.
1487 */
1488 if (FAIL == (*buffer)->resize_chunk((*buffer), *data_size + prealloc_more_bytes)) {
1489 SET_OOM_ERROR(*conn->error_info);
1490 ret = FAIL;
1491 break;
1492 }
1493 /* The position could have changed, recalculate */
1494 p = (*buffer)->ptr + (*data_size - header.size);
1495 }
1496
1497 if (PASS != (ret = conn->net->data->m.receive_ex(conn->net, p, header.size, conn->stats, conn->error_info))) {
1498 DBG_ERR("Empty row packet body");
1499 php_error(E_WARNING, "Empty row packet body");
1500 break;
1501 }
1502
1503 if (header.size < MYSQLND_MAX_PACKET_SIZE) {
1504 break;
1505 }
1506 }
1507 if (ret == FAIL && *buffer) {
1508 (*buffer)->free_chunk((*buffer));
1509 *buffer = NULL;
1510 }
1511 DBG_RETURN(ret);
1512 }
1513 /* }}} */
1514
1515
1516 /* {{{ php_mysqlnd_rowp_read_binary_protocol */
1517 enum_func_status
php_mysqlnd_rowp_read_binary_protocol(MYSQLND_MEMORY_POOL_CHUNK * row_buffer,zval * fields,unsigned int field_count,const MYSQLND_FIELD * fields_metadata,zend_bool as_int_or_float,MYSQLND_STATS * stats)1518 php_mysqlnd_rowp_read_binary_protocol(MYSQLND_MEMORY_POOL_CHUNK * row_buffer, zval * fields,
1519 unsigned int field_count, const MYSQLND_FIELD * fields_metadata,
1520 zend_bool as_int_or_float, MYSQLND_STATS * stats)
1521 {
1522 unsigned int i;
1523 zend_uchar *p = row_buffer->ptr;
1524 zend_uchar *null_ptr, bit;
1525 zval *current_field, *end_field, *start_field;
1526
1527 DBG_ENTER("php_mysqlnd_rowp_read_binary_protocol");
1528
1529 if (!fields) {
1530 DBG_RETURN(FAIL);
1531 }
1532
1533 end_field = (start_field = fields) + field_count;
1534
1535 /* skip the first byte, not EODATA_MARKER -> 0x0, status */
1536 p++;
1537 null_ptr= p;
1538 p += (field_count + 9)/8; /* skip null bits */
1539 bit = 4; /* first 2 bits are reserved */
1540
1541 for (i = 0, current_field = start_field; current_field < end_field; current_field++, i++) {
1542 enum_mysqlnd_collected_stats statistic;
1543 zend_uchar * orig_p = p;
1544
1545 DBG_INF_FMT("Into zval=%p decoding column %u [%s.%s.%s] type=%u field->flags&unsigned=%u flags=%u is_bit=%u",
1546 current_field, i,
1547 fields_metadata[i].db, fields_metadata[i].table, fields_metadata[i].name, fields_metadata[i].type,
1548 fields_metadata[i].flags & UNSIGNED_FLAG, fields_metadata[i].flags, fields_metadata[i].type == MYSQL_TYPE_BIT);
1549 if (*null_ptr & bit) {
1550 DBG_INF("It's null");
1551 ZVAL_NULL(current_field);
1552 statistic = STAT_BINARY_TYPE_FETCHED_NULL;
1553 } else {
1554 enum_mysqlnd_field_types type = fields_metadata[i].type;
1555 mysqlnd_ps_fetch_functions[type].func(current_field, &fields_metadata[i], 0, &p);
1556
1557 if (MYSQLND_G(collect_statistics)) {
1558 switch (fields_metadata[i].type) {
1559 case MYSQL_TYPE_DECIMAL: statistic = STAT_BINARY_TYPE_FETCHED_DECIMAL; break;
1560 case MYSQL_TYPE_TINY: statistic = STAT_BINARY_TYPE_FETCHED_INT8; break;
1561 case MYSQL_TYPE_SHORT: statistic = STAT_BINARY_TYPE_FETCHED_INT16; break;
1562 case MYSQL_TYPE_LONG: statistic = STAT_BINARY_TYPE_FETCHED_INT32; break;
1563 case MYSQL_TYPE_FLOAT: statistic = STAT_BINARY_TYPE_FETCHED_FLOAT; break;
1564 case MYSQL_TYPE_DOUBLE: statistic = STAT_BINARY_TYPE_FETCHED_DOUBLE; break;
1565 case MYSQL_TYPE_NULL: statistic = STAT_BINARY_TYPE_FETCHED_NULL; break;
1566 case MYSQL_TYPE_TIMESTAMP: statistic = STAT_BINARY_TYPE_FETCHED_TIMESTAMP; break;
1567 case MYSQL_TYPE_LONGLONG: statistic = STAT_BINARY_TYPE_FETCHED_INT64; break;
1568 case MYSQL_TYPE_INT24: statistic = STAT_BINARY_TYPE_FETCHED_INT24; break;
1569 case MYSQL_TYPE_DATE: statistic = STAT_BINARY_TYPE_FETCHED_DATE; break;
1570 case MYSQL_TYPE_TIME: statistic = STAT_BINARY_TYPE_FETCHED_TIME; break;
1571 case MYSQL_TYPE_DATETIME: statistic = STAT_BINARY_TYPE_FETCHED_DATETIME; break;
1572 case MYSQL_TYPE_YEAR: statistic = STAT_BINARY_TYPE_FETCHED_YEAR; break;
1573 case MYSQL_TYPE_NEWDATE: statistic = STAT_BINARY_TYPE_FETCHED_DATE; break;
1574 case MYSQL_TYPE_VARCHAR: statistic = STAT_BINARY_TYPE_FETCHED_STRING; break;
1575 case MYSQL_TYPE_BIT: statistic = STAT_BINARY_TYPE_FETCHED_BIT; break;
1576 case MYSQL_TYPE_NEWDECIMAL: statistic = STAT_BINARY_TYPE_FETCHED_DECIMAL; break;
1577 case MYSQL_TYPE_ENUM: statistic = STAT_BINARY_TYPE_FETCHED_ENUM; break;
1578 case MYSQL_TYPE_SET: statistic = STAT_BINARY_TYPE_FETCHED_SET; break;
1579 case MYSQL_TYPE_TINY_BLOB: statistic = STAT_BINARY_TYPE_FETCHED_BLOB; break;
1580 case MYSQL_TYPE_MEDIUM_BLOB:statistic = STAT_BINARY_TYPE_FETCHED_BLOB; break;
1581 case MYSQL_TYPE_LONG_BLOB: statistic = STAT_BINARY_TYPE_FETCHED_BLOB; break;
1582 case MYSQL_TYPE_BLOB: statistic = STAT_BINARY_TYPE_FETCHED_BLOB; break;
1583 case MYSQL_TYPE_VAR_STRING: statistic = STAT_BINARY_TYPE_FETCHED_STRING; break;
1584 case MYSQL_TYPE_STRING: statistic = STAT_BINARY_TYPE_FETCHED_STRING; break;
1585 case MYSQL_TYPE_GEOMETRY: statistic = STAT_BINARY_TYPE_FETCHED_GEOMETRY; break;
1586 default: statistic = STAT_BINARY_TYPE_FETCHED_OTHER; break;
1587 }
1588 }
1589 }
1590 MYSQLND_INC_CONN_STATISTIC_W_VALUE2(stats, statistic, 1,
1591 STAT_BYTES_RECEIVED_PURE_DATA_PS,
1592 (Z_TYPE_P(current_field) == IS_STRING)?
1593 Z_STRLEN_P(current_field) : (p - orig_p));
1594
1595 if (!((bit<<=1) & 255)) {
1596 bit = 1; /* to the following byte */
1597 null_ptr++;
1598 }
1599 }
1600
1601 DBG_RETURN(PASS);
1602 }
1603 /* }}} */
1604
1605
1606 /* {{{ php_mysqlnd_rowp_read_text_protocol */
1607 enum_func_status
php_mysqlnd_rowp_read_text_protocol_aux(MYSQLND_MEMORY_POOL_CHUNK * row_buffer,zval * fields,unsigned int field_count,const MYSQLND_FIELD * fields_metadata,zend_bool as_int_or_float,MYSQLND_STATS * stats)1608 php_mysqlnd_rowp_read_text_protocol_aux(MYSQLND_MEMORY_POOL_CHUNK * row_buffer, zval * fields,
1609 unsigned int field_count, const MYSQLND_FIELD * fields_metadata,
1610 zend_bool as_int_or_float, MYSQLND_STATS * stats)
1611 {
1612 unsigned int i;
1613 zval *current_field, *end_field, *start_field;
1614 zend_uchar * p = row_buffer->ptr;
1615 size_t data_size = row_buffer->app;
1616 /* we allocate from here. In pre-7.0 it was +1, as there was an additional \0 for the last string in the packet - because of the zval optimizations - using no-copy */
1617 zend_uchar * bit_area = (zend_uchar*) row_buffer->ptr + data_size;
1618 const zend_uchar * const packet_end = (zend_uchar*) row_buffer->ptr + data_size;
1619
1620 DBG_ENTER("php_mysqlnd_rowp_read_text_protocol_aux");
1621
1622 if (!fields) {
1623 DBG_RETURN(FAIL);
1624 }
1625
1626 end_field = (start_field = fields) + field_count;
1627
1628 for (i = 0, current_field = start_field; current_field < end_field; current_field++, i++) {
1629 /* php_mysqlnd_net_field_length() call should be after *this_field_len_pos = p; */
1630 const zend_ulong len = php_mysqlnd_net_field_length(&p);
1631
1632 /* NULL or NOT NULL, this is the question! */
1633 if (len == MYSQLND_NULL_LENGTH) {
1634 ZVAL_NULL(current_field);
1635 } else if ((p + len) > packet_end) {
1636 php_error_docref(NULL, E_WARNING, "Malformed server packet. Field length pointing "MYSQLND_SZ_T_SPEC
1637 " bytes after end of packet", (p + len) - packet_end - 1);
1638 DBG_RETURN(FAIL);
1639 } else {
1640 #if defined(MYSQLND_STRING_TO_INT_CONVERSION)
1641 struct st_mysqlnd_perm_bind perm_bind =
1642 mysqlnd_ps_fetch_functions[fields_metadata[i].type];
1643 #endif
1644 if (MYSQLND_G(collect_statistics)) {
1645 enum_mysqlnd_collected_stats statistic;
1646 switch (fields_metadata[i].type) {
1647 case MYSQL_TYPE_DECIMAL: statistic = STAT_TEXT_TYPE_FETCHED_DECIMAL; break;
1648 case MYSQL_TYPE_TINY: statistic = STAT_TEXT_TYPE_FETCHED_INT8; break;
1649 case MYSQL_TYPE_SHORT: statistic = STAT_TEXT_TYPE_FETCHED_INT16; break;
1650 case MYSQL_TYPE_LONG: statistic = STAT_TEXT_TYPE_FETCHED_INT32; break;
1651 case MYSQL_TYPE_FLOAT: statistic = STAT_TEXT_TYPE_FETCHED_FLOAT; break;
1652 case MYSQL_TYPE_DOUBLE: statistic = STAT_TEXT_TYPE_FETCHED_DOUBLE; break;
1653 case MYSQL_TYPE_NULL: statistic = STAT_TEXT_TYPE_FETCHED_NULL; break;
1654 case MYSQL_TYPE_TIMESTAMP: statistic = STAT_TEXT_TYPE_FETCHED_TIMESTAMP; break;
1655 case MYSQL_TYPE_LONGLONG: statistic = STAT_TEXT_TYPE_FETCHED_INT64; break;
1656 case MYSQL_TYPE_INT24: statistic = STAT_TEXT_TYPE_FETCHED_INT24; break;
1657 case MYSQL_TYPE_DATE: statistic = STAT_TEXT_TYPE_FETCHED_DATE; break;
1658 case MYSQL_TYPE_TIME: statistic = STAT_TEXT_TYPE_FETCHED_TIME; break;
1659 case MYSQL_TYPE_DATETIME: statistic = STAT_TEXT_TYPE_FETCHED_DATETIME; break;
1660 case MYSQL_TYPE_YEAR: statistic = STAT_TEXT_TYPE_FETCHED_YEAR; break;
1661 case MYSQL_TYPE_NEWDATE: statistic = STAT_TEXT_TYPE_FETCHED_DATE; break;
1662 case MYSQL_TYPE_VARCHAR: statistic = STAT_TEXT_TYPE_FETCHED_STRING; break;
1663 case MYSQL_TYPE_BIT: statistic = STAT_TEXT_TYPE_FETCHED_BIT; break;
1664 case MYSQL_TYPE_NEWDECIMAL: statistic = STAT_TEXT_TYPE_FETCHED_DECIMAL; break;
1665 case MYSQL_TYPE_ENUM: statistic = STAT_TEXT_TYPE_FETCHED_ENUM; break;
1666 case MYSQL_TYPE_SET: statistic = STAT_TEXT_TYPE_FETCHED_SET; break;
1667 case MYSQL_TYPE_JSON: statistic = STAT_TEXT_TYPE_FETCHED_JSON; break;
1668 case MYSQL_TYPE_TINY_BLOB: statistic = STAT_TEXT_TYPE_FETCHED_BLOB; break;
1669 case MYSQL_TYPE_MEDIUM_BLOB:statistic = STAT_TEXT_TYPE_FETCHED_BLOB; break;
1670 case MYSQL_TYPE_LONG_BLOB: statistic = STAT_TEXT_TYPE_FETCHED_BLOB; break;
1671 case MYSQL_TYPE_BLOB: statistic = STAT_TEXT_TYPE_FETCHED_BLOB; break;
1672 case MYSQL_TYPE_VAR_STRING: statistic = STAT_TEXT_TYPE_FETCHED_STRING; break;
1673 case MYSQL_TYPE_STRING: statistic = STAT_TEXT_TYPE_FETCHED_STRING; break;
1674 case MYSQL_TYPE_GEOMETRY: statistic = STAT_TEXT_TYPE_FETCHED_GEOMETRY; break;
1675 default: statistic = STAT_TEXT_TYPE_FETCHED_OTHER; break;
1676 }
1677 MYSQLND_INC_CONN_STATISTIC_W_VALUE2(stats, statistic, 1, STAT_BYTES_RECEIVED_PURE_DATA_TEXT, len);
1678 }
1679 #ifdef MYSQLND_STRING_TO_INT_CONVERSION
1680 if (as_int_or_float && perm_bind.php_type == IS_LONG) {
1681 zend_uchar save = *(p + len);
1682 /* We have to make it ASCIIZ temporarily */
1683 *(p + len) = '\0';
1684 if (perm_bind.pack_len < SIZEOF_ZEND_LONG) {
1685 /* direct conversion */
1686 int64_t v =
1687 #ifndef PHP_WIN32
1688 atoll((char *) p);
1689 #else
1690 _atoi64((char *) p);
1691 #endif
1692 ZVAL_LONG(current_field, (zend_long) v); /* the cast is safe */
1693 } else {
1694 uint64_t v =
1695 #ifndef PHP_WIN32
1696 (uint64_t) atoll((char *) p);
1697 #else
1698 (uint64_t) _atoi64((char *) p);
1699 #endif
1700 zend_bool uns = fields_metadata[i].flags & UNSIGNED_FLAG? TRUE:FALSE;
1701 /* We have to make it ASCIIZ temporarily */
1702 #if SIZEOF_ZEND_LONG==8
1703 if (uns == TRUE && v > 9223372036854775807L)
1704 #elif SIZEOF_ZEND_LONG==4
1705 if ((uns == TRUE && v > L64(2147483647)) ||
1706 (uns == FALSE && (( L64(2147483647) < (int64_t) v) ||
1707 (L64(-2147483648) > (int64_t) v))))
1708 #else
1709 #error Need fix for this architecture
1710 #endif /* SIZEOF */
1711 {
1712 ZVAL_STRINGL(current_field, (char *)p, len);
1713 } else {
1714 ZVAL_LONG(current_field, (zend_long) v); /* the cast is safe */
1715 }
1716 }
1717 *(p + len) = save;
1718 } else if (as_int_or_float && perm_bind.php_type == IS_DOUBLE) {
1719 zend_uchar save = *(p + len);
1720 /* We have to make it ASCIIZ temporarily */
1721 *(p + len) = '\0';
1722 ZVAL_DOUBLE(current_field, atof((char *) p));
1723 *(p + len) = save;
1724 } else
1725 #endif /* MYSQLND_STRING_TO_INT_CONVERSION */
1726 if (fields_metadata[i].type == MYSQL_TYPE_BIT) {
1727 /*
1728 BIT fields are specially handled. As they come as bit mask, we have
1729 to convert it to human-readable representation. As the bits take
1730 less space in the protocol than the numbers they represent, we don't
1731 have enough space in the packet buffer to overwrite inside.
1732 Thus, a bit more space is pre-allocated at the end of the buffer,
1733 see php_mysqlnd_rowp_read(). And we add the strings at the end.
1734 Definitely not nice, _hackish_ :(, but works.
1735 */
1736 zend_uchar *start = bit_area;
1737 ps_fetch_from_1_to_8_bytes(current_field, &(fields_metadata[i]), 0, &p, len);
1738 /*
1739 We have advanced in ps_fetch_from_1_to_8_bytes. We should go back because
1740 later in this function there will be an advancement.
1741 */
1742 p -= len;
1743 if (Z_TYPE_P(current_field) == IS_LONG) {
1744 /*
1745 Andrey : See below. No need of bit_area, as we can use on stack for this.
1746 The bit area should be removed - the `prealloc_more_bytes` in php_mysqlnd_read_row_ex()
1747
1748 char tmp[22];
1749 const size_t tmp_len = sprintf((char *)&tmp, MYSQLND_LLU_SPEC, Z_LVAL_P(current_field));
1750 ZVAL_STRINGL(current_field, tmp, tmp_len);
1751 */
1752 bit_area += 1 + sprintf((char *)start, ZEND_LONG_FMT, Z_LVAL_P(current_field));
1753 ZVAL_STRINGL(current_field, (char *) start, bit_area - start - 1);
1754 } else if (Z_TYPE_P(current_field) == IS_STRING) {
1755 /*
1756 Andrey : This is totally sensless, but I am not gonna remove it in a production version.
1757 This copies the data from the zval to the bit area. The destroys the original value
1758 and creates the same one from the bit area. No need. It was making sense in pre-7.0
1759 when we used zval IS_STRING with no-copy that referred to the bit area.
1760 The bit area has no sense in both the case of IS_LONG and IS_STRING as 7.0 zval
1761 IS_STRING always copies.
1762 */
1763 memcpy(bit_area, Z_STRVAL_P(current_field), Z_STRLEN_P(current_field));
1764 bit_area += Z_STRLEN_P(current_field);
1765 *bit_area++ = '\0';
1766 zval_dtor(current_field);
1767 ZVAL_STRINGL(current_field, (char *) start, bit_area - start - 1);
1768 }
1769 } else {
1770 ZVAL_STRINGL(current_field, (char *)p, len);
1771 }
1772 p += len;
1773 }
1774 }
1775
1776 DBG_RETURN(PASS);
1777 }
1778 /* }}} */
1779
1780
1781 /* {{{ php_mysqlnd_rowp_read_text_protocol_zval */
1782 enum_func_status
php_mysqlnd_rowp_read_text_protocol_zval(MYSQLND_MEMORY_POOL_CHUNK * row_buffer,zval * fields,unsigned int field_count,const MYSQLND_FIELD * fields_metadata,zend_bool as_int_or_float,MYSQLND_STATS * stats)1783 php_mysqlnd_rowp_read_text_protocol_zval(MYSQLND_MEMORY_POOL_CHUNK * row_buffer, zval * fields,
1784 unsigned int field_count, const MYSQLND_FIELD * fields_metadata,
1785 zend_bool as_int_or_float, MYSQLND_STATS * stats)
1786 {
1787 enum_func_status ret;
1788 DBG_ENTER("php_mysqlnd_rowp_read_text_protocol_zval");
1789 ret = php_mysqlnd_rowp_read_text_protocol_aux(row_buffer, fields, field_count, fields_metadata, as_int_or_float, stats);
1790 DBG_RETURN(ret);
1791 }
1792 /* }}} */
1793
1794
1795 /* {{{ php_mysqlnd_rowp_read_text_protocol_c */
1796 enum_func_status
php_mysqlnd_rowp_read_text_protocol_c(MYSQLND_MEMORY_POOL_CHUNK * row_buffer,zval * fields,unsigned int field_count,const MYSQLND_FIELD * fields_metadata,zend_bool as_int_or_float,MYSQLND_STATS * stats)1797 php_mysqlnd_rowp_read_text_protocol_c(MYSQLND_MEMORY_POOL_CHUNK * row_buffer, zval * fields,
1798 unsigned int field_count, const MYSQLND_FIELD * fields_metadata,
1799 zend_bool as_int_or_float, MYSQLND_STATS * stats)
1800 {
1801 enum_func_status ret;
1802 DBG_ENTER("php_mysqlnd_rowp_read_text_protocol_c");
1803 ret = php_mysqlnd_rowp_read_text_protocol_aux(row_buffer, fields, field_count, fields_metadata, as_int_or_float, stats);
1804 DBG_RETURN(ret);
1805 }
1806 /* }}} */
1807
1808
1809 /* {{{ php_mysqlnd_rowp_read */
1810 /*
1811 if normal statements => packet->fields is created by this function,
1812 if PS => packet->fields is passed from outside
1813 */
1814 static enum_func_status
php_mysqlnd_rowp_read(void * _packet,MYSQLND_CONN_DATA * conn)1815 php_mysqlnd_rowp_read(void * _packet, MYSQLND_CONN_DATA * conn)
1816 {
1817 zend_uchar *p;
1818 enum_func_status ret = PASS;
1819 MYSQLND_PACKET_ROW *packet= (MYSQLND_PACKET_ROW *) _packet;
1820 size_t post_alloc_for_bit_fields = 0;
1821 size_t data_size = 0;
1822
1823 DBG_ENTER("php_mysqlnd_rowp_read");
1824
1825 if (!packet->binary_protocol && packet->bit_fields_count) {
1826 /* For every field we need terminating \0 */
1827 post_alloc_for_bit_fields = packet->bit_fields_total_len + packet->bit_fields_count;
1828 }
1829
1830 ret = php_mysqlnd_read_row_ex(conn, packet->result_set_memory_pool, &packet->row_buffer, &data_size,
1831 packet->persistent_alloc, post_alloc_for_bit_fields
1832 );
1833 if (FAIL == ret) {
1834 goto end;
1835 }
1836 MYSQLND_INC_CONN_STATISTIC_W_VALUE2(conn->stats, packet_type_to_statistic_byte_count[PROT_ROW_PACKET],
1837 MYSQLND_HEADER_SIZE + packet->header.size,
1838 packet_type_to_statistic_packet_count[PROT_ROW_PACKET],
1839 1);
1840
1841 /*
1842 packet->row_buffer->ptr is of size 'data_size'
1843 in pre-7.0 it was really 'data_size + 1' although it was counted as 'data_size'
1844 The +1 was for the additional byte needed to \0 terminate the last string in the row.
1845 This was needed as the zvals of pre-7.0 could use external memory (no copy param to ZVAL_STRINGL).
1846 However, in 7.0+ the strings always copy. Thus this +1 byte was removed. Also the optimization or \0
1847 terminating every string, which did overwrite the lengths from the packet. For this reason we needed
1848 to keep (and copy) the lengths externally.
1849 */
1850 packet->header.size = data_size;
1851 packet->row_buffer->app = data_size;
1852
1853 if (ERROR_MARKER == (*(p = packet->row_buffer->ptr))) {
1854 /*
1855 Error message as part of the result set,
1856 not good but we should not hang. See:
1857 Bug #27876 : SF with cyrillic variable name fails during execution
1858 */
1859 ret = FAIL;
1860 php_mysqlnd_read_error_from_line(p + 1, data_size - 1,
1861 packet->error_info.error,
1862 sizeof(packet->error_info.error),
1863 &packet->error_info.error_no,
1864 packet->error_info.sqlstate
1865 );
1866 } else if (EODATA_MARKER == *p && data_size < 8) { /* EOF */
1867 packet->eof = TRUE;
1868 p++;
1869 if (data_size > 1) {
1870 packet->warning_count = uint2korr(p);
1871 p += 2;
1872 packet->server_status = uint2korr(p);
1873 /* Seems we have 3 bytes reserved for future use */
1874 DBG_INF_FMT("server_status=%u warning_count=%u", packet->server_status, packet->warning_count);
1875 }
1876 } else {
1877 MYSQLND_INC_CONN_STATISTIC(conn->stats,
1878 packet->binary_protocol? STAT_ROWS_FETCHED_FROM_SERVER_PS:
1879 STAT_ROWS_FETCHED_FROM_SERVER_NORMAL);
1880
1881 packet->eof = FALSE;
1882 /* packet->field_count is set by the user of the packet */
1883
1884 if (!packet->skip_extraction) {
1885 if (!packet->fields) {
1886 DBG_INF("Allocating packet->fields");
1887 /*
1888 old-API will probably set packet->fields to NULL every time, though for
1889 unbuffered sets it makes not much sense as the zvals in this buffer matter,
1890 not the buffer. Constantly allocating and deallocating brings nothing.
1891
1892 For PS - if stmt_store() is performed, thus we don't have a cursor, it will
1893 behave just like old-API buffered. Cursors will behave like a bit different,
1894 but mostly like old-API unbuffered and thus will populate this array with
1895 value.
1896 */
1897 packet->fields = mnd_pecalloc(packet->field_count, sizeof(zval),
1898 packet->persistent_alloc);
1899 }
1900 } else {
1901 MYSQLND_INC_CONN_STATISTIC(conn->stats,
1902 packet->binary_protocol? STAT_ROWS_SKIPPED_PS:
1903 STAT_ROWS_SKIPPED_NORMAL);
1904 }
1905 }
1906
1907 end:
1908 DBG_RETURN(ret);
1909 }
1910 /* }}} */
1911
1912
1913 /* {{{ php_mysqlnd_rowp_free_mem */
1914 static void
php_mysqlnd_rowp_free_mem(void * _packet,zend_bool stack_allocation)1915 php_mysqlnd_rowp_free_mem(void * _packet, zend_bool stack_allocation)
1916 {
1917 MYSQLND_PACKET_ROW *p;
1918
1919 DBG_ENTER("php_mysqlnd_rowp_free_mem");
1920 p = (MYSQLND_PACKET_ROW *) _packet;
1921 if (p->row_buffer) {
1922 p->row_buffer->free_chunk(p->row_buffer);
1923 p->row_buffer = NULL;
1924 }
1925 DBG_INF_FMT("stack_allocation=%u persistent=%u", (int)stack_allocation, (int)p->header.persistent);
1926 /*
1927 Don't free packet->fields :
1928 - normal queries -> store_result() | fetch_row_unbuffered() will transfer
1929 the ownership and NULL it.
1930 - PS will pass in it the bound variables, we have to use them! and of course
1931 not free the array. As it is passed to us, we should not clean it ourselves.
1932 */
1933 if (!stack_allocation) {
1934 mnd_pefree(p, p->header.persistent);
1935 }
1936 DBG_VOID_RETURN;
1937 }
1938 /* }}} */
1939
1940
1941 /* {{{ php_mysqlnd_stats_read */
1942 static enum_func_status
php_mysqlnd_stats_read(void * _packet,MYSQLND_CONN_DATA * conn)1943 php_mysqlnd_stats_read(void * _packet, MYSQLND_CONN_DATA * conn)
1944 {
1945 MYSQLND_PACKET_STATS *packet= (MYSQLND_PACKET_STATS *) _packet;
1946 size_t buf_len = conn->net->cmd_buffer.length;
1947 zend_uchar *buf = (zend_uchar *) conn->net->cmd_buffer.buffer;
1948
1949 DBG_ENTER("php_mysqlnd_stats_read");
1950
1951 PACKET_READ_HEADER_AND_BODY(packet, conn, buf, buf_len, "statistics", PROT_STATS_PACKET);
1952
1953 packet->message = mnd_emalloc(packet->header.size + 1);
1954 memcpy(packet->message, buf, packet->header.size);
1955 packet->message[packet->header.size] = '\0';
1956 packet->message_len = packet->header.size;
1957
1958 DBG_RETURN(PASS);
1959 }
1960 /* }}} */
1961
1962
1963 /* {{{ php_mysqlnd_stats_free_mem */
1964 static
php_mysqlnd_stats_free_mem(void * _packet,zend_bool stack_allocation)1965 void php_mysqlnd_stats_free_mem(void * _packet, zend_bool stack_allocation)
1966 {
1967 MYSQLND_PACKET_STATS *p= (MYSQLND_PACKET_STATS *) _packet;
1968 if (p->message) {
1969 mnd_efree(p->message);
1970 p->message = NULL;
1971 }
1972 if (!stack_allocation) {
1973 mnd_pefree(p, p->header.persistent);
1974 }
1975 }
1976 /* }}} */
1977
1978
1979 /* 1 + 4 (id) + 2 (field_c) + 2 (param_c) + 1 (filler) + 2 (warnings ) */
1980 #define PREPARE_RESPONSE_SIZE_41 9
1981 #define PREPARE_RESPONSE_SIZE_50 12
1982
1983 /* {{{ php_mysqlnd_prepare_read */
1984 static enum_func_status
php_mysqlnd_prepare_read(void * _packet,MYSQLND_CONN_DATA * conn)1985 php_mysqlnd_prepare_read(void * _packet, MYSQLND_CONN_DATA * conn)
1986 {
1987 /* In case of an error, we should have place to put it */
1988 size_t buf_len = conn->net->cmd_buffer.length;
1989 zend_uchar *buf = (zend_uchar *) conn->net->cmd_buffer.buffer;
1990 zend_uchar *p = buf;
1991 zend_uchar *begin = buf;
1992 unsigned int data_size;
1993 MYSQLND_PACKET_PREPARE_RESPONSE *packet= (MYSQLND_PACKET_PREPARE_RESPONSE *) _packet;
1994
1995 DBG_ENTER("php_mysqlnd_prepare_read");
1996
1997 PACKET_READ_HEADER_AND_BODY(packet, conn, buf, buf_len, "prepare", PROT_PREPARE_RESP_PACKET);
1998 BAIL_IF_NO_MORE_DATA;
1999
2000 data_size = packet->header.size;
2001 packet->error_code = uint1korr(p);
2002 p++;
2003 BAIL_IF_NO_MORE_DATA;
2004
2005 if (ERROR_MARKER == packet->error_code) {
2006 php_mysqlnd_read_error_from_line(p, data_size - 1,
2007 packet->error_info.error,
2008 sizeof(packet->error_info.error),
2009 &packet->error_info.error_no,
2010 packet->error_info.sqlstate
2011 );
2012 DBG_RETURN(PASS);
2013 }
2014
2015 if (data_size != PREPARE_RESPONSE_SIZE_41 &&
2016 data_size != PREPARE_RESPONSE_SIZE_50 &&
2017 !(data_size > PREPARE_RESPONSE_SIZE_50)) {
2018 DBG_ERR_FMT("Wrong COM_STMT_PREPARE response size. Received %u", data_size);
2019 php_error(E_WARNING, "Wrong COM_STMT_PREPARE response size. Received %u", data_size);
2020 DBG_RETURN(FAIL);
2021 }
2022
2023 packet->stmt_id = uint4korr(p);
2024 p += 4;
2025 BAIL_IF_NO_MORE_DATA;
2026
2027 /* Number of columns in result set */
2028 packet->field_count = uint2korr(p);
2029 p += 2;
2030 BAIL_IF_NO_MORE_DATA;
2031
2032 packet->param_count = uint2korr(p);
2033 p += 2;
2034 BAIL_IF_NO_MORE_DATA;
2035
2036 if (data_size > 9) {
2037 /* 0x0 filler sent by the server for 5.0+ clients */
2038 p++;
2039 BAIL_IF_NO_MORE_DATA;
2040
2041 packet->warning_count = uint2korr(p);
2042 }
2043
2044 DBG_INF_FMT("Prepare packet read: stmt_id=%u fields=%u params=%u",
2045 packet->stmt_id, packet->field_count, packet->param_count);
2046
2047 BAIL_IF_NO_MORE_DATA;
2048
2049 DBG_RETURN(PASS);
2050 premature_end:
2051 DBG_ERR_FMT("PREPARE packet %d bytes shorter than expected", p - begin - packet->header.size);
2052 php_error_docref(NULL, E_WARNING, "PREPARE packet "MYSQLND_SZ_T_SPEC" bytes shorter than expected",
2053 p - begin - packet->header.size);
2054 DBG_RETURN(FAIL);
2055 }
2056 /* }}} */
2057
2058
2059 /* {{{ php_mysqlnd_prepare_free_mem */
2060 static void
php_mysqlnd_prepare_free_mem(void * _packet,zend_bool stack_allocation)2061 php_mysqlnd_prepare_free_mem(void * _packet, zend_bool stack_allocation)
2062 {
2063 MYSQLND_PACKET_PREPARE_RESPONSE *p= (MYSQLND_PACKET_PREPARE_RESPONSE *) _packet;
2064 if (!stack_allocation) {
2065 mnd_pefree(p, p->header.persistent);
2066 }
2067 }
2068 /* }}} */
2069
2070
2071 /* {{{ php_mysqlnd_chg_user_read */
2072 static enum_func_status
php_mysqlnd_chg_user_read(void * _packet,MYSQLND_CONN_DATA * conn)2073 php_mysqlnd_chg_user_read(void * _packet, MYSQLND_CONN_DATA * conn)
2074 {
2075 /* There could be an error message */
2076 size_t buf_len = conn->net->cmd_buffer.length;
2077 zend_uchar *buf = (zend_uchar *) conn->net->cmd_buffer.buffer;
2078 zend_uchar *p = buf;
2079 zend_uchar *begin = buf;
2080 MYSQLND_PACKET_CHG_USER_RESPONSE *packet= (MYSQLND_PACKET_CHG_USER_RESPONSE *) _packet;
2081
2082 DBG_ENTER("php_mysqlnd_chg_user_read");
2083
2084 PACKET_READ_HEADER_AND_BODY(packet, conn, buf, buf_len, "change user response", PROT_CHG_USER_RESP_PACKET);
2085 BAIL_IF_NO_MORE_DATA;
2086
2087 /*
2088 Don't increment. First byte is ERROR_MARKER on error, but otherwise is starting byte
2089 of encoded sequence for length.
2090 */
2091
2092 /* Should be always 0x0 or ERROR_MARKER for error */
2093 packet->response_code = uint1korr(p);
2094 p++;
2095
2096 if (packet->header.size == 1 && buf[0] == EODATA_MARKER && packet->server_capabilities & CLIENT_SECURE_CONNECTION) {
2097 /* We don't handle 3.23 authentication */
2098 packet->server_asked_323_auth = TRUE;
2099 DBG_RETURN(FAIL);
2100 }
2101
2102 if (ERROR_MARKER == packet->response_code) {
2103 php_mysqlnd_read_error_from_line(p, packet->header.size - 1,
2104 packet->error_info.error,
2105 sizeof(packet->error_info.error),
2106 &packet->error_info.error_no,
2107 packet->error_info.sqlstate
2108 );
2109 }
2110 BAIL_IF_NO_MORE_DATA;
2111 if (packet->response_code == 0xFE && packet->header.size > (size_t) (p - buf)) {
2112 packet->new_auth_protocol = mnd_pestrdup((char *)p, FALSE);
2113 packet->new_auth_protocol_len = strlen(packet->new_auth_protocol);
2114 p+= packet->new_auth_protocol_len + 1; /* +1 for the \0 */
2115 packet->new_auth_protocol_data_len = packet->header.size - (size_t) (p - buf);
2116 if (packet->new_auth_protocol_data_len) {
2117 packet->new_auth_protocol_data = mnd_emalloc(packet->new_auth_protocol_data_len);
2118 memcpy(packet->new_auth_protocol_data, p, packet->new_auth_protocol_data_len);
2119 }
2120 DBG_INF_FMT("The server requested switching auth plugin to : %s", packet->new_auth_protocol);
2121 DBG_INF_FMT("Server salt : [%*s]", packet->new_auth_protocol_data_len, packet->new_auth_protocol_data);
2122 }
2123
2124 DBG_RETURN(PASS);
2125 premature_end:
2126 DBG_ERR_FMT("CHANGE_USER packet %d bytes shorter than expected", p - begin - packet->header.size);
2127 php_error_docref(NULL, E_WARNING, "CHANGE_USER packet "MYSQLND_SZ_T_SPEC" bytes shorter than expected",
2128 p - begin - packet->header.size);
2129 DBG_RETURN(FAIL);
2130 }
2131 /* }}} */
2132
2133
2134 /* {{{ php_mysqlnd_chg_user_free_mem */
2135 static void
php_mysqlnd_chg_user_free_mem(void * _packet,zend_bool stack_allocation)2136 php_mysqlnd_chg_user_free_mem(void * _packet, zend_bool stack_allocation)
2137 {
2138 MYSQLND_PACKET_CHG_USER_RESPONSE * p = (MYSQLND_PACKET_CHG_USER_RESPONSE *) _packet;
2139
2140 if (p->new_auth_protocol) {
2141 mnd_efree(p->new_auth_protocol);
2142 p->new_auth_protocol = NULL;
2143 }
2144 p->new_auth_protocol_len = 0;
2145
2146 if (p->new_auth_protocol_data) {
2147 mnd_efree(p->new_auth_protocol_data);
2148 p->new_auth_protocol_data = NULL;
2149 }
2150 p->new_auth_protocol_data_len = 0;
2151
2152 if (!stack_allocation) {
2153 mnd_pefree(p, p->header.persistent);
2154 }
2155 }
2156 /* }}} */
2157
2158
2159 /* {{{ php_mysqlnd_sha256_pk_request_write */
2160 static
php_mysqlnd_sha256_pk_request_write(void * _packet,MYSQLND_CONN_DATA * conn)2161 size_t php_mysqlnd_sha256_pk_request_write(void * _packet, MYSQLND_CONN_DATA * conn)
2162 {
2163 zend_uchar buffer[MYSQLND_HEADER_SIZE + 1];
2164 size_t sent;
2165
2166 DBG_ENTER("php_mysqlnd_sha256_pk_request_write");
2167
2168 int1store(buffer + MYSQLND_HEADER_SIZE, '\1');
2169 sent = conn->net->data->m.send_ex(conn->net, buffer, 1, conn->stats, conn->error_info);
2170
2171 DBG_RETURN(sent);
2172 }
2173 /* }}} */
2174
2175
2176 /* {{{ php_mysqlnd_sha256_pk_request_free_mem */
2177 static
php_mysqlnd_sha256_pk_request_free_mem(void * _packet,zend_bool stack_allocation)2178 void php_mysqlnd_sha256_pk_request_free_mem(void * _packet, zend_bool stack_allocation)
2179 {
2180 if (!stack_allocation) {
2181 MYSQLND_PACKET_SHA256_PK_REQUEST * p = (MYSQLND_PACKET_SHA256_PK_REQUEST *) _packet;
2182 mnd_pefree(p, p->header.persistent);
2183 }
2184 }
2185 /* }}} */
2186
2187
2188 #define SHA256_PK_REQUEST_RESP_BUFFER_SIZE 2048
2189
2190 /* {{{ php_mysqlnd_sha256_pk_request_response_read */
2191 static enum_func_status
php_mysqlnd_sha256_pk_request_response_read(void * _packet,MYSQLND_CONN_DATA * conn)2192 php_mysqlnd_sha256_pk_request_response_read(void * _packet, MYSQLND_CONN_DATA * conn)
2193 {
2194 zend_uchar buf[SHA256_PK_REQUEST_RESP_BUFFER_SIZE];
2195 zend_uchar *p = buf;
2196 zend_uchar *begin = buf;
2197 MYSQLND_PACKET_SHA256_PK_REQUEST_RESPONSE * packet= (MYSQLND_PACKET_SHA256_PK_REQUEST_RESPONSE *) _packet;
2198
2199 DBG_ENTER("php_mysqlnd_sha256_pk_request_response_read");
2200
2201 /* leave space for terminating safety \0 */
2202 PACKET_READ_HEADER_AND_BODY(packet, conn, buf, sizeof(buf), "SHA256_PK_REQUEST_RESPONSE", PROT_SHA256_PK_REQUEST_RESPONSE_PACKET);
2203 BAIL_IF_NO_MORE_DATA;
2204
2205 p++;
2206 BAIL_IF_NO_MORE_DATA;
2207
2208 packet->public_key_len = packet->header.size - (p - buf);
2209 packet->public_key = mnd_emalloc(packet->public_key_len + 1);
2210 memcpy(packet->public_key, p, packet->public_key_len);
2211 packet->public_key[packet->public_key_len] = '\0';
2212
2213 DBG_RETURN(PASS);
2214
2215 premature_end:
2216 DBG_ERR_FMT("OK packet %d bytes shorter than expected", p - begin - packet->header.size);
2217 php_error_docref(NULL, E_WARNING, "SHA256_PK_REQUEST_RESPONSE packet "MYSQLND_SZ_T_SPEC" bytes shorter than expected",
2218 p - begin - packet->header.size);
2219 DBG_RETURN(FAIL);
2220 }
2221 /* }}} */
2222
2223
2224 /* {{{ php_mysqlnd_sha256_pk_request_response_free_mem */
2225 static void
php_mysqlnd_sha256_pk_request_response_free_mem(void * _packet,zend_bool stack_allocation)2226 php_mysqlnd_sha256_pk_request_response_free_mem(void * _packet, zend_bool stack_allocation)
2227 {
2228 MYSQLND_PACKET_SHA256_PK_REQUEST_RESPONSE * p = (MYSQLND_PACKET_SHA256_PK_REQUEST_RESPONSE *) _packet;
2229 if (p->public_key) {
2230 mnd_efree(p->public_key);
2231 p->public_key = NULL;
2232 }
2233 p->public_key_len = 0;
2234
2235 if (!stack_allocation) {
2236 mnd_pefree(p, p->header.persistent);
2237 }
2238 }
2239 /* }}} */
2240
2241
2242 /* {{{ packet_methods */
2243 static
2244 mysqlnd_packet_methods packet_methods[PROT_LAST] =
2245 {
2246 {
2247 sizeof(MYSQLND_PACKET_GREET),
2248 php_mysqlnd_greet_read,
2249 NULL, /* write */
2250 php_mysqlnd_greet_free_mem,
2251 }, /* PROT_GREET_PACKET */
2252 {
2253 sizeof(MYSQLND_PACKET_AUTH),
2254 NULL, /* read */
2255 php_mysqlnd_auth_write,
2256 php_mysqlnd_auth_free_mem,
2257 }, /* PROT_AUTH_PACKET */
2258 {
2259 sizeof(MYSQLND_PACKET_AUTH_RESPONSE),
2260 php_mysqlnd_auth_response_read, /* read */
2261 NULL, /* write */
2262 php_mysqlnd_auth_response_free_mem,
2263 }, /* PROT_AUTH_RESP_PACKET */
2264 {
2265 sizeof(MYSQLND_PACKET_CHANGE_AUTH_RESPONSE),
2266 NULL, /* read */
2267 php_mysqlnd_change_auth_response_write, /* write */
2268 php_mysqlnd_change_auth_response_free_mem,
2269 }, /* PROT_CHANGE_AUTH_RESP_PACKET */
2270 {
2271 sizeof(MYSQLND_PACKET_OK),
2272 php_mysqlnd_ok_read, /* read */
2273 NULL, /* write */
2274 php_mysqlnd_ok_free_mem,
2275 }, /* PROT_OK_PACKET */
2276 {
2277 sizeof(MYSQLND_PACKET_EOF),
2278 php_mysqlnd_eof_read, /* read */
2279 NULL, /* write */
2280 php_mysqlnd_eof_free_mem,
2281 }, /* PROT_EOF_PACKET */
2282 {
2283 sizeof(MYSQLND_PACKET_COMMAND),
2284 NULL, /* read */
2285 php_mysqlnd_cmd_write, /* write */
2286 php_mysqlnd_cmd_free_mem,
2287 }, /* PROT_CMD_PACKET */
2288 {
2289 sizeof(MYSQLND_PACKET_RSET_HEADER),
2290 php_mysqlnd_rset_header_read, /* read */
2291 NULL, /* write */
2292 php_mysqlnd_rset_header_free_mem,
2293 }, /* PROT_RSET_HEADER_PACKET */
2294 {
2295 sizeof(MYSQLND_PACKET_RES_FIELD),
2296 php_mysqlnd_rset_field_read, /* read */
2297 NULL, /* write */
2298 php_mysqlnd_rset_field_free_mem,
2299 }, /* PROT_RSET_FLD_PACKET */
2300 {
2301 sizeof(MYSQLND_PACKET_ROW),
2302 php_mysqlnd_rowp_read, /* read */
2303 NULL, /* write */
2304 php_mysqlnd_rowp_free_mem,
2305 }, /* PROT_ROW_PACKET */
2306 {
2307 sizeof(MYSQLND_PACKET_STATS),
2308 php_mysqlnd_stats_read, /* read */
2309 NULL, /* write */
2310 php_mysqlnd_stats_free_mem,
2311 }, /* PROT_STATS_PACKET */
2312 {
2313 sizeof(MYSQLND_PACKET_PREPARE_RESPONSE),
2314 php_mysqlnd_prepare_read, /* read */
2315 NULL, /* write */
2316 php_mysqlnd_prepare_free_mem,
2317 }, /* PROT_PREPARE_RESP_PACKET */
2318 {
2319 sizeof(MYSQLND_PACKET_CHG_USER_RESPONSE),
2320 php_mysqlnd_chg_user_read, /* read */
2321 NULL, /* write */
2322 php_mysqlnd_chg_user_free_mem,
2323 }, /* PROT_CHG_USER_RESP_PACKET */
2324 {
2325 sizeof(MYSQLND_PACKET_SHA256_PK_REQUEST),
2326 NULL, /* read */
2327 php_mysqlnd_sha256_pk_request_write,
2328 php_mysqlnd_sha256_pk_request_free_mem,
2329 }, /* PROT_SHA256_PK_REQUEST_PACKET */
2330 {
2331 sizeof(MYSQLND_PACKET_SHA256_PK_REQUEST_RESPONSE),
2332 php_mysqlnd_sha256_pk_request_response_read,
2333 NULL, /* write */
2334 php_mysqlnd_sha256_pk_request_response_free_mem,
2335 } /* PROT_SHA256_PK_REQUEST_RESPONSE_PACKET */
2336 };
2337 /* }}} */
2338
2339
2340 /* {{{ mysqlnd_protocol::get_greet_packet */
2341 static struct st_mysqlnd_packet_greet *
MYSQLND_METHOD(mysqlnd_protocol,get_greet_packet)2342 MYSQLND_METHOD(mysqlnd_protocol, get_greet_packet)(MYSQLND_PROTOCOL * const protocol, zend_bool persistent)
2343 {
2344 struct st_mysqlnd_packet_greet * packet = mnd_pecalloc(1, packet_methods[PROT_GREET_PACKET].struct_size, persistent);
2345 DBG_ENTER("mysqlnd_protocol::get_greet_packet");
2346 if (packet) {
2347 packet->header.m = &packet_methods[PROT_GREET_PACKET];
2348 packet->header.persistent = persistent;
2349 }
2350 DBG_RETURN(packet);
2351 }
2352 /* }}} */
2353
2354
2355 /* {{{ mysqlnd_protocol::get_auth_packet */
2356 static struct st_mysqlnd_packet_auth *
MYSQLND_METHOD(mysqlnd_protocol,get_auth_packet)2357 MYSQLND_METHOD(mysqlnd_protocol, get_auth_packet)(MYSQLND_PROTOCOL * const protocol, zend_bool persistent)
2358 {
2359 struct st_mysqlnd_packet_auth * packet = mnd_pecalloc(1, packet_methods[PROT_AUTH_PACKET].struct_size, persistent);
2360 DBG_ENTER("mysqlnd_protocol::get_auth_packet");
2361 if (packet) {
2362 packet->header.m = &packet_methods[PROT_AUTH_PACKET];
2363 packet->header.persistent = persistent;
2364 }
2365 DBG_RETURN(packet);
2366 }
2367 /* }}} */
2368
2369
2370 /* {{{ mysqlnd_protocol::get_auth_response_packet */
2371 static struct st_mysqlnd_packet_auth_response *
MYSQLND_METHOD(mysqlnd_protocol,get_auth_response_packet)2372 MYSQLND_METHOD(mysqlnd_protocol, get_auth_response_packet)(MYSQLND_PROTOCOL * const protocol, zend_bool persistent)
2373 {
2374 struct st_mysqlnd_packet_auth_response * packet = mnd_pecalloc(1, packet_methods[PROT_AUTH_RESP_PACKET].struct_size, persistent);
2375 DBG_ENTER("mysqlnd_protocol::get_auth_response_packet");
2376 if (packet) {
2377 packet->header.m = &packet_methods[PROT_AUTH_RESP_PACKET];
2378 packet->header.persistent = persistent;
2379 }
2380 DBG_RETURN(packet);
2381 }
2382 /* }}} */
2383
2384
2385 /* {{{ mysqlnd_protocol::get_change_auth_response_packet */
2386 static struct st_mysqlnd_packet_change_auth_response *
MYSQLND_METHOD(mysqlnd_protocol,get_change_auth_response_packet)2387 MYSQLND_METHOD(mysqlnd_protocol, get_change_auth_response_packet)(MYSQLND_PROTOCOL * const protocol, zend_bool persistent)
2388 {
2389 struct st_mysqlnd_packet_change_auth_response * packet = mnd_pecalloc(1, packet_methods[PROT_CHANGE_AUTH_RESP_PACKET].struct_size, persistent);
2390 DBG_ENTER("mysqlnd_protocol::get_change_auth_response_packet");
2391 if (packet) {
2392 packet->header.m = &packet_methods[PROT_CHANGE_AUTH_RESP_PACKET];
2393 packet->header.persistent = persistent;
2394 }
2395 DBG_RETURN(packet);
2396 }
2397 /* }}} */
2398
2399
2400 /* {{{ mysqlnd_protocol::get_ok_packet */
2401 static struct st_mysqlnd_packet_ok *
MYSQLND_METHOD(mysqlnd_protocol,get_ok_packet)2402 MYSQLND_METHOD(mysqlnd_protocol, get_ok_packet)(MYSQLND_PROTOCOL * const protocol, zend_bool persistent)
2403 {
2404 struct st_mysqlnd_packet_ok * packet = mnd_pecalloc(1, packet_methods[PROT_OK_PACKET].struct_size, persistent);
2405 DBG_ENTER("mysqlnd_protocol::get_ok_packet");
2406 if (packet) {
2407 packet->header.m = &packet_methods[PROT_OK_PACKET];
2408 packet->header.persistent = persistent;
2409 }
2410 DBG_RETURN(packet);
2411 }
2412 /* }}} */
2413
2414
2415 /* {{{ mysqlnd_protocol::get_eof_packet */
2416 static struct st_mysqlnd_packet_eof *
MYSQLND_METHOD(mysqlnd_protocol,get_eof_packet)2417 MYSQLND_METHOD(mysqlnd_protocol, get_eof_packet)(MYSQLND_PROTOCOL * const protocol, zend_bool persistent)
2418 {
2419 struct st_mysqlnd_packet_eof * packet = mnd_pecalloc(1, packet_methods[PROT_EOF_PACKET].struct_size, persistent);
2420 DBG_ENTER("mysqlnd_protocol::get_eof_packet");
2421 if (packet) {
2422 packet->header.m = &packet_methods[PROT_EOF_PACKET];
2423 packet->header.persistent = persistent;
2424 }
2425 DBG_RETURN(packet);
2426 }
2427 /* }}} */
2428
2429
2430 /* {{{ mysqlnd_protocol::get_command_packet */
2431 static struct st_mysqlnd_packet_command *
MYSQLND_METHOD(mysqlnd_protocol,get_command_packet)2432 MYSQLND_METHOD(mysqlnd_protocol, get_command_packet)(MYSQLND_PROTOCOL * const protocol, zend_bool persistent)
2433 {
2434 struct st_mysqlnd_packet_command * packet = mnd_pecalloc(1, packet_methods[PROT_CMD_PACKET].struct_size, persistent);
2435 DBG_ENTER("mysqlnd_protocol::get_command_packet");
2436 if (packet) {
2437 packet->header.m = &packet_methods[PROT_CMD_PACKET];
2438 packet->header.persistent = persistent;
2439 }
2440 DBG_RETURN(packet);
2441 }
2442 /* }}} */
2443
2444
2445 /* {{{ mysqlnd_protocol::get_rset_packet */
2446 static struct st_mysqlnd_packet_rset_header *
MYSQLND_METHOD(mysqlnd_protocol,get_rset_header_packet)2447 MYSQLND_METHOD(mysqlnd_protocol, get_rset_header_packet)(MYSQLND_PROTOCOL * const protocol, zend_bool persistent)
2448 {
2449 struct st_mysqlnd_packet_rset_header * packet = mnd_pecalloc(1, packet_methods[PROT_RSET_HEADER_PACKET].struct_size, persistent);
2450 DBG_ENTER("mysqlnd_protocol::get_rset_header_packet");
2451 if (packet) {
2452 packet->header.m = &packet_methods[PROT_RSET_HEADER_PACKET];
2453 packet->header.persistent = persistent;
2454 }
2455 DBG_RETURN(packet);
2456 }
2457 /* }}} */
2458
2459
2460 /* {{{ mysqlnd_protocol::get_result_field_packet */
2461 static struct st_mysqlnd_packet_res_field *
MYSQLND_METHOD(mysqlnd_protocol,get_result_field_packet)2462 MYSQLND_METHOD(mysqlnd_protocol, get_result_field_packet)(MYSQLND_PROTOCOL * const protocol, zend_bool persistent)
2463 {
2464 struct st_mysqlnd_packet_res_field * packet = mnd_pecalloc(1, packet_methods[PROT_RSET_FLD_PACKET].struct_size, persistent);
2465 DBG_ENTER("mysqlnd_protocol::get_result_field_packet");
2466 if (packet) {
2467 packet->header.m = &packet_methods[PROT_RSET_FLD_PACKET];
2468 packet->header.persistent = persistent;
2469 }
2470 DBG_RETURN(packet);
2471 }
2472 /* }}} */
2473
2474
2475 /* {{{ mysqlnd_protocol::get_row_packet */
2476 static struct st_mysqlnd_packet_row *
MYSQLND_METHOD(mysqlnd_protocol,get_row_packet)2477 MYSQLND_METHOD(mysqlnd_protocol, get_row_packet)(MYSQLND_PROTOCOL * const protocol, zend_bool persistent)
2478 {
2479 struct st_mysqlnd_packet_row * packet = mnd_pecalloc(1, packet_methods[PROT_ROW_PACKET].struct_size, persistent);
2480 DBG_ENTER("mysqlnd_protocol::get_row_packet");
2481 if (packet) {
2482 packet->header.m = &packet_methods[PROT_ROW_PACKET];
2483 packet->header.persistent = persistent;
2484 }
2485 DBG_RETURN(packet);
2486 }
2487 /* }}} */
2488
2489
2490 /* {{{ mysqlnd_protocol::get_stats_packet */
2491 static struct st_mysqlnd_packet_stats *
MYSQLND_METHOD(mysqlnd_protocol,get_stats_packet)2492 MYSQLND_METHOD(mysqlnd_protocol, get_stats_packet)(MYSQLND_PROTOCOL * const protocol, zend_bool persistent)
2493 {
2494 struct st_mysqlnd_packet_stats * packet = mnd_pecalloc(1, packet_methods[PROT_STATS_PACKET].struct_size, persistent);
2495 DBG_ENTER("mysqlnd_protocol::get_stats_packet");
2496 if (packet) {
2497 packet->header.m = &packet_methods[PROT_STATS_PACKET];
2498 packet->header.persistent = persistent;
2499 }
2500 DBG_RETURN(packet);
2501 }
2502 /* }}} */
2503
2504
2505 /* {{{ mysqlnd_protocol::get_prepare_response_packet */
2506 static struct st_mysqlnd_packet_prepare_response *
MYSQLND_METHOD(mysqlnd_protocol,get_prepare_response_packet)2507 MYSQLND_METHOD(mysqlnd_protocol, get_prepare_response_packet)(MYSQLND_PROTOCOL * const protocol, zend_bool persistent)
2508 {
2509 struct st_mysqlnd_packet_prepare_response * packet = mnd_pecalloc(1, packet_methods[PROT_PREPARE_RESP_PACKET].struct_size, persistent);
2510 DBG_ENTER("mysqlnd_protocol::get_prepare_response_packet");
2511 if (packet) {
2512 packet->header.m = &packet_methods[PROT_PREPARE_RESP_PACKET];
2513 packet->header.persistent = persistent;
2514 }
2515 DBG_RETURN(packet);
2516 }
2517 /* }}} */
2518
2519
2520 /* {{{ mysqlnd_protocol::get_change_user_response_packet */
2521 static struct st_mysqlnd_packet_chg_user_resp*
MYSQLND_METHOD(mysqlnd_protocol,get_change_user_response_packet)2522 MYSQLND_METHOD(mysqlnd_protocol, get_change_user_response_packet)(MYSQLND_PROTOCOL * const protocol, zend_bool persistent)
2523 {
2524 struct st_mysqlnd_packet_chg_user_resp * packet = mnd_pecalloc(1, packet_methods[PROT_CHG_USER_RESP_PACKET].struct_size, persistent);
2525 DBG_ENTER("mysqlnd_protocol::get_change_user_response_packet");
2526 if (packet) {
2527 packet->header.m = &packet_methods[PROT_CHG_USER_RESP_PACKET];
2528 packet->header.persistent = persistent;
2529 }
2530 DBG_RETURN(packet);
2531 }
2532 /* }}} */
2533
2534
2535 /* {{{ mysqlnd_protocol::get_sha256_pk_request_packet */
2536 static struct st_mysqlnd_packet_sha256_pk_request *
MYSQLND_METHOD(mysqlnd_protocol,get_sha256_pk_request_packet)2537 MYSQLND_METHOD(mysqlnd_protocol, get_sha256_pk_request_packet)(MYSQLND_PROTOCOL * const protocol, zend_bool persistent)
2538 {
2539 struct st_mysqlnd_packet_sha256_pk_request * packet = mnd_pecalloc(1, packet_methods[PROT_SHA256_PK_REQUEST_PACKET].struct_size, persistent);
2540 DBG_ENTER("mysqlnd_protocol::get_sha256_pk_request_packet");
2541 if (packet) {
2542 packet->header.m = &packet_methods[PROT_SHA256_PK_REQUEST_PACKET];
2543 packet->header.persistent = persistent;
2544 }
2545 DBG_RETURN(packet);
2546 }
2547 /* }}} */
2548
2549
2550 /* {{{ mysqlnd_protocol::get_sha256_pk_request_response_packet */
2551 static struct st_mysqlnd_packet_sha256_pk_request_response *
MYSQLND_METHOD(mysqlnd_protocol,get_sha256_pk_request_response_packet)2552 MYSQLND_METHOD(mysqlnd_protocol, get_sha256_pk_request_response_packet)(MYSQLND_PROTOCOL * const protocol, zend_bool persistent)
2553 {
2554 struct st_mysqlnd_packet_sha256_pk_request_response * packet = mnd_pecalloc(1, packet_methods[PROT_SHA256_PK_REQUEST_RESPONSE_PACKET].struct_size, persistent);
2555 DBG_ENTER("mysqlnd_protocol::get_sha256_pk_request_response_packet");
2556 if (packet) {
2557 packet->header.m = &packet_methods[PROT_SHA256_PK_REQUEST_RESPONSE_PACKET];
2558 packet->header.persistent = persistent;
2559 }
2560 DBG_RETURN(packet);
2561 }
2562 /* }}} */
2563
2564
2565
2566 MYSQLND_CLASS_METHODS_START(mysqlnd_protocol)
2567 MYSQLND_METHOD(mysqlnd_protocol, get_greet_packet),
2568 MYSQLND_METHOD(mysqlnd_protocol, get_auth_packet),
2569 MYSQLND_METHOD(mysqlnd_protocol, get_auth_response_packet),
2570 MYSQLND_METHOD(mysqlnd_protocol, get_change_auth_response_packet),
2571 MYSQLND_METHOD(mysqlnd_protocol, get_ok_packet),
2572 MYSQLND_METHOD(mysqlnd_protocol, get_command_packet),
2573 MYSQLND_METHOD(mysqlnd_protocol, get_eof_packet),
2574 MYSQLND_METHOD(mysqlnd_protocol, get_rset_header_packet),
2575 MYSQLND_METHOD(mysqlnd_protocol, get_result_field_packet),
2576 MYSQLND_METHOD(mysqlnd_protocol, get_row_packet),
2577 MYSQLND_METHOD(mysqlnd_protocol, get_stats_packet),
2578 MYSQLND_METHOD(mysqlnd_protocol, get_prepare_response_packet),
2579 MYSQLND_METHOD(mysqlnd_protocol, get_change_user_response_packet),
2580 MYSQLND_METHOD(mysqlnd_protocol, get_sha256_pk_request_packet),
2581 MYSQLND_METHOD(mysqlnd_protocol, get_sha256_pk_request_response_packet)
2582 MYSQLND_CLASS_METHODS_END;
2583
2584
2585 /* {{{ mysqlnd_protocol_init */
2586 PHPAPI MYSQLND_PROTOCOL *
mysqlnd_protocol_init(zend_bool persistent)2587 mysqlnd_protocol_init(zend_bool persistent)
2588 {
2589 MYSQLND_PROTOCOL * ret;
2590 DBG_ENTER("mysqlnd_protocol_init");
2591 ret = MYSQLND_CLASS_METHOD_TABLE_NAME(mysqlnd_object_factory).get_protocol_decoder(persistent);
2592 DBG_RETURN(ret);
2593 }
2594 /* }}} */
2595
2596
2597 /* {{{ mysqlnd_protocol_free */
2598 PHPAPI void
mysqlnd_protocol_free(MYSQLND_PROTOCOL * const protocol)2599 mysqlnd_protocol_free(MYSQLND_PROTOCOL * const protocol)
2600 {
2601 DBG_ENTER("mysqlnd_protocol_free");
2602
2603 if (protocol) {
2604 zend_bool pers = protocol->persistent;
2605 mnd_pefree(protocol, pers);
2606 }
2607 DBG_VOID_RETURN;
2608 }
2609 /* }}} */
2610
2611
2612 /*
2613 * Local variables:
2614 * tab-width: 4
2615 * c-basic-offset: 4
2616 * End:
2617 * vim600: noet sw=4 ts=4 fdm=marker
2618 * vim<600: noet sw=4 ts=4
2619 */
2620