mysqlnd_commands.c 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696
  1. /*
  2. +----------------------------------------------------------------------+
  3. | Copyright (c) The PHP Group |
  4. +----------------------------------------------------------------------+
  5. | This source file is subject to version 3.01 of the PHP license, |
  6. | that is bundled with this package in the file LICENSE, and is |
  7. | available through the world-wide-web at the following url: |
  8. | https://www.php.net/license/3_01.txt |
  9. | If you did not receive a copy of the PHP license and are unable to |
  10. | obtain it through the world-wide-web, please send a note to |
  11. | license@php.net so we can mail you a copy immediately. |
  12. +----------------------------------------------------------------------+
  13. | Authors: Andrey Hristov <andrey@php.net> |
  14. | Ulf Wendel <uw@php.net> |
  15. +----------------------------------------------------------------------+
  16. */
  17. #include "php.h"
  18. #include "mysqlnd.h"
  19. #include "mysqlnd_connection.h"
  20. #include "mysqlnd_priv.h"
  21. #include "mysqlnd_auth.h"
  22. #include "mysqlnd_wireprotocol.h"
  23. #include "mysqlnd_debug.h"
  24. /* {{{ mysqlnd_command::set_option */
  25. static enum_func_status
  26. MYSQLND_METHOD(mysqlnd_command, set_option)(MYSQLND_CONN_DATA * const conn, const enum_mysqlnd_server_option option)
  27. {
  28. const func_mysqlnd_protocol_payload_decoder_factory__send_command send_command = conn->payload_decoder_factory->m.send_command;
  29. const func_mysqlnd_protocol_payload_decoder_factory__send_command_handle_response send_command_handle_response = conn->payload_decoder_factory->m.send_command_handle_response;
  30. zend_uchar buffer[2];
  31. enum_func_status ret = FAIL;
  32. DBG_ENTER("mysqlnd_command::set_option");
  33. int2store(buffer, (unsigned int) option);
  34. ret = send_command(conn->payload_decoder_factory, COM_SET_OPTION, buffer, sizeof(buffer), FALSE,
  35. &conn->state,
  36. conn->error_info,
  37. conn->upsert_status,
  38. conn->stats,
  39. conn->m->send_close,
  40. conn);
  41. if (PASS == ret) {
  42. ret = send_command_handle_response(conn->payload_decoder_factory, PROT_EOF_PACKET, FALSE, COM_SET_OPTION, TRUE,
  43. conn->error_info, conn->upsert_status, &conn->last_message);
  44. }
  45. DBG_RETURN(ret);
  46. }
  47. /* }}} */
  48. /* {{{ mysqlnd_command::debug */
  49. static enum_func_status
  50. MYSQLND_METHOD(mysqlnd_command, debug)(MYSQLND_CONN_DATA * const conn)
  51. {
  52. const func_mysqlnd_protocol_payload_decoder_factory__send_command send_command = conn->payload_decoder_factory->m.send_command;
  53. const func_mysqlnd_protocol_payload_decoder_factory__send_command_handle_response send_command_handle_response = conn->payload_decoder_factory->m.send_command_handle_response;
  54. enum_func_status ret = FAIL;
  55. DBG_ENTER("mysqlnd_command::debug");
  56. ret = send_command(conn->payload_decoder_factory, COM_DEBUG, NULL, 0, FALSE,
  57. &conn->state,
  58. conn->error_info,
  59. conn->upsert_status,
  60. conn->stats,
  61. conn->m->send_close,
  62. conn);
  63. if (PASS == ret) {
  64. ret = send_command_handle_response(conn->payload_decoder_factory, PROT_EOF_PACKET, FALSE, COM_DEBUG, TRUE,
  65. conn->error_info, conn->upsert_status, &conn->last_message);
  66. }
  67. DBG_RETURN(ret);
  68. }
  69. /* }}} */
  70. /* {{{ mysqlnd_command::init_db */
  71. static enum_func_status
  72. MYSQLND_METHOD(mysqlnd_command, init_db)(MYSQLND_CONN_DATA * const conn, const MYSQLND_CSTRING db)
  73. {
  74. const func_mysqlnd_protocol_payload_decoder_factory__send_command send_command = conn->payload_decoder_factory->m.send_command;
  75. const func_mysqlnd_protocol_payload_decoder_factory__send_command_handle_response send_command_handle_response = conn->payload_decoder_factory->m.send_command_handle_response;
  76. enum_func_status ret = FAIL;
  77. DBG_ENTER("mysqlnd_command::init_db");
  78. ret = send_command(conn->payload_decoder_factory, COM_INIT_DB, (const zend_uchar*) db.s, db.l, FALSE,
  79. &conn->state,
  80. conn->error_info,
  81. conn->upsert_status,
  82. conn->stats,
  83. conn->m->send_close,
  84. conn);
  85. if (PASS == ret) {
  86. ret = send_command_handle_response(conn->payload_decoder_factory, PROT_OK_PACKET, FALSE, COM_INIT_DB, TRUE,
  87. conn->error_info, conn->upsert_status, &conn->last_message);
  88. }
  89. /*
  90. The server sends 0 but libmysql doesn't read it and has established
  91. a protocol of giving back -1. Thus we have to follow it :(
  92. */
  93. UPSERT_STATUS_SET_AFFECTED_ROWS_TO_ERROR(conn->upsert_status);
  94. if (ret == PASS) {
  95. mysqlnd_set_persistent_string(&conn->connect_or_select_db, db.s, db.l, conn->persistent);
  96. }
  97. DBG_RETURN(ret);
  98. }
  99. /* }}} */
  100. /* {{{ mysqlnd_command::ping */
  101. static enum_func_status
  102. MYSQLND_METHOD(mysqlnd_command, ping)(MYSQLND_CONN_DATA * const conn)
  103. {
  104. const func_mysqlnd_protocol_payload_decoder_factory__send_command send_command = conn->payload_decoder_factory->m.send_command;
  105. const func_mysqlnd_protocol_payload_decoder_factory__send_command_handle_response send_command_handle_response = conn->payload_decoder_factory->m.send_command_handle_response;
  106. enum_func_status ret = FAIL;
  107. DBG_ENTER("mysqlnd_command::ping");
  108. ret = send_command(conn->payload_decoder_factory, COM_PING, NULL, 0, TRUE,
  109. &conn->state,
  110. conn->error_info,
  111. conn->upsert_status,
  112. conn->stats,
  113. conn->m->send_close,
  114. conn);
  115. if (PASS == ret) {
  116. ret = send_command_handle_response(conn->payload_decoder_factory, PROT_OK_PACKET, TRUE, COM_PING, TRUE,
  117. conn->error_info, conn->upsert_status, &conn->last_message);
  118. }
  119. /*
  120. The server sends 0 but libmysql doesn't read it and has established
  121. a protocol of giving back -1. Thus we have to follow it :(
  122. */
  123. UPSERT_STATUS_SET_AFFECTED_ROWS_TO_ERROR(conn->upsert_status);
  124. DBG_RETURN(ret);
  125. }
  126. /* }}} */
  127. /* {{{ mysqlnd_command::statistics */
  128. static enum_func_status
  129. MYSQLND_METHOD(mysqlnd_command, statistics)(MYSQLND_CONN_DATA * const conn, zend_string ** message)
  130. {
  131. const func_mysqlnd_protocol_payload_decoder_factory__send_command send_command = conn->payload_decoder_factory->m.send_command;
  132. enum_func_status ret = FAIL;
  133. DBG_ENTER("mysqlnd_command::statistics");
  134. ret = send_command(conn->payload_decoder_factory, COM_STATISTICS, NULL, 0, FALSE,
  135. &conn->state,
  136. conn->error_info,
  137. conn->upsert_status,
  138. conn->stats,
  139. conn->m->send_close,
  140. conn);
  141. if (PASS == ret) {
  142. MYSQLND_PACKET_STATS stats_header;
  143. conn->payload_decoder_factory->m.init_stats_packet(&stats_header);
  144. if (PASS == (ret = PACKET_READ(conn, &stats_header))) {
  145. /* will be freed by Zend, thus don't use the mnd_ allocator */
  146. *message = zend_string_init(stats_header.message.s, stats_header.message.l, 0);
  147. DBG_INF(ZSTR_VAL(*message));
  148. }
  149. PACKET_FREE(&stats_header);
  150. }
  151. DBG_RETURN(ret);
  152. }
  153. /* }}} */
  154. /* {{{ mysqlnd_command::process_kill */
  155. static enum_func_status
  156. MYSQLND_METHOD(mysqlnd_command, process_kill)(MYSQLND_CONN_DATA * const conn, const unsigned int process_id, const bool read_response)
  157. {
  158. const func_mysqlnd_protocol_payload_decoder_factory__send_command send_command = conn->payload_decoder_factory->m.send_command;
  159. const func_mysqlnd_protocol_payload_decoder_factory__send_command_handle_response send_command_handle_response = conn->payload_decoder_factory->m.send_command_handle_response;
  160. zend_uchar buff[4];
  161. enum_func_status ret = FAIL;
  162. DBG_ENTER("mysqlnd_command::process_kill");
  163. int4store(buff, process_id);
  164. ret = send_command(conn->payload_decoder_factory, COM_PROCESS_KILL, buff, 4, FALSE,
  165. &conn->state,
  166. conn->error_info,
  167. conn->upsert_status,
  168. conn->stats,
  169. conn->m->send_close,
  170. conn);
  171. if (PASS == ret && read_response) {
  172. ret = send_command_handle_response(conn->payload_decoder_factory, PROT_OK_PACKET, FALSE, COM_PROCESS_KILL, TRUE,
  173. conn->error_info, conn->upsert_status, &conn->last_message);
  174. }
  175. if (read_response) {
  176. /*
  177. The server sends 0 but libmysql doesn't read it and has established
  178. a protocol of giving back -1. Thus we have to follow it :(
  179. */
  180. UPSERT_STATUS_SET_AFFECTED_ROWS_TO_ERROR(conn->upsert_status);
  181. } else if (PASS == ret) {
  182. SET_CONNECTION_STATE(&conn->state, CONN_QUIT_SENT);
  183. conn->m->send_close(conn);
  184. }
  185. DBG_RETURN(ret);
  186. }
  187. /* }}} */
  188. /* {{{ mysqlnd_command::refresh */
  189. static enum_func_status
  190. MYSQLND_METHOD(mysqlnd_command, refresh)(MYSQLND_CONN_DATA * const conn, const uint8_t options)
  191. {
  192. const func_mysqlnd_protocol_payload_decoder_factory__send_command send_command = conn->payload_decoder_factory->m.send_command;
  193. const func_mysqlnd_protocol_payload_decoder_factory__send_command_handle_response send_command_handle_response = conn->payload_decoder_factory->m.send_command_handle_response;
  194. zend_uchar bits[1];
  195. enum_func_status ret = FAIL;
  196. DBG_ENTER("mysqlnd_command::refresh");
  197. int1store(bits, options);
  198. ret = send_command(conn->payload_decoder_factory, COM_REFRESH, bits, 1, FALSE,
  199. &conn->state,
  200. conn->error_info,
  201. conn->upsert_status,
  202. conn->stats,
  203. conn->m->send_close,
  204. conn);
  205. if (PASS == ret) {
  206. ret = send_command_handle_response(conn->payload_decoder_factory, PROT_OK_PACKET, FALSE, COM_REFRESH, TRUE,
  207. conn->error_info, conn->upsert_status, &conn->last_message);
  208. }
  209. DBG_RETURN(ret);
  210. }
  211. /* }}} */
  212. /* {{{ mysqlnd_command::shutdown */
  213. static enum_func_status
  214. MYSQLND_METHOD(mysqlnd_command, shutdown)(MYSQLND_CONN_DATA * const conn, const uint8_t level)
  215. {
  216. const func_mysqlnd_protocol_payload_decoder_factory__send_command send_command = conn->payload_decoder_factory->m.send_command;
  217. const func_mysqlnd_protocol_payload_decoder_factory__send_command_handle_response send_command_handle_response = conn->payload_decoder_factory->m.send_command_handle_response;
  218. zend_uchar bits[1];
  219. enum_func_status ret = FAIL;
  220. DBG_ENTER("mysqlnd_command::shutdown");
  221. int1store(bits, level);
  222. ret = send_command(conn->payload_decoder_factory, COM_SHUTDOWN, bits, 1, FALSE,
  223. &conn->state,
  224. conn->error_info,
  225. conn->upsert_status,
  226. conn->stats,
  227. conn->m->send_close,
  228. conn);
  229. if (PASS == ret) {
  230. ret = send_command_handle_response(conn->payload_decoder_factory, PROT_OK_PACKET, FALSE, COM_SHUTDOWN, TRUE,
  231. conn->error_info, conn->upsert_status, &conn->last_message);
  232. }
  233. DBG_RETURN(ret);
  234. }
  235. /* }}} */
  236. /* {{{ mysqlnd_command::quit */
  237. static enum_func_status
  238. MYSQLND_METHOD(mysqlnd_command, quit)(MYSQLND_CONN_DATA * const conn)
  239. {
  240. const func_mysqlnd_protocol_payload_decoder_factory__send_command send_command = conn->payload_decoder_factory->m.send_command;
  241. enum_func_status ret = FAIL;
  242. DBG_ENTER("mysqlnd_command::quit");
  243. ret = send_command(conn->payload_decoder_factory, COM_QUIT, NULL, 0, TRUE,
  244. &conn->state,
  245. conn->error_info,
  246. conn->upsert_status,
  247. conn->stats,
  248. conn->m->send_close,
  249. conn);
  250. DBG_RETURN(ret);
  251. }
  252. /* }}} */
  253. /* {{{ mysqlnd_command::query */
  254. static enum_func_status
  255. MYSQLND_METHOD(mysqlnd_command, query)(MYSQLND_CONN_DATA * const conn, MYSQLND_CSTRING query)
  256. {
  257. func_mysqlnd_protocol_payload_decoder_factory__send_command send_command = conn->payload_decoder_factory->m.send_command;
  258. enum_func_status ret = FAIL;
  259. DBG_ENTER("mysqlnd_command::query");
  260. ret = send_command(conn->payload_decoder_factory, COM_QUERY, (const zend_uchar*) query.s, query.l, FALSE,
  261. &conn->state,
  262. conn->error_info,
  263. conn->upsert_status,
  264. conn->stats,
  265. conn->m->send_close,
  266. conn);
  267. if (PASS == ret) {
  268. SET_CONNECTION_STATE(&conn->state, CONN_QUERY_SENT);
  269. }
  270. DBG_RETURN(ret);
  271. }
  272. /* }}} */
  273. /* {{{ mysqlnd_command::change_user */
  274. static enum_func_status
  275. MYSQLND_METHOD(mysqlnd_command, change_user)(MYSQLND_CONN_DATA * const conn, const MYSQLND_CSTRING payload, const bool silent)
  276. {
  277. const func_mysqlnd_protocol_payload_decoder_factory__send_command send_command = conn->payload_decoder_factory->m.send_command;
  278. enum_func_status ret = FAIL;
  279. DBG_ENTER("mysqlnd_command::change_user");
  280. ret = send_command(conn->payload_decoder_factory, COM_CHANGE_USER, (const zend_uchar*) payload.s, payload.l, silent,
  281. &conn->state,
  282. conn->error_info,
  283. conn->upsert_status,
  284. conn->stats,
  285. conn->m->send_close,
  286. conn);
  287. DBG_RETURN(ret);
  288. }
  289. /* }}} */
  290. /* {{{ mysqlnd_command::reap_result */
  291. static enum_func_status
  292. MYSQLND_METHOD(mysqlnd_command, reap_result)(MYSQLND_CONN_DATA * const conn)
  293. {
  294. const enum_mysqlnd_connection_state state = GET_CONNECTION_STATE(&conn->state);
  295. enum_func_status ret = FAIL;
  296. DBG_ENTER("mysqlnd_command::reap_result");
  297. if (state <= CONN_READY || state == CONN_QUIT_SENT) {
  298. php_error_docref(NULL, E_WARNING, "Connection not opened, clear or has been closed");
  299. DBG_ERR_FMT("Connection not opened, clear or has been closed. State=%u", state);
  300. DBG_RETURN(ret);
  301. }
  302. ret = conn->m->query_read_result_set_header(conn, NULL);
  303. DBG_RETURN(ret);
  304. }
  305. /* }}} */
  306. /* {{{ mysqlnd_command::stmt_prepare */
  307. static enum_func_status
  308. MYSQLND_METHOD(mysqlnd_command, stmt_prepare)(MYSQLND_CONN_DATA * const conn, const MYSQLND_CSTRING query)
  309. {
  310. func_mysqlnd_protocol_payload_decoder_factory__send_command send_command = conn->payload_decoder_factory->m.send_command;
  311. enum_func_status ret = FAIL;
  312. DBG_ENTER("mysqlnd_command::stmt_prepare");
  313. ret = send_command(conn->payload_decoder_factory, COM_STMT_PREPARE, (const zend_uchar*) query.s, query.l, FALSE,
  314. &conn->state,
  315. conn->error_info,
  316. conn->upsert_status,
  317. conn->stats,
  318. conn->m->send_close,
  319. conn);
  320. DBG_RETURN(ret);
  321. }
  322. /* }}} */
  323. /* {{{ mysqlnd_command::stmt_execute */
  324. static enum_func_status
  325. MYSQLND_METHOD(mysqlnd_command, stmt_execute)(MYSQLND_CONN_DATA * conn, const MYSQLND_CSTRING payload)
  326. {
  327. func_mysqlnd_protocol_payload_decoder_factory__send_command send_command = conn->payload_decoder_factory->m.send_command;
  328. enum_func_status ret = FAIL;
  329. DBG_ENTER("mysqlnd_command::stmt_execute");
  330. ret = send_command(conn->payload_decoder_factory, COM_STMT_EXECUTE,
  331. (const unsigned char *) payload.s, payload.l, FALSE,
  332. &conn->state,
  333. conn->error_info,
  334. conn->upsert_status,
  335. conn->stats,
  336. conn->m->send_close,
  337. conn);
  338. DBG_RETURN(ret);
  339. }
  340. /* }}} */
  341. /* {{{ mysqlnd_command::stmt_fetch */
  342. static enum_func_status
  343. MYSQLND_METHOD(mysqlnd_command, stmt_fetch)(MYSQLND_CONN_DATA * const conn, const MYSQLND_CSTRING payload)
  344. {
  345. func_mysqlnd_protocol_payload_decoder_factory__send_command send_command = conn->payload_decoder_factory->m.send_command;
  346. enum_func_status ret = FAIL;
  347. DBG_ENTER("mysqlnd_command::stmt_fetch");
  348. ret = send_command(conn->payload_decoder_factory, COM_STMT_FETCH, (const zend_uchar*) payload.s, payload.l, FALSE,
  349. &conn->state,
  350. conn->error_info,
  351. conn->upsert_status,
  352. conn->stats,
  353. conn->m->send_close,
  354. conn);
  355. DBG_RETURN(ret);
  356. }
  357. /* }}} */
  358. /* {{{ mysqlnd_command::stmt_reset */
  359. static enum_func_status
  360. MYSQLND_METHOD(mysqlnd_command, stmt_reset)(MYSQLND_CONN_DATA * const conn, const zend_ulong stmt_id)
  361. {
  362. const func_mysqlnd_protocol_payload_decoder_factory__send_command send_command = conn->payload_decoder_factory->m.send_command;
  363. const func_mysqlnd_protocol_payload_decoder_factory__send_command_handle_response send_command_handle_response = conn->payload_decoder_factory->m.send_command_handle_response;
  364. zend_uchar cmd_buf[MYSQLND_STMT_ID_LENGTH /* statement id */];
  365. enum_func_status ret = FAIL;
  366. DBG_ENTER("mysqlnd_command::stmt_reset");
  367. int4store(cmd_buf, stmt_id);
  368. ret = send_command(conn->payload_decoder_factory, COM_STMT_RESET, cmd_buf, sizeof(cmd_buf), FALSE,
  369. &conn->state,
  370. conn->error_info,
  371. conn->upsert_status,
  372. conn->stats,
  373. conn->m->send_close,
  374. conn);
  375. if (PASS == ret) {
  376. ret = send_command_handle_response(conn->payload_decoder_factory, PROT_OK_PACKET, FALSE, COM_STMT_RESET, TRUE,
  377. conn->error_info, conn->upsert_status, &conn->last_message);
  378. }
  379. DBG_RETURN(ret);
  380. }
  381. /* }}} */
  382. /* {{{ mysqlnd_command::stmt_send_long_data */
  383. static enum_func_status
  384. MYSQLND_METHOD(mysqlnd_command, stmt_send_long_data)(MYSQLND_CONN_DATA * const conn, const MYSQLND_CSTRING payload)
  385. {
  386. func_mysqlnd_protocol_payload_decoder_factory__send_command send_command = conn->payload_decoder_factory->m.send_command;
  387. enum_func_status ret = FAIL;
  388. DBG_ENTER("mysqlnd_command::stmt_send_long_data");
  389. ret = send_command(conn->payload_decoder_factory, COM_STMT_SEND_LONG_DATA, (const zend_uchar*) payload.s, payload.l, FALSE,
  390. &conn->state,
  391. conn->error_info,
  392. conn->upsert_status,
  393. conn->stats,
  394. conn->m->send_close,
  395. conn);
  396. /* COM_STMT_SEND_LONG_DATA - doesn't read result, the server doesn't send ACK */
  397. DBG_RETURN(ret);
  398. }
  399. /* }}} */
  400. /* {{{ mysqlnd_command::stmt_close */
  401. static enum_func_status
  402. MYSQLND_METHOD(mysqlnd_command, stmt_close)(MYSQLND_CONN_DATA * const conn, const zend_ulong stmt_id)
  403. {
  404. func_mysqlnd_protocol_payload_decoder_factory__send_command send_command = conn->payload_decoder_factory->m.send_command;
  405. zend_uchar cmd_buf[MYSQLND_STMT_ID_LENGTH /* statement id */];
  406. enum_func_status ret = FAIL;
  407. DBG_ENTER("mysqlnd_command::stmt_close");
  408. int4store(cmd_buf, stmt_id);
  409. ret = send_command(conn->payload_decoder_factory, COM_STMT_CLOSE, cmd_buf, sizeof(cmd_buf), FALSE,
  410. &conn->state,
  411. conn->error_info,
  412. conn->upsert_status,
  413. conn->stats,
  414. conn->m->send_close,
  415. conn);
  416. DBG_RETURN(ret);
  417. }
  418. /* }}} */
  419. /* {{{ mysqlnd_command::enable_ssl */
  420. static enum_func_status
  421. MYSQLND_METHOD(mysqlnd_command, enable_ssl)(MYSQLND_CONN_DATA * const conn, const size_t client_capabilities, const size_t server_capabilities, const unsigned int charset_no)
  422. {
  423. enum_func_status ret = FAIL;
  424. MYSQLND_PACKET_AUTH auth_packet;
  425. DBG_ENTER("mysqlnd_command::enable_ssl");
  426. DBG_INF_FMT("client_capability_flags=%zu", client_capabilities);
  427. DBG_INF_FMT("CLIENT_LONG_PASSWORD= %d", client_capabilities & CLIENT_LONG_PASSWORD? 1:0);
  428. DBG_INF_FMT("CLIENT_FOUND_ROWS= %d", client_capabilities & CLIENT_FOUND_ROWS? 1:0);
  429. DBG_INF_FMT("CLIENT_LONG_FLAG= %d", client_capabilities & CLIENT_LONG_FLAG? 1:0);
  430. DBG_INF_FMT("CLIENT_NO_SCHEMA= %d", client_capabilities & CLIENT_NO_SCHEMA? 1:0);
  431. DBG_INF_FMT("CLIENT_COMPRESS= %d", client_capabilities & CLIENT_COMPRESS? 1:0);
  432. DBG_INF_FMT("CLIENT_ODBC= %d", client_capabilities & CLIENT_ODBC? 1:0);
  433. DBG_INF_FMT("CLIENT_LOCAL_FILES= %d", client_capabilities & CLIENT_LOCAL_FILES? 1:0);
  434. DBG_INF_FMT("CLIENT_IGNORE_SPACE= %d", client_capabilities & CLIENT_IGNORE_SPACE? 1:0);
  435. DBG_INF_FMT("CLIENT_PROTOCOL_41= %d", client_capabilities & CLIENT_PROTOCOL_41? 1:0);
  436. DBG_INF_FMT("CLIENT_INTERACTIVE= %d", client_capabilities & CLIENT_INTERACTIVE? 1:0);
  437. DBG_INF_FMT("CLIENT_SSL= %d", client_capabilities & CLIENT_SSL? 1:0);
  438. DBG_INF_FMT("CLIENT_IGNORE_SIGPIPE= %d", client_capabilities & CLIENT_IGNORE_SIGPIPE? 1:0);
  439. DBG_INF_FMT("CLIENT_TRANSACTIONS= %d", client_capabilities & CLIENT_TRANSACTIONS? 1:0);
  440. DBG_INF_FMT("CLIENT_RESERVED= %d", client_capabilities & CLIENT_RESERVED? 1:0);
  441. DBG_INF_FMT("CLIENT_SECURE_CONNECTION=%d", client_capabilities & CLIENT_SECURE_CONNECTION? 1:0);
  442. DBG_INF_FMT("CLIENT_MULTI_STATEMENTS=%d", client_capabilities & CLIENT_MULTI_STATEMENTS? 1:0);
  443. DBG_INF_FMT("CLIENT_MULTI_RESULTS= %d", client_capabilities & CLIENT_MULTI_RESULTS? 1:0);
  444. DBG_INF_FMT("CLIENT_PS_MULTI_RESULTS=%d", client_capabilities & CLIENT_PS_MULTI_RESULTS? 1:0);
  445. DBG_INF_FMT("CLIENT_CONNECT_ATTRS= %d", client_capabilities & CLIENT_PLUGIN_AUTH? 1:0);
  446. DBG_INF_FMT("CLIENT_PLUGIN_AUTH_LENENC_CLIENT_DATA= %d", client_capabilities & CLIENT_PLUGIN_AUTH_LENENC_CLIENT_DATA? 1:0);
  447. DBG_INF_FMT("CLIENT_CAN_HANDLE_EXPIRED_PASSWORDS= %d", client_capabilities & CLIENT_CAN_HANDLE_EXPIRED_PASSWORDS? 1:0);
  448. DBG_INF_FMT("CLIENT_SESSION_TRACK= %d", client_capabilities & CLIENT_SESSION_TRACK? 1:0);
  449. DBG_INF_FMT("CLIENT_SSL_VERIFY_SERVER_CERT= %d", client_capabilities & CLIENT_SSL_VERIFY_SERVER_CERT? 1:0);
  450. DBG_INF_FMT("CLIENT_REMEMBER_OPTIONS= %d", client_capabilities & CLIENT_REMEMBER_OPTIONS? 1:0);
  451. conn->payload_decoder_factory->m.init_auth_packet(&auth_packet);
  452. auth_packet.client_flags = client_capabilities;
  453. auth_packet.max_packet_size = MYSQLND_ASSEMBLED_PACKET_MAX_SIZE;
  454. auth_packet.charset_no = charset_no;
  455. #ifdef MYSQLND_SSL_SUPPORTED
  456. if (client_capabilities & CLIENT_SSL) {
  457. const bool server_has_ssl = (server_capabilities & CLIENT_SSL)? TRUE:FALSE;
  458. if (server_has_ssl == FALSE) {
  459. goto close_conn;
  460. } else {
  461. enum mysqlnd_ssl_peer verify = client_capabilities & CLIENT_SSL_VERIFY_SERVER_CERT?
  462. MYSQLND_SSL_PEER_VERIFY:
  463. (client_capabilities & CLIENT_SSL_DONT_VERIFY_SERVER_CERT?
  464. MYSQLND_SSL_PEER_DONT_VERIFY:
  465. MYSQLND_SSL_PEER_DEFAULT);
  466. DBG_INF("Switching to SSL");
  467. if (!PACKET_WRITE(conn, &auth_packet)) {
  468. goto close_conn;
  469. }
  470. conn->vio->data->m.set_client_option(conn->vio, MYSQL_OPT_SSL_VERIFY_SERVER_CERT, (const char *) &verify);
  471. if (FAIL == conn->vio->data->m.enable_ssl(conn->vio)) {
  472. goto end;
  473. }
  474. }
  475. }
  476. #else
  477. auth_packet.client_flags &= ~CLIENT_SSL;
  478. if (!PACKET_WRITE(conn, &auth_packet)) {
  479. goto close_conn;
  480. }
  481. #endif
  482. ret = PASS;
  483. end:
  484. PACKET_FREE(&auth_packet);
  485. DBG_RETURN(ret);
  486. close_conn:
  487. SET_CONNECTION_STATE(&conn->state, CONN_QUIT_SENT);
  488. conn->m->send_close(conn);
  489. SET_CLIENT_ERROR(conn->error_info, CR_SERVER_GONE_ERROR, UNKNOWN_SQLSTATE, mysqlnd_server_gone);
  490. PACKET_FREE(&auth_packet);
  491. DBG_RETURN(ret);
  492. }
  493. /* }}} */
  494. /* {{{ mysqlnd_command::handshake */
  495. static enum_func_status
  496. MYSQLND_METHOD(mysqlnd_command, handshake)(MYSQLND_CONN_DATA * const conn, const MYSQLND_CSTRING username, const MYSQLND_CSTRING password, const MYSQLND_CSTRING database, const size_t client_flags)
  497. {
  498. const char * const user = username.s;
  499. const char * const passwd = password.s;
  500. const size_t passwd_len = password.l;
  501. const char * const db = database.s;
  502. const size_t db_len = database.l;
  503. const size_t mysql_flags = client_flags;
  504. MYSQLND_PACKET_GREET greet_packet;
  505. DBG_ENTER("mysqlnd_command::handshake");
  506. DBG_INF_FMT("stream=%p", conn->vio->data->m.get_stream(conn->vio));
  507. DBG_INF_FMT("[user=%s] [db=%s:%zu] [flags=%zu]", user, db, db_len, mysql_flags);
  508. conn->payload_decoder_factory->m.init_greet_packet(&greet_packet);
  509. if (FAIL == PACKET_READ(conn, &greet_packet)) {
  510. DBG_ERR("Error while reading greeting packet");
  511. php_error_docref(NULL, E_WARNING, "Error while reading greeting packet. PID=%d", getpid());
  512. goto err;
  513. } else if (greet_packet.error_no) {
  514. DBG_ERR_FMT("errorno=%u error=%s", greet_packet.error_no, greet_packet.error);
  515. SET_CLIENT_ERROR(conn->error_info, greet_packet.error_no, greet_packet.sqlstate, greet_packet.error);
  516. goto err;
  517. } else if (greet_packet.pre41) {
  518. char * msg;
  519. mnd_sprintf(&msg, 0, "Connecting to 3.22, 3.23 & 4.0 is not supported. Server is %-.32s", greet_packet.server_version);
  520. DBG_ERR(msg);
  521. SET_CLIENT_ERROR(conn->error_info, CR_NOT_IMPLEMENTED, UNKNOWN_SQLSTATE, msg);
  522. mnd_sprintf_free(msg);
  523. goto err;
  524. }
  525. conn->thread_id = greet_packet.thread_id;
  526. conn->protocol_version = greet_packet.protocol_version;
  527. conn->server_version = mnd_pestrdup(greet_packet.server_version, conn->persistent);
  528. conn->greet_charset = mysqlnd_find_charset_nr(greet_packet.charset_no);
  529. if (!conn->greet_charset) {
  530. char * msg;
  531. mnd_sprintf(&msg, 0, "Server sent charset (%d) unknown to the client. Please, report to the developers", greet_packet.charset_no);
  532. SET_CLIENT_ERROR(conn->error_info, CR_NOT_IMPLEMENTED, UNKNOWN_SQLSTATE, msg);
  533. mnd_sprintf_free(msg);
  534. goto err;
  535. }
  536. conn->server_capabilities = greet_packet.server_capabilities;
  537. if (FAIL == mysqlnd_connect_run_authentication(conn, user, passwd, db, db_len, (size_t) passwd_len,
  538. greet_packet.authentication_plugin_data, greet_packet.auth_protocol,
  539. greet_packet.charset_no, greet_packet.server_capabilities,
  540. conn->options, mysql_flags))
  541. {
  542. goto err;
  543. }
  544. UPSERT_STATUS_RESET(conn->upsert_status);
  545. UPSERT_STATUS_SET_SERVER_STATUS(conn->upsert_status, greet_packet.server_status);
  546. PACKET_FREE(&greet_packet);
  547. DBG_RETURN(PASS);
  548. err:
  549. conn->server_capabilities = 0;
  550. PACKET_FREE(&greet_packet);
  551. DBG_RETURN(FAIL);
  552. }
  553. /* }}} */
  554. MYSQLND_CLASS_METHODS_START(mysqlnd_command)
  555. MYSQLND_METHOD(mysqlnd_command, set_option),
  556. MYSQLND_METHOD(mysqlnd_command, debug),
  557. MYSQLND_METHOD(mysqlnd_command, init_db),
  558. MYSQLND_METHOD(mysqlnd_command, ping),
  559. MYSQLND_METHOD(mysqlnd_command, statistics),
  560. MYSQLND_METHOD(mysqlnd_command, process_kill),
  561. MYSQLND_METHOD(mysqlnd_command, refresh),
  562. MYSQLND_METHOD(mysqlnd_command, shutdown),
  563. MYSQLND_METHOD(mysqlnd_command, quit),
  564. MYSQLND_METHOD(mysqlnd_command, query),
  565. MYSQLND_METHOD(mysqlnd_command, change_user),
  566. MYSQLND_METHOD(mysqlnd_command, reap_result),
  567. MYSQLND_METHOD(mysqlnd_command, stmt_prepare),
  568. MYSQLND_METHOD(mysqlnd_command, stmt_execute),
  569. MYSQLND_METHOD(mysqlnd_command, stmt_fetch),
  570. MYSQLND_METHOD(mysqlnd_command, stmt_reset),
  571. MYSQLND_METHOD(mysqlnd_command, stmt_send_long_data),
  572. MYSQLND_METHOD(mysqlnd_command, stmt_close),
  573. MYSQLND_METHOD(mysqlnd_command, enable_ssl),
  574. MYSQLND_METHOD(mysqlnd_command, handshake),
  575. MYSQLND_CLASS_METHODS_END;