1 /* Copyright (c) 2003, 2020, Oracle and/or its affiliates. All rights reserved.
2
3 This program is free software; you can redistribute it and/or modify
4 it under the terms of the GNU General Public License, version 2.0,
5 as published by the Free Software Foundation.
6
7 This program is also distributed with certain software (including
8 but not limited to OpenSSL) that is licensed under separate terms,
9 as designated in a particular file or component or in included license
10 documentation. The authors of MySQL hereby grant you an additional
11 permission to link the program and your derivative works with the
12 separately licensed software that they have included with MySQL.
13
14 Without limiting anything contained in the foregoing, this file,
15 which is part of C Driver for MySQL (Connector/C), is also subject to the
16 Universal FOSS Exception, version 1.0, a copy of which can be found at
17 http://oss.oracle.com/licenses/universal-foss-exception.
18
19 This program is distributed in the hope that it will be useful,
20 but WITHOUT ANY WARRANTY; without even the implied warranty of
21 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 GNU General Public License, version 2.0, for more details.
23
24 You should have received a copy of the GNU General Public License
25 along with this program; if not, write to the Free Software
26 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */
27
28 /*
29 This file is included by both libmysql.c (the MySQL client C API)
30 and the mysqld server to connect to another MYSQL server.
31
32 The differences for the two cases are:
33
34 - Things that only works for the client:
35 - Trying to automaticly determinate user name if not supplied to
36 mysql_real_connect()
37 - Support for reading local file with LOAD DATA LOCAL
38 - SHARED memory handling
39 - Prepared statements
40 - Things that only works for the server
41
42 In all other cases, the code should be idential for the client and
43 server.
44 */
45
46 #include <my_global.h>
47 #include "mysql.h"
48 #include "hash.h"
49 #include "mysql/client_authentication.h"
50
51 /* Remove client convenience wrappers */
52 #undef max_allowed_packet
53 #undef net_buffer_length
54
55 #ifdef EMBEDDED_LIBRARY
56
57 #undef MYSQL_SERVER
58
59 #ifndef MYSQL_CLIENT
60 #define MYSQL_CLIENT
61 #endif
62
63 #define CLI_MYSQL_REAL_CONNECT STDCALL cli_mysql_real_connect
64
65 #undef net_flush
66 my_bool net_flush(NET *net);
67
68 #else /*EMBEDDED_LIBRARY*/
69 #define CLI_MYSQL_REAL_CONNECT STDCALL mysql_real_connect
70 #endif /*EMBEDDED_LIBRARY*/
71
72 #include <my_sys.h>
73 #include "my_default.h"
74 #include <mysys_err.h>
75 #include <m_string.h>
76 #include <m_ctype.h>
77 #include "mysql_version.h"
78 #include "mysqld_error.h"
79 #include "errmsg.h"
80 #include <violite.h>
81
82 #if !defined(__WIN__)
83 #include <my_pthread.h> /* because of signal() */
84 #endif /* !defined(__WIN__) */
85
86 #include <sys/stat.h>
87 #include <signal.h>
88 #include <time.h>
89
90 #ifdef HAVE_PWD_H
91 #include <pwd.h>
92 #endif
93
94 #if !defined(__WIN__)
95 #ifdef HAVE_SELECT_H
96 # include <select.h>
97 #endif
98 #ifdef HAVE_SYS_SELECT_H
99 # include <sys/select.h>
100 #endif
101 #endif /* !defined(__WIN__) */
102
103 #ifdef HAVE_SYS_UN_H
104 # include <sys/un.h>
105 #endif
106
107 #ifndef _WIN32
108 #include <errno.h>
109 #define SOCKET_ERROR -1
110 #endif
111
112 #ifdef HAVE_OPENSSL
113 #include <openssl/x509v3.h>
114 #endif
115
116 #include "client_settings.h"
117 #include <sql_common.h>
118 #include <mysql/client_plugin.h>
119
120 #define native_password_plugin_name "mysql_native_password"
121 #define old_password_plugin_name "mysql_old_password"
122
123
124 uint mysql_port=0;
125 char *mysql_unix_port= 0;
126 const char *unknown_sqlstate= "HY000";
127 const char *not_error_sqlstate= "00000";
128 const char *cant_connect_sqlstate= "08001";
129 #ifdef HAVE_SMEM
130 char *shared_memory_base_name= 0;
131 const char *def_shared_memory_base_name= default_shared_memory_base_name;
132 #endif
133
134 static void mysql_close_free_options(MYSQL *mysql);
135 static void mysql_close_free(MYSQL *mysql);
136 static void mysql_prune_stmt_list(MYSQL *mysql);
137
138 CHARSET_INFO *default_client_charset_info = &my_charset_latin1;
139
140 /* Server error code and message */
141 unsigned int mysql_server_last_errno;
142 char mysql_server_last_error[MYSQL_ERRMSG_SIZE];
143
144 /**
145 Convert the connect timeout option to a timeout value for VIO
146 functions (vio_socket_connect() and vio_io_wait()).
147
148 @param mysql Connection handle (client side).
149
150 @return The timeout value in milliseconds, or -1 if no timeout.
151 */
152
get_vio_connect_timeout(MYSQL * mysql)153 static int get_vio_connect_timeout(MYSQL *mysql)
154 {
155 int timeout_ms;
156 uint timeout_sec;
157
158 /*
159 A timeout of 0 means no timeout. Also, the connect_timeout
160 option value is in seconds, while VIO timeouts are measured
161 in milliseconds. Hence, check for a possible overflow. In
162 case of overflow, set to no timeout.
163 */
164 timeout_sec= mysql->options.connect_timeout;
165
166 if (!timeout_sec || (timeout_sec > INT_MAX/1000))
167 timeout_ms= -1;
168 else
169 timeout_ms= (int) (timeout_sec * 1000);
170
171 return timeout_ms;
172 }
173
174
175 #ifdef _WIN32
176
177 /**
178 Convert the connect timeout option to a timeout value for WIN32
179 synchronization functions.
180
181 @remark Specific for WIN32 connection methods shared memory and
182 named pipe.
183
184 @param mysql Connection handle (client side).
185
186 @return The timeout value in milliseconds, or INFINITE if no timeout.
187 */
188
get_win32_connect_timeout(MYSQL * mysql)189 static DWORD get_win32_connect_timeout(MYSQL *mysql)
190 {
191 DWORD timeout_ms;
192 uint timeout_sec;
193
194 /*
195 A timeout of 0 means no timeout. Also, the connect_timeout
196 option value is in seconds, while WIN32 timeouts are in
197 milliseconds. Hence, check for a possible overflow. In case
198 of overflow, set to no timeout.
199 */
200 timeout_sec= mysql->options.connect_timeout;
201
202 if (!timeout_sec || (timeout_sec > INT_MAX/1000))
203 timeout_ms= INFINITE;
204 else
205 timeout_ms= (DWORD) (timeout_sec * 1000);
206
207 return timeout_ms;
208 }
209
210 #endif
211
212
213 /**
214 Set the internal error message to mysql handler
215
216 @param mysql connection handle (client side)
217 @param errcode CR_ error code, passed to ER macro to get
218 error text
219 @parma sqlstate SQL standard sqlstate
220 */
221
set_mysql_error(MYSQL * mysql,int errcode,const char * sqlstate)222 void set_mysql_error(MYSQL *mysql, int errcode, const char *sqlstate)
223 {
224 NET *net;
225 DBUG_ENTER("set_mysql_error");
226 DBUG_PRINT("enter", ("error :%d '%s'", errcode, ER(errcode)));
227 DBUG_ASSERT(mysql != 0);
228
229 if (mysql)
230 {
231 net= &mysql->net;
232 net->last_errno= errcode;
233 strmov(net->last_error, ER(errcode));
234 strmov(net->sqlstate, sqlstate);
235 }
236 else
237 {
238 mysql_server_last_errno= errcode;
239 strmov(mysql_server_last_error, ER(errcode));
240 }
241 DBUG_VOID_RETURN;
242 }
243
244 /**
245 Is this NET instance initialized?
246 @c my_net_init() and net_end()
247 */
248
my_net_is_inited(NET * net)249 my_bool my_net_is_inited(NET *net)
250 {
251 return net->buff != NULL;
252 }
253
254 /**
255 Clear possible error state of struct NET
256
257 @param net clear the state of the argument
258 */
259
net_clear_error(NET * net)260 void net_clear_error(NET *net)
261 {
262 net->last_errno= 0;
263 net->last_error[0]= '\0';
264 strmov(net->sqlstate, not_error_sqlstate);
265 }
266
267 /**
268 Set an error message on the client.
269
270 @param mysql connection handle
271 @param errcode CR_* errcode, for client errors
272 @param sqlstate SQL standard sql state, unknown_sqlstate for the
273 majority of client errors.
274 @param format error message template, in sprintf format
275 @param ... variable number of arguments
276 */
277
set_mysql_extended_error(MYSQL * mysql,int errcode,const char * sqlstate,const char * format,...)278 void set_mysql_extended_error(MYSQL *mysql, int errcode,
279 const char *sqlstate,
280 const char *format, ...)
281 {
282 NET *net;
283 va_list args;
284 DBUG_ENTER("set_mysql_extended_error");
285 DBUG_PRINT("enter", ("error :%d '%s'", errcode, format));
286 DBUG_ASSERT(mysql != 0);
287
288 net= &mysql->net;
289 net->last_errno= errcode;
290 va_start(args, format);
291 my_vsnprintf(net->last_error, sizeof(net->last_error)-1,
292 format, args);
293 va_end(args);
294 strmov(net->sqlstate, sqlstate);
295
296 DBUG_VOID_RETURN;
297 }
298
299
300
301 /*
302 Create a named pipe connection
303 */
304
305 #ifdef _WIN32
306
create_named_pipe(MYSQL * mysql,DWORD connect_timeout,const char ** arg_host,const char ** arg_unix_socket)307 static HANDLE create_named_pipe(MYSQL *mysql, DWORD connect_timeout,
308 const char **arg_host,
309 const char **arg_unix_socket)
310 {
311 HANDLE hPipe=INVALID_HANDLE_VALUE;
312 char pipe_name[1024];
313 DWORD dwMode;
314 int i;
315 my_bool testing_named_pipes=0;
316 const char *host= *arg_host, *unix_socket= *arg_unix_socket;
317
318 if ( ! unix_socket || (unix_socket)[0] == 0x00)
319 unix_socket = mysql_unix_port;
320 if (!host || !strcmp(host,LOCAL_HOST))
321 host=LOCAL_HOST_NAMEDPIPE;
322
323
324 pipe_name[sizeof(pipe_name)-1]= 0; /* Safety if too long string */
325 strxnmov(pipe_name, sizeof(pipe_name)-1, "\\\\", host, "\\pipe\\",
326 unix_socket, NullS);
327 DBUG_PRINT("info",("Server name: '%s'. Named Pipe: %s", host, unix_socket));
328
329 for (i=0 ; i < 100 ; i++) /* Don't retry forever */
330 {
331 if ((hPipe = CreateFile(pipe_name,
332 FILE_READ_ATTRIBUTES | FILE_READ_DATA |
333 FILE_WRITE_ATTRIBUTES | FILE_WRITE_DATA,
334 0,
335 NULL,
336 OPEN_EXISTING,
337 FILE_FLAG_OVERLAPPED,
338 NULL )) != INVALID_HANDLE_VALUE)
339 break;
340 if (GetLastError() != ERROR_PIPE_BUSY)
341 {
342 set_mysql_extended_error(mysql, CR_NAMEDPIPEOPEN_ERROR,
343 unknown_sqlstate, ER(CR_NAMEDPIPEOPEN_ERROR),
344 host, unix_socket, (ulong) GetLastError());
345 return INVALID_HANDLE_VALUE;
346 }
347 /* wait for for an other instance */
348 if (!WaitNamedPipe(pipe_name, connect_timeout))
349 {
350 set_mysql_extended_error(mysql, CR_NAMEDPIPEWAIT_ERROR, unknown_sqlstate,
351 ER(CR_NAMEDPIPEWAIT_ERROR),
352 host, unix_socket, (ulong) GetLastError());
353 return INVALID_HANDLE_VALUE;
354 }
355 }
356 if (hPipe == INVALID_HANDLE_VALUE)
357 {
358 set_mysql_extended_error(mysql, CR_NAMEDPIPEOPEN_ERROR, unknown_sqlstate,
359 ER(CR_NAMEDPIPEOPEN_ERROR), host, unix_socket,
360 (ulong) GetLastError());
361 return INVALID_HANDLE_VALUE;
362 }
363 dwMode = PIPE_READMODE_BYTE | PIPE_WAIT;
364 if ( !SetNamedPipeHandleState(hPipe, &dwMode, NULL, NULL) )
365 {
366 CloseHandle( hPipe );
367 set_mysql_extended_error(mysql, CR_NAMEDPIPESETSTATE_ERROR,
368 unknown_sqlstate, ER(CR_NAMEDPIPESETSTATE_ERROR),
369 host, unix_socket, (ulong) GetLastError());
370 return INVALID_HANDLE_VALUE;
371 }
372 *arg_host=host ; *arg_unix_socket=unix_socket; /* connect arg */
373 return (hPipe);
374 }
375 #endif
376
377
378 /*
379 Create new shared memory connection, return handler of connection
380
381 @param mysql Pointer of mysql structure
382 @param net Pointer of net structure
383 @param connect_timeout Timeout of connection (in milliseconds)
384
385 @return HANDLE to the shared memory area.
386 */
387
388 #ifdef HAVE_SMEM
create_shared_memory(MYSQL * mysql,NET * net,DWORD connect_timeout)389 static HANDLE create_shared_memory(MYSQL *mysql, NET *net,
390 DWORD connect_timeout)
391 {
392 ulong smem_buffer_length = shared_memory_buffer_length + 4;
393 /*
394 event_connect_request is event object for start connection actions
395 event_connect_answer is event object for confirm, that server put data
396 handle_connect_file_map is file-mapping object, use for create shared
397 memory
398 handle_connect_map is pointer on shared memory
399 handle_map is pointer on shared memory for client
400 event_server_wrote,
401 event_server_read,
402 event_client_wrote,
403 event_client_read are events for transfer data between server and client
404 handle_file_map is file-mapping object, use for create shared memory
405 */
406 HANDLE event_connect_request = NULL;
407 HANDLE event_connect_answer = NULL;
408 HANDLE handle_connect_file_map = NULL;
409 char *handle_connect_map = NULL;
410
411 char *handle_map = NULL;
412 HANDLE event_server_wrote = NULL;
413 HANDLE event_server_read = NULL;
414 HANDLE event_client_wrote = NULL;
415 HANDLE event_client_read = NULL;
416 HANDLE event_conn_closed = NULL;
417 HANDLE handle_file_map = NULL;
418 ulong connect_number;
419 char connect_number_char[22], *p;
420 char *tmp= NULL;
421 char *suffix_pos;
422 DWORD error_allow = 0;
423 DWORD error_code = 0;
424 DWORD event_access_rights= SYNCHRONIZE | EVENT_MODIFY_STATE;
425 char *shared_memory_base_name = mysql->options.shared_memory_base_name;
426 static const char *name_prefixes[] = {"","Global\\"};
427 const char *prefix;
428 int i;
429
430 /*
431 If this is NULL, somebody freed the MYSQL* options. mysql_close()
432 is a good candidate. We don't just silently (re)set it to
433 def_shared_memory_base_name as that would create really confusing/buggy
434 behavior if the user passed in a different name on the command-line or
435 in a my.cnf.
436 */
437 DBUG_ASSERT(shared_memory_base_name != NULL);
438
439 /*
440 get enough space base-name + '_' + longest suffix we might ever send
441 */
442 if (!(tmp= (char *)my_malloc(strlen(shared_memory_base_name) + 32L, MYF(MY_FAE))))
443 goto err;
444
445 /*
446 The name of event and file-mapping events create agree next rule:
447 shared_memory_base_name+unique_part
448 Where:
449 shared_memory_base_name is unique value for each server
450 unique_part is uniquel value for each object (events and file-mapping)
451 */
452 for (i = 0; i< array_elements(name_prefixes); i++)
453 {
454 prefix= name_prefixes[i];
455 suffix_pos = strxmov(tmp, prefix , shared_memory_base_name, "_", NullS);
456 strmov(suffix_pos, "CONNECT_REQUEST");
457 event_connect_request= OpenEvent(event_access_rights, FALSE, tmp);
458 if (event_connect_request)
459 {
460 break;
461 }
462 }
463 if (!event_connect_request)
464 {
465 error_allow = CR_SHARED_MEMORY_CONNECT_REQUEST_ERROR;
466 goto err;
467 }
468 strmov(suffix_pos, "CONNECT_ANSWER");
469 if (!(event_connect_answer= OpenEvent(event_access_rights,FALSE,tmp)))
470 {
471 error_allow = CR_SHARED_MEMORY_CONNECT_ANSWER_ERROR;
472 goto err;
473 }
474 strmov(suffix_pos, "CONNECT_DATA");
475 if (!(handle_connect_file_map= OpenFileMapping(FILE_MAP_WRITE,FALSE,tmp)))
476 {
477 error_allow = CR_SHARED_MEMORY_CONNECT_FILE_MAP_ERROR;
478 goto err;
479 }
480 if (!(handle_connect_map= MapViewOfFile(handle_connect_file_map,
481 FILE_MAP_WRITE,0,0,sizeof(DWORD))))
482 {
483 error_allow = CR_SHARED_MEMORY_CONNECT_MAP_ERROR;
484 goto err;
485 }
486
487 /* Send to server request of connection */
488 if (!SetEvent(event_connect_request))
489 {
490 error_allow = CR_SHARED_MEMORY_CONNECT_SET_ERROR;
491 goto err;
492 }
493
494 /* Wait of answer from server */
495 if (WaitForSingleObject(event_connect_answer, connect_timeout) !=
496 WAIT_OBJECT_0)
497 {
498 error_allow = CR_SHARED_MEMORY_CONNECT_ABANDONED_ERROR;
499 goto err;
500 }
501
502 /* Get number of connection */
503 connect_number = uint4korr(handle_connect_map);/*WAX2*/
504 p= int10_to_str(connect_number, connect_number_char, 10);
505
506 /*
507 The name of event and file-mapping events create agree next rule:
508 shared_memory_base_name+unique_part+number_of_connection
509
510 Where:
511 shared_memory_base_name is uniquel value for each server
512 unique_part is uniquel value for each object (events and file-mapping)
513 number_of_connection is number of connection between server and client
514 */
515 suffix_pos = strxmov(tmp, prefix , shared_memory_base_name, "_", connect_number_char,
516 "_", NullS);
517 strmov(suffix_pos, "DATA");
518 if ((handle_file_map = OpenFileMapping(FILE_MAP_WRITE,FALSE,tmp)) == NULL)
519 {
520 error_allow = CR_SHARED_MEMORY_FILE_MAP_ERROR;
521 goto err2;
522 }
523 if ((handle_map = MapViewOfFile(handle_file_map,FILE_MAP_WRITE,0,0,
524 smem_buffer_length)) == NULL)
525 {
526 error_allow = CR_SHARED_MEMORY_MAP_ERROR;
527 goto err2;
528 }
529
530 strmov(suffix_pos, "SERVER_WROTE");
531 if ((event_server_wrote = OpenEvent(event_access_rights,FALSE,tmp)) == NULL)
532 {
533 error_allow = CR_SHARED_MEMORY_EVENT_ERROR;
534 goto err2;
535 }
536
537 strmov(suffix_pos, "SERVER_READ");
538 if ((event_server_read = OpenEvent(event_access_rights,FALSE,tmp)) == NULL)
539 {
540 error_allow = CR_SHARED_MEMORY_EVENT_ERROR;
541 goto err2;
542 }
543
544 strmov(suffix_pos, "CLIENT_WROTE");
545 if ((event_client_wrote = OpenEvent(event_access_rights,FALSE,tmp)) == NULL)
546 {
547 error_allow = CR_SHARED_MEMORY_EVENT_ERROR;
548 goto err2;
549 }
550
551 strmov(suffix_pos, "CLIENT_READ");
552 if ((event_client_read = OpenEvent(event_access_rights,FALSE,tmp)) == NULL)
553 {
554 error_allow = CR_SHARED_MEMORY_EVENT_ERROR;
555 goto err2;
556 }
557
558 strmov(suffix_pos, "CONNECTION_CLOSED");
559 if ((event_conn_closed = OpenEvent(event_access_rights,FALSE,tmp)) == NULL)
560 {
561 error_allow = CR_SHARED_MEMORY_EVENT_ERROR;
562 goto err2;
563 }
564 /*
565 Set event that server should send data
566 */
567 SetEvent(event_server_read);
568
569 err2:
570 if (error_allow == 0)
571 {
572 net->vio= vio_new_win32shared_memory(handle_file_map,handle_map,
573 event_server_wrote,
574 event_server_read,event_client_wrote,
575 event_client_read,event_conn_closed);
576 }
577 else
578 {
579 error_code = GetLastError();
580 if (event_server_read)
581 CloseHandle(event_server_read);
582 if (event_server_wrote)
583 CloseHandle(event_server_wrote);
584 if (event_client_read)
585 CloseHandle(event_client_read);
586 if (event_client_wrote)
587 CloseHandle(event_client_wrote);
588 if (event_conn_closed)
589 CloseHandle(event_conn_closed);
590 if (handle_map)
591 UnmapViewOfFile(handle_map);
592 if (handle_file_map)
593 CloseHandle(handle_file_map);
594 }
595 err:
596 my_free(tmp);
597 if (error_allow)
598 error_code = GetLastError();
599 if (event_connect_request)
600 CloseHandle(event_connect_request);
601 if (event_connect_answer)
602 CloseHandle(event_connect_answer);
603 if (handle_connect_map)
604 UnmapViewOfFile(handle_connect_map);
605 if (handle_connect_file_map)
606 CloseHandle(handle_connect_file_map);
607 if (error_allow)
608 {
609 if (error_allow == CR_SHARED_MEMORY_EVENT_ERROR)
610 set_mysql_extended_error(mysql, error_allow, unknown_sqlstate,
611 ER(error_allow), suffix_pos, error_code);
612 else
613 set_mysql_extended_error(mysql, error_allow, unknown_sqlstate,
614 ER(error_allow), error_code);
615 return(INVALID_HANDLE_VALUE);
616 }
617 return(handle_map);
618 }
619 #endif
620
621 /**
622 Read a packet from server. Give error message if socket was down
623 or packet is an error message
624
625 @retval packet_error An error occurred during reading.
626 Error message is set.
627 @retval
628 */
629
630 ulong
cli_safe_read(MYSQL * mysql)631 cli_safe_read(MYSQL *mysql)
632 {
633 NET *net= &mysql->net;
634 ulong len=0;
635
636 if (net->vio != 0)
637 len=my_net_read(net);
638
639 if (len == packet_error || len == 0)
640 {
641 DBUG_PRINT("error",("Wrong connection or packet. fd: %s len: %lu",
642 vio_description(net->vio),len));
643 #ifdef MYSQL_SERVER
644 if (net->vio && (net->last_errno == ER_NET_READ_INTERRUPTED))
645 return (packet_error);
646 #endif /*MYSQL_SERVER*/
647 end_server(mysql);
648 set_mysql_error(mysql, net->last_errno == ER_NET_PACKET_TOO_LARGE ?
649 CR_NET_PACKET_TOO_LARGE: CR_SERVER_LOST, unknown_sqlstate);
650 return (packet_error);
651 }
652 if (net->read_pos[0] == 255)
653 {
654 if (len > 3)
655 {
656 char *pos=(char*) net->read_pos+1;
657 net->last_errno=uint2korr(pos);
658 pos+=2;
659 len-=2;
660 if (protocol_41(mysql) && pos[0] == '#')
661 {
662 strmake(net->sqlstate, pos+1, SQLSTATE_LENGTH);
663 pos+= SQLSTATE_LENGTH+1;
664 }
665 else
666 {
667 /*
668 The SQL state hasn't been received -- it should be reset to HY000
669 (unknown error sql state).
670 */
671
672 strmov(net->sqlstate, unknown_sqlstate);
673 }
674
675 (void) strmake(net->last_error,(char*) pos,
676 MY_MIN((uint) len,(uint) sizeof(net->last_error)-1));
677 }
678 else
679 set_mysql_error(mysql, CR_UNKNOWN_ERROR, unknown_sqlstate);
680 /*
681 Cover a protocol design error: error packet does not
682 contain the server status. Therefore, the client has no way
683 to find out whether there are more result sets of
684 a multiple-result-set statement pending. Luckily, in 5.0 an
685 error always aborts execution of a statement, wherever it is
686 a multi-statement or a stored procedure, so it should be
687 safe to unconditionally turn off the flag here.
688 */
689 mysql->server_status&= ~SERVER_MORE_RESULTS_EXISTS;
690
691 DBUG_PRINT("error",("Got error: %d/%s (%s)",
692 net->last_errno,
693 net->sqlstate,
694 net->last_error));
695 return(packet_error);
696 }
697 return len;
698 }
699
free_rows(MYSQL_DATA * cur)700 void free_rows(MYSQL_DATA *cur)
701 {
702 if (cur)
703 {
704 free_root(&cur->alloc,MYF(0));
705 my_free(cur);
706 }
707 }
708
709 my_bool
cli_advanced_command(MYSQL * mysql,enum enum_server_command command,const uchar * header,ulong header_length,const uchar * arg,ulong arg_length,my_bool skip_check,MYSQL_STMT * stmt)710 cli_advanced_command(MYSQL *mysql, enum enum_server_command command,
711 const uchar *header, ulong header_length,
712 const uchar *arg, ulong arg_length, my_bool skip_check,
713 MYSQL_STMT *stmt)
714 {
715 NET *net= &mysql->net;
716 my_bool result= 1;
717 my_bool stmt_skip= stmt ? stmt->state != MYSQL_STMT_INIT_DONE : FALSE;
718 DBUG_ENTER("cli_advanced_command");
719
720 if (mysql->net.vio == 0)
721 { /* Do reconnect if possible */
722 if (mysql_reconnect(mysql) || stmt_skip)
723 DBUG_RETURN(1);
724 }
725 if (mysql->status != MYSQL_STATUS_READY ||
726 mysql->server_status & SERVER_MORE_RESULTS_EXISTS)
727 {
728 DBUG_PRINT("error",("state: %d", mysql->status));
729 set_mysql_error(mysql, CR_COMMANDS_OUT_OF_SYNC, unknown_sqlstate);
730 DBUG_RETURN(1);
731 }
732
733 net_clear_error(net);
734 mysql->info=0;
735 mysql->affected_rows= ~(my_ulonglong) 0;
736 /*
737 Do not check the socket/protocol buffer on COM_QUIT as the
738 result of a previous command might not have been read. This
739 can happen if a client sends a query but does not reap the
740 result before attempting to close the connection.
741 */
742 net_clear(&mysql->net, (command != COM_QUIT));
743
744 #if !defined(EMBEDDED_LIBRARY)
745 /*
746 If auto-reconnect mode is enabled check if connection is still alive before
747 sending new command. Otherwise, send() might not notice that connection was
748 closed by the server (for example, due to KILL statement), and the fact that
749 connection is gone will be noticed only on attempt to read command's result,
750 when it is too late to reconnect. Note that such scenario can still occur if
751 connection gets killed after this check but before command is sent to
752 server. But this should be rare.
753 */
754 if ((command != COM_QUIT) && mysql->reconnect && !vio_is_connected(net->vio))
755 net->error= 2;
756 #endif
757
758 if (net_write_command(net,(uchar) command, header, header_length,
759 arg, arg_length))
760 {
761 DBUG_PRINT("error",("Can't send command to server. Error: %d",
762 socket_errno));
763 if (net->last_errno == ER_NET_PACKET_TOO_LARGE)
764 {
765 set_mysql_error(mysql, CR_NET_PACKET_TOO_LARGE, unknown_sqlstate);
766 goto end;
767 }
768 end_server(mysql);
769 if (mysql_reconnect(mysql) || stmt_skip)
770 goto end;
771 if (net_write_command(net,(uchar) command, header, header_length,
772 arg, arg_length))
773 {
774 set_mysql_error(mysql, CR_SERVER_GONE_ERROR, unknown_sqlstate);
775 goto end;
776 }
777 }
778 result=0;
779 if (!skip_check)
780 result= ((mysql->packet_length=cli_safe_read(mysql)) == packet_error ?
781 1 : 0);
782 end:
783 DBUG_PRINT("exit",("result: %d", result));
784 DBUG_RETURN(result);
785 }
786
free_old_query(MYSQL * mysql)787 void free_old_query(MYSQL *mysql)
788 {
789 DBUG_ENTER("free_old_query");
790 if (mysql->fields)
791 free_root(&mysql->field_alloc,MYF(0));
792 init_alloc_root(&mysql->field_alloc,8192,0); /* Assume rowlength < 8192 */
793 mysql->fields= 0;
794 mysql->field_count= 0; /* For API */
795 mysql->warning_count= 0;
796 mysql->info= 0;
797 DBUG_VOID_RETURN;
798 }
799
800
801 /**
802 Finish reading of a partial result set from the server.
803 Get the EOF packet, and update mysql->status
804 and mysql->warning_count.
805
806 @return TRUE if a communication or protocol error, an error
807 is set in this case, FALSE otherwise.
808 */
809
flush_one_result(MYSQL * mysql)810 my_bool flush_one_result(MYSQL *mysql)
811 {
812 ulong packet_length;
813
814 DBUG_ASSERT(mysql->status != MYSQL_STATUS_READY);
815
816 do
817 {
818 packet_length= cli_safe_read(mysql);
819 /*
820 There is an error reading from the connection,
821 or (sic!) there were no error and no
822 data in the stream, i.e. no more data from the server.
823 Since we know our position in the stream (somewhere in
824 the middle of a result set), this latter case is an error too
825 -- each result set must end with a EOF packet.
826 cli_safe_read() has set an error for us, just return.
827 */
828 if (packet_length == packet_error)
829 return TRUE;
830 }
831 while (packet_length > 8 || mysql->net.read_pos[0] != 254);
832
833 /* Analyze EOF packet of the result set. */
834
835 if (protocol_41(mysql))
836 {
837 char *pos= (char*) mysql->net.read_pos + 1;
838 mysql->warning_count=uint2korr(pos);
839 pos+=2;
840 mysql->server_status=uint2korr(pos);
841 pos+=2;
842 }
843 return FALSE;
844 }
845
846
847 /**
848 Read a packet from network. If it's an OK packet, flush it.
849
850 @return TRUE if error, FALSE otherwise. In case of
851 success, is_ok_packet is set to TRUE or FALSE,
852 based on what we got from network.
853 */
854
opt_flush_ok_packet(MYSQL * mysql,my_bool * is_ok_packet)855 my_bool opt_flush_ok_packet(MYSQL *mysql, my_bool *is_ok_packet)
856 {
857 ulong packet_length= cli_safe_read(mysql);
858
859 if (packet_length == packet_error)
860 return TRUE;
861
862 /* cli_safe_read always reads a non-empty packet. */
863 DBUG_ASSERT(packet_length);
864
865 *is_ok_packet= mysql->net.read_pos[0] == 0;
866 if (*is_ok_packet)
867 {
868 uchar *pos= mysql->net.read_pos + 1;
869
870 net_field_length_ll(&pos); /* affected rows */
871 net_field_length_ll(&pos); /* insert id */
872
873 mysql->server_status=uint2korr(pos);
874 pos+=2;
875
876 if (protocol_41(mysql))
877 {
878 mysql->warning_count=uint2korr(pos);
879 pos+=2;
880 }
881 }
882 return FALSE;
883 }
884
885
886 /*
887 Flush result set sent from server
888 */
889
cli_flush_use_result(MYSQL * mysql,my_bool flush_all_results)890 static void cli_flush_use_result(MYSQL *mysql, my_bool flush_all_results)
891 {
892 /* Clear the current execution status */
893 DBUG_ENTER("cli_flush_use_result");
894 DBUG_PRINT("warning",("Not all packets read, clearing them"));
895
896 if (flush_one_result(mysql))
897 DBUG_VOID_RETURN; /* An error occurred */
898
899 if (! flush_all_results)
900 DBUG_VOID_RETURN;
901
902 while (mysql->server_status & SERVER_MORE_RESULTS_EXISTS)
903 {
904 my_bool is_ok_packet;
905 if (opt_flush_ok_packet(mysql, &is_ok_packet))
906 DBUG_VOID_RETURN; /* An error occurred. */
907 if (is_ok_packet)
908 {
909 /*
910 Indeed what we got from network was an OK packet, and we
911 know that OK is the last one in a multi-result-set, so
912 just return.
913 */
914 DBUG_VOID_RETURN;
915 }
916 /*
917 It's a result set, not an OK packet. A result set contains
918 of two result set subsequences: field metadata, terminated
919 with EOF packet, and result set data, again terminated with
920 EOF packet. Read and flush them.
921 */
922 if (flush_one_result(mysql) || flush_one_result(mysql))
923 DBUG_VOID_RETURN; /* An error occurred. */
924 }
925
926 DBUG_VOID_RETURN;
927 }
928
929
930 #ifdef __WIN__
is_NT(void)931 static my_bool is_NT(void)
932 {
933 char *os=getenv("OS");
934 return (os && !strcmp(os, "Windows_NT")) ? 1 : 0;
935 }
936 #endif
937
938
939 #ifdef CHECK_LICENSE
940 /**
941 Check server side variable 'license'.
942
943 If the variable does not exist or does not contain 'Commercial',
944 we're talking to non-commercial server from commercial client.
945
946 @retval 0 success
947 @retval !0 network error or the server is not commercial.
948 Error code is saved in mysql->net.last_errno.
949 */
950
check_license(MYSQL * mysql)951 static int check_license(MYSQL *mysql)
952 {
953 MYSQL_ROW row;
954 MYSQL_RES *res;
955 NET *net= &mysql->net;
956 static const char query[]= "SELECT @@license";
957 static const char required_license[]= STRINGIFY_ARG(LICENSE);
958
959 if (mysql_real_query(mysql, query, sizeof(query)-1))
960 {
961 if (net->last_errno == ER_UNKNOWN_SYSTEM_VARIABLE)
962 {
963 set_mysql_extended_error(mysql, CR_WRONG_LICENSE, unknown_sqlstate,
964 ER(CR_WRONG_LICENSE), required_license);
965 }
966 return 1;
967 }
968 if (!(res= mysql_use_result(mysql)))
969 return 1;
970 row= mysql_fetch_row(res);
971 /*
972 If no rows in result set, or column value is NULL (none of these
973 two is ever true for server variables now), or column value
974 mismatch, set wrong license error.
975 */
976 if (!net->last_errno &&
977 (!row || !row[0] ||
978 strncmp(row[0], required_license, sizeof(required_license))))
979 {
980 set_mysql_extended_error(mysql, CR_WRONG_LICENSE, unknown_sqlstate,
981 ER(CR_WRONG_LICENSE), required_license);
982 }
983 mysql_free_result(res);
984 return net->last_errno;
985 }
986 #endif /* CHECK_LICENSE */
987
988
989 /**************************************************************************
990 Shut down connection
991 **************************************************************************/
992
end_server(MYSQL * mysql)993 void end_server(MYSQL *mysql)
994 {
995 int save_errno= errno;
996 DBUG_ENTER("end_server");
997 if (mysql->net.vio != 0)
998 {
999 DBUG_PRINT("info",("Net: %s", vio_description(mysql->net.vio)));
1000 #ifdef MYSQL_SERVER
1001 slave_io_thread_detach_vio();
1002 #endif
1003 vio_delete(mysql->net.vio);
1004 mysql->net.vio= 0; /* Marker */
1005 mysql_prune_stmt_list(mysql);
1006 }
1007 net_end(&mysql->net);
1008 free_old_query(mysql);
1009 errno= save_errno;
1010 DBUG_VOID_RETURN;
1011 }
1012
1013
1014 void STDCALL
mysql_free_result(MYSQL_RES * result)1015 mysql_free_result(MYSQL_RES *result)
1016 {
1017 DBUG_ENTER("mysql_free_result");
1018 DBUG_PRINT("enter",("mysql_res: 0x%lx", (long) result));
1019 if (result)
1020 {
1021 MYSQL *mysql= result->handle;
1022 if (mysql)
1023 {
1024 if (mysql->unbuffered_fetch_owner == &result->unbuffered_fetch_cancelled)
1025 mysql->unbuffered_fetch_owner= 0;
1026 if (mysql->status == MYSQL_STATUS_USE_RESULT)
1027 {
1028 (*mysql->methods->flush_use_result)(mysql, FALSE);
1029 mysql->status=MYSQL_STATUS_READY;
1030 if (mysql->unbuffered_fetch_owner)
1031 *mysql->unbuffered_fetch_owner= TRUE;
1032 }
1033 }
1034 free_rows(result->data);
1035 if (result->fields)
1036 free_root(&result->field_alloc,MYF(0));
1037 my_free(result->row);
1038 my_free(result);
1039 }
1040 DBUG_VOID_RETURN;
1041 }
1042
1043 /****************************************************************************
1044 Get options from my.cnf
1045 ****************************************************************************/
1046
1047 static const char *default_options[]=
1048 {
1049 "port","socket","compress","password","pipe", "timeout", "user",
1050 "init-command", "host", "database", "debug", "return-found-rows",
1051 "ssl-key" ,"ssl-cert" ,"ssl-ca" ,"ssl-capath",
1052 "character-sets-dir", "default-character-set", "interactive-timeout",
1053 "connect-timeout", "local-infile", "disable-local-infile",
1054 "ssl-cipher", "max-allowed-packet", "protocol", "shared-memory-base-name",
1055 "multi-results", "multi-statements", "multi-queries", "secure-auth",
1056 "report-data-truncation", "plugin-dir", "default-auth",
1057 "bind-address", "ssl-crl", "ssl-crlpath", "enable-cleartext-plugin",
1058 "ssl-mode",
1059 NullS
1060 };
1061 enum option_id {
1062 OPT_port=1, OPT_socket, OPT_compress, OPT_password, OPT_pipe, OPT_timeout, OPT_user,
1063 OPT_init_command, OPT_host, OPT_database, OPT_debug, OPT_return_found_rows,
1064 OPT_ssl_key, OPT_ssl_cert, OPT_ssl_ca, OPT_ssl_capath,
1065 OPT_character_sets_dir, OPT_default_character_set, OPT_interactive_timeout,
1066 OPT_connect_timeout, OPT_local_infile, OPT_disable_local_infile,
1067 OPT_ssl_cipher, OPT_max_allowed_packet, OPT_protocol, OPT_shared_memory_base_name,
1068 OPT_multi_results, OPT_multi_statements, OPT_multi_queries, OPT_secure_auth,
1069 OPT_report_data_truncation, OPT_plugin_dir, OPT_default_auth,
1070 OPT_bind_address, OPT_ssl_crl, OPT_ssl_crlpath, OPT_enable_cleartext_plugin,
1071 OPT_ssl_mode,
1072 OPT_keep_this_one_last
1073 };
1074
1075 static TYPELIB option_types={array_elements(default_options)-1,
1076 "options",default_options, NULL};
1077
1078 const char *sql_protocol_names_lib[] =
1079 { "TCP", "SOCKET", "PIPE", "MEMORY", NullS };
1080 TYPELIB sql_protocol_typelib = {array_elements(sql_protocol_names_lib)-1,"",
1081 sql_protocol_names_lib, NULL};
1082
add_init_command(struct st_mysql_options * options,const char * cmd)1083 static int add_init_command(struct st_mysql_options *options, const char *cmd)
1084 {
1085 char *tmp;
1086
1087 if (!options->init_commands)
1088 {
1089 options->init_commands= (DYNAMIC_ARRAY*)my_malloc(sizeof(DYNAMIC_ARRAY),
1090 MYF(MY_WME));
1091 init_dynamic_array(options->init_commands,sizeof(char*),0,5);
1092 }
1093
1094 if (!(tmp= my_strdup(cmd,MYF(MY_WME))) ||
1095 insert_dynamic(options->init_commands, &tmp))
1096 {
1097 my_free(tmp);
1098 return 1;
1099 }
1100
1101 return 0;
1102 }
1103
1104 #define ALLOCATE_EXTENSIONS(OPTS) \
1105 (OPTS)->extension= (struct st_mysql_options_extention *) \
1106 my_malloc(sizeof(struct st_mysql_options_extention), \
1107 MYF(MY_WME | MY_ZEROFILL)) \
1108
1109 #define ENSURE_EXTENSIONS_PRESENT(OPTS) \
1110 do { \
1111 if (!(OPTS)->extension) \
1112 ALLOCATE_EXTENSIONS(OPTS); \
1113 } while (0)
1114
1115
1116 #define EXTENSION_SET_STRING(OPTS, X, STR) \
1117 do { \
1118 if ((OPTS)->extension) \
1119 my_free((OPTS)->extension->X); \
1120 else \
1121 ALLOCATE_EXTENSIONS(OPTS); \
1122 (OPTS)->extension->X= ((STR) != NULL) ? \
1123 my_strdup((STR), MYF(MY_WME)) : NULL; \
1124 } while (0)
1125
1126 #if defined(HAVE_OPENSSL) && !defined(EMBEDDED_LIBRARY)
1127 #define SET_SSL_OPTION(opt_var,arg) \
1128 if (mysql->options.opt_var) \
1129 my_free(mysql->options.opt_var); \
1130 mysql->options.opt_var= arg ? my_strdup(arg, MYF(MY_WME)) : NULL; \
1131 if (mysql->options.opt_var) \
1132 mysql->options.use_ssl= 1
1133 #define EXTENSION_SET_SSL_STRING(OPTS, X, STR) \
1134 EXTENSION_SET_STRING(OPTS, X, STR); \
1135 if ((OPTS)->extension->X) \
1136 (OPTS)->use_ssl= 1
1137
1138
1139 #else
1140 #define SET_SSL_OPTION(opt_var,arg) \
1141 do { \
1142 ; \
1143 } while(0)
1144 #define EXTENSION_SET_SSL_STRING(OPTS, X, STR) \
1145 do { \
1146 ; \
1147 } while(0)
1148 #endif
1149
1150 #if defined(HAVE_OPENSSL) && !defined(EMBEDDED_LIBRARY)
set_ssl_option_unpack_path(struct st_mysql_options * options,const char * arg)1151 static char *set_ssl_option_unpack_path(struct st_mysql_options *options,
1152 const char *arg)
1153 {
1154 char *opt_var= NULL;
1155 if (arg)
1156 {
1157 char *buff= (char *)my_malloc(FN_REFLEN + 1, MYF(MY_WME));
1158 unpack_filename(buff, (char *)arg);
1159 opt_var= my_strdup(buff, MYF(MY_WME));
1160 options->use_ssl= 1;
1161 my_free(buff);
1162 }
1163 return opt_var;
1164 }
1165 #endif
1166
1167
mysql_read_default_options(struct st_mysql_options * options,const char * filename,const char * group)1168 void mysql_read_default_options(struct st_mysql_options *options,
1169 const char *filename,const char *group)
1170 {
1171 int argc;
1172 char *argv_buff[1],**argv;
1173 const char *groups[3];
1174 DBUG_ENTER("mysql_read_default_options");
1175 DBUG_PRINT("enter",("file: %s group: %s",filename,group ? group :"NULL"));
1176
1177 compile_time_assert(OPT_keep_this_one_last ==
1178 array_elements(default_options));
1179
1180 argc=1; argv=argv_buff; argv_buff[0]= (char*) "client";
1181 groups[0]= (char*) "client"; groups[1]= (char*) group; groups[2]=0;
1182
1183 my_load_defaults(filename, groups, &argc, &argv, NULL);
1184 if (argc != 1) /* If some default option */
1185 {
1186 char **option=argv;
1187 while (*++option)
1188 {
1189 if (my_getopt_is_args_separator(option[0])) /* skip arguments separator */
1190 continue;
1191 /* DBUG_PRINT("info",("option: %s",option[0])); */
1192 if (option[0][0] == '-' && option[0][1] == '-')
1193 {
1194 char *end=strcend(*option,'=');
1195 char *opt_arg=0;
1196 if (*end)
1197 {
1198 opt_arg=end+1;
1199 *end=0; /* Remove '=' */
1200 }
1201 /* Change all '_' in variable name to '-' */
1202 for (end= *option ; *(end= strcend(end,'_')) ; )
1203 *end= '-';
1204 switch (find_type(*option + 2, &option_types, FIND_TYPE_BASIC)) {
1205 case OPT_port:
1206 if (opt_arg)
1207 options->port=atoi(opt_arg);
1208 break;
1209 case OPT_socket:
1210 if (opt_arg)
1211 {
1212 my_free(options->unix_socket);
1213 options->unix_socket=my_strdup(opt_arg,MYF(MY_WME));
1214 }
1215 break;
1216 case OPT_compress:
1217 options->compress=1;
1218 options->client_flag|= CLIENT_COMPRESS;
1219 break;
1220 case OPT_password:
1221 if (opt_arg)
1222 {
1223 my_free(options->password);
1224 options->password=my_strdup(opt_arg,MYF(MY_WME));
1225 }
1226 break;
1227 case OPT_pipe:
1228 options->protocol = MYSQL_PROTOCOL_PIPE;
1229 case OPT_connect_timeout:
1230 case OPT_timeout:
1231 if (opt_arg)
1232 options->connect_timeout=atoi(opt_arg);
1233 break;
1234 case OPT_user:
1235 if (opt_arg)
1236 {
1237 my_free(options->user);
1238 options->user=my_strdup(opt_arg,MYF(MY_WME));
1239 }
1240 break;
1241 case OPT_init_command:
1242 add_init_command(options,opt_arg);
1243 break;
1244 case OPT_host:
1245 if (opt_arg)
1246 {
1247 my_free(options->host);
1248 options->host=my_strdup(opt_arg,MYF(MY_WME));
1249 }
1250 break;
1251 case OPT_database:
1252 if (opt_arg)
1253 {
1254 my_free(options->db);
1255 options->db=my_strdup(opt_arg,MYF(MY_WME));
1256 }
1257 break;
1258 case OPT_debug:
1259 #ifdef MYSQL_CLIENT
1260 mysql_debug(opt_arg ? opt_arg : "d:t:o,/tmp/client.trace");
1261 break;
1262 #endif
1263 case OPT_return_found_rows:
1264 options->client_flag|=CLIENT_FOUND_ROWS;
1265 break;
1266 #if defined(HAVE_OPENSSL) && !defined(EMBEDDED_LIBRARY)
1267 case OPT_ssl_key:
1268 my_free(options->ssl_key);
1269 options->ssl_key = my_strdup(opt_arg, MYF(MY_WME));
1270 break;
1271 case OPT_ssl_cert:
1272 my_free(options->ssl_cert);
1273 options->ssl_cert = my_strdup(opt_arg, MYF(MY_WME));
1274 break;
1275 case OPT_ssl_ca:
1276 my_free(options->ssl_ca);
1277 options->ssl_ca = my_strdup(opt_arg, MYF(MY_WME));
1278 break;
1279 case OPT_ssl_capath:
1280 my_free(options->ssl_capath);
1281 options->ssl_capath = my_strdup(opt_arg, MYF(MY_WME));
1282 break;
1283 case OPT_ssl_cipher:
1284 my_free(options->ssl_cipher);
1285 options->ssl_cipher= my_strdup(opt_arg, MYF(MY_WME));
1286 break;
1287 case OPT_ssl_crl:
1288 EXTENSION_SET_SSL_STRING(options, ssl_crl, opt_arg);
1289 break;
1290 case OPT_ssl_crlpath:
1291 EXTENSION_SET_SSL_STRING(options, ssl_crlpath, opt_arg);
1292 break;
1293 case OPT_ssl_mode:
1294 if (opt_arg &&
1295 !my_strcasecmp(&my_charset_latin1, opt_arg, "required"))
1296 {
1297 ENSURE_EXTENSIONS_PRESENT(options);
1298 options->extension->ssl_mode= SSL_MODE_REQUIRED;
1299 }
1300 else
1301 {
1302 fprintf(stderr, "Unknown option to ssl-mode: %s\n", opt_arg);
1303 exit(1);
1304 }
1305 break;
1306 #else
1307 case OPT_ssl_key:
1308 case OPT_ssl_cert:
1309 case OPT_ssl_ca:
1310 case OPT_ssl_capath:
1311 case OPT_ssl_cipher:
1312 case OPT_ssl_crl:
1313 case OPT_ssl_crlpath:
1314 case OPT_ssl_mode:
1315 break;
1316 #endif /* HAVE_OPENSSL && !EMBEDDED_LIBRARY */
1317 case OPT_character_sets_dir:
1318 my_free(options->charset_dir);
1319 options->charset_dir = my_strdup(opt_arg, MYF(MY_WME));
1320 break;
1321 case OPT_default_character_set:
1322 my_free(options->charset_name);
1323 options->charset_name = my_strdup(opt_arg, MYF(MY_WME));
1324 break;
1325 case OPT_interactive_timeout:
1326 options->client_flag|= CLIENT_INTERACTIVE;
1327 break;
1328 case OPT_local_infile:
1329 if (!opt_arg || atoi(opt_arg) != 0)
1330 options->client_flag|= CLIENT_LOCAL_FILES;
1331 else
1332 options->client_flag&= ~CLIENT_LOCAL_FILES;
1333 break;
1334 case OPT_disable_local_infile:
1335 options->client_flag&= ~CLIENT_LOCAL_FILES;
1336 break;
1337 case OPT_max_allowed_packet:
1338 if (opt_arg)
1339 options->max_allowed_packet= atoi(opt_arg);
1340 break;
1341 case OPT_protocol:
1342 if ((options->protocol= find_type(opt_arg, &sql_protocol_typelib,
1343 FIND_TYPE_BASIC)) <= 0)
1344 {
1345 fprintf(stderr, "Unknown option to protocol: %s\n", opt_arg);
1346 exit(1);
1347 }
1348 break;
1349 case OPT_shared_memory_base_name:
1350 #ifdef HAVE_SMEM
1351 if (options->shared_memory_base_name != def_shared_memory_base_name)
1352 my_free(options->shared_memory_base_name);
1353 options->shared_memory_base_name=my_strdup(opt_arg,MYF(MY_WME));
1354 #endif
1355 break;
1356 case OPT_multi_results:
1357 options->client_flag|= CLIENT_MULTI_RESULTS;
1358 break;
1359 case OPT_multi_statements:
1360 case OPT_multi_queries:
1361 options->client_flag|= CLIENT_MULTI_STATEMENTS | CLIENT_MULTI_RESULTS;
1362 break;
1363 case OPT_secure_auth:
1364 options->secure_auth= TRUE;
1365 break;
1366 case OPT_report_data_truncation:
1367 options->report_data_truncation= opt_arg ? MY_TEST(atoi(opt_arg)) : 1;
1368 break;
1369 case OPT_plugin_dir:
1370 {
1371 char buff[FN_REFLEN], buff2[FN_REFLEN];
1372 if (strlen(opt_arg) >= FN_REFLEN)
1373 opt_arg[FN_REFLEN]= '\0';
1374 if (my_realpath(buff, opt_arg, 0))
1375 {
1376 DBUG_PRINT("warning",("failed to normalize the plugin path: %s",
1377 opt_arg));
1378 break;
1379 }
1380 convert_dirname(buff2, buff, NULL);
1381 EXTENSION_SET_STRING(options, plugin_dir, buff2);
1382 }
1383 break;
1384 case OPT_default_auth:
1385 EXTENSION_SET_STRING(options, default_auth, opt_arg);
1386 break;
1387 case OPT_bind_address:
1388 my_free(options->ci.bind_address);
1389 options->ci.bind_address= my_strdup(opt_arg, MYF(MY_WME));
1390 break;
1391 case OPT_enable_cleartext_plugin:
1392 ENSURE_EXTENSIONS_PRESENT(options);
1393 options->extension->enable_cleartext_plugin=
1394 (!opt_arg || atoi(opt_arg) != 0) ? TRUE : FALSE;
1395 break;
1396
1397 default:
1398 DBUG_PRINT("warning",("unknown option: %s",option[0]));
1399 }
1400 }
1401 }
1402 }
1403 free_defaults(argv);
1404 DBUG_VOID_RETURN;
1405 }
1406
1407
1408 /**************************************************************************
1409 Get column lengths of the current row
1410 If one uses mysql_use_result, res->lengths contains the length information,
1411 else the lengths are calculated from the offset between pointers.
1412 **************************************************************************/
1413
cli_fetch_lengths(ulong * to,MYSQL_ROW column,unsigned int field_count)1414 static void cli_fetch_lengths(ulong *to, MYSQL_ROW column,
1415 unsigned int field_count)
1416 {
1417 ulong *prev_length;
1418 char *start=0;
1419 MYSQL_ROW end;
1420
1421 prev_length=0; /* Keep gcc happy */
1422 for (end=column + field_count + 1 ; column != end ; column++, to++)
1423 {
1424 if (!*column)
1425 {
1426 *to= 0; /* Null */
1427 continue;
1428 }
1429 if (start) /* Found end of prev string */
1430 *prev_length= (ulong) (*column-start-1);
1431 start= *column;
1432 prev_length= to;
1433 }
1434 }
1435
1436 /***************************************************************************
1437 Change field rows to field structs
1438 ***************************************************************************/
1439
1440 MYSQL_FIELD *
unpack_fields(MYSQL * mysql,MYSQL_DATA * data,MEM_ROOT * alloc,uint fields,my_bool default_value,uint server_capabilities)1441 unpack_fields(MYSQL *mysql, MYSQL_DATA *data,MEM_ROOT *alloc,uint fields,
1442 my_bool default_value, uint server_capabilities)
1443 {
1444 MYSQL_ROWS *row;
1445 MYSQL_FIELD *field,*result;
1446 ulong lengths[9]; /* Max of fields */
1447 DBUG_ENTER("unpack_fields");
1448
1449 field= result= (MYSQL_FIELD*) alloc_root(alloc,
1450 (uint) sizeof(*field)*fields);
1451 if (!result)
1452 {
1453 free_rows(data); /* Free old data */
1454 set_mysql_error(mysql, CR_OUT_OF_MEMORY, unknown_sqlstate);
1455 DBUG_RETURN(0);
1456 }
1457 memset(field, 0, sizeof(MYSQL_FIELD)*fields);
1458 if (server_capabilities & CLIENT_PROTOCOL_41)
1459 {
1460 /* server is 4.1, and returns the new field result format */
1461 for (row=data->data; row ; row = row->next,field++)
1462 {
1463 uchar *pos;
1464 /* fields count may be wrong */
1465 if (field < result || (uint) (field - result) >= fields)
1466 DBUG_RETURN(NULL);
1467 cli_fetch_lengths(&lengths[0], row->data, default_value ? 8 : 7);
1468 field->catalog= strmake_root(alloc,(char*) row->data[0], lengths[0]);
1469 field->db= strmake_root(alloc,(char*) row->data[1], lengths[1]);
1470 field->table= strmake_root(alloc,(char*) row->data[2], lengths[2]);
1471 field->org_table= strmake_root(alloc,(char*) row->data[3], lengths[3]);
1472 field->name= strmake_root(alloc,(char*) row->data[4], lengths[4]);
1473 field->org_name= strmake_root(alloc,(char*) row->data[5], lengths[5]);
1474
1475 field->catalog_length= lengths[0];
1476 field->db_length= lengths[1];
1477 field->table_length= lengths[2];
1478 field->org_table_length= lengths[3];
1479 field->name_length= lengths[4];
1480 field->org_name_length= lengths[5];
1481
1482 /* Unpack fixed length parts */
1483 if (lengths[6] != 12)
1484 {
1485 /* malformed packet. signal an error. */
1486 free_rows(data); /* Free old data */
1487 set_mysql_error(mysql, CR_MALFORMED_PACKET, unknown_sqlstate);
1488 DBUG_RETURN(0);
1489 }
1490
1491 pos= (uchar*) row->data[6];
1492 field->charsetnr= uint2korr(pos);
1493 field->length= (uint) uint4korr(pos+2);
1494 field->type= (enum enum_field_types) pos[6];
1495 field->flags= uint2korr(pos+7);
1496 field->decimals= (uint) pos[9];
1497
1498 if (IS_NUM(field->type))
1499 field->flags|= NUM_FLAG;
1500 if (default_value && row->data[7])
1501 {
1502 field->def=strmake_root(alloc,(char*) row->data[7], lengths[7]);
1503 field->def_length= lengths[7];
1504 }
1505 else
1506 field->def=0;
1507 field->max_length= 0;
1508 }
1509 }
1510 #ifndef DELETE_SUPPORT_OF_4_0_PROTOCOL
1511 else
1512 {
1513 /* old protocol, for backward compatibility */
1514 for (row=data->data; row ; row = row->next,field++)
1515 {
1516 /*
1517 If any of the row->data[] below is NULL, it can result in a
1518 crash. Error out early as it indicates a malformed packet.
1519 For data[0], data[1] and data[5], strmake_root will handle
1520 NULL values.
1521 */
1522 if (!row->data[2] || !row->data[3] || !row->data[4])
1523 {
1524 free_rows(data);
1525 set_mysql_error(mysql, CR_MALFORMED_PACKET, unknown_sqlstate);
1526 DBUG_RETURN(0);
1527 }
1528
1529 cli_fetch_lengths(&lengths[0], row->data, default_value ? 6 : 5);
1530 field->org_table= field->table= strmake_root(alloc,(char*) row->data[0], lengths[0]);
1531 field->name= strmake_root(alloc,(char*) row->data[1], lengths[1]);
1532 field->length= (uint) uint3korr(row->data[2]);
1533 field->type= (enum enum_field_types) (uchar) row->data[3][0];
1534
1535 field->catalog=(char*) "";
1536 field->db= (char*) "";
1537 field->catalog_length= 0;
1538 field->db_length= 0;
1539 field->org_table_length= field->table_length= lengths[0];
1540 field->name_length= lengths[1];
1541
1542 if (server_capabilities & CLIENT_LONG_FLAG)
1543 {
1544 field->flags= uint2korr(row->data[4]);
1545 field->decimals=(uint) (uchar) row->data[4][2];
1546 }
1547 else
1548 {
1549 field->flags= (uint) (uchar) row->data[4][0];
1550 field->decimals=(uint) (uchar) row->data[4][1];
1551 }
1552 if (IS_NUM(field->type))
1553 field->flags|= NUM_FLAG;
1554 if (default_value && row->data[5])
1555 {
1556 field->def= strmake_root(alloc,(char*) row->data[5], lengths[5]);
1557 field->def_length= lengths[5];
1558 }
1559 else
1560 field->def=0;
1561 field->max_length= 0;
1562 }
1563 }
1564 #endif /* DELETE_SUPPORT_OF_4_0_PROTOCOL */
1565 free_rows(data); /* Free old data */
1566 DBUG_RETURN(result);
1567 }
1568
1569 /* Read all rows (fields or data) from server */
1570
cli_read_rows(MYSQL * mysql,MYSQL_FIELD * mysql_fields,unsigned int fields)1571 MYSQL_DATA *cli_read_rows(MYSQL *mysql,MYSQL_FIELD *mysql_fields,
1572 unsigned int fields)
1573 {
1574 uint field;
1575 ulong pkt_len;
1576 ulong len;
1577 uchar *cp;
1578 char *to, *end_to;
1579 MYSQL_DATA *result;
1580 MYSQL_ROWS **prev_ptr,*cur;
1581 NET *net = &mysql->net;
1582 DBUG_ENTER("cli_read_rows");
1583
1584 if ((pkt_len= cli_safe_read(mysql)) == packet_error)
1585 DBUG_RETURN(0);
1586 if (pkt_len == 0) DBUG_RETURN(0);
1587 if (!(result=(MYSQL_DATA*) my_malloc(sizeof(MYSQL_DATA),
1588 MYF(MY_WME | MY_ZEROFILL))))
1589 {
1590 set_mysql_error(mysql, CR_OUT_OF_MEMORY, unknown_sqlstate);
1591 DBUG_RETURN(0);
1592 }
1593 init_alloc_root(&result->alloc,8192,0); /* Assume rowlength < 8192 */
1594 result->alloc.min_malloc=sizeof(MYSQL_ROWS);
1595 prev_ptr= &result->data;
1596 result->rows=0;
1597 result->fields=fields;
1598
1599 /*
1600 The last EOF packet is either a single 254 character or (in MySQL 4.1)
1601 254 followed by 1-7 status bytes.
1602
1603 This doesn't conflict with normal usage of 254 which stands for a
1604 string where the length of the string is 8 bytes. (see net_field_length())
1605 */
1606
1607 while (*(cp=net->read_pos) != 254 || pkt_len >= 8)
1608 {
1609 result->rows++;
1610 if (!(cur= (MYSQL_ROWS*) alloc_root(&result->alloc,
1611 sizeof(MYSQL_ROWS))) ||
1612 !(cur->data= ((MYSQL_ROW)
1613 alloc_root(&result->alloc,
1614 (fields+1)*sizeof(char *)+pkt_len))))
1615 {
1616 free_rows(result);
1617 set_mysql_error(mysql, CR_OUT_OF_MEMORY, unknown_sqlstate);
1618 DBUG_RETURN(0);
1619 }
1620 *prev_ptr=cur;
1621 prev_ptr= &cur->next;
1622 to= (char*) (cur->data+fields+1);
1623 end_to=to+pkt_len-1;
1624 for (field=0 ; field < fields ; field++)
1625 {
1626 if ((len=(ulong) net_field_length(&cp)) == NULL_LENGTH)
1627 { /* null field */
1628 cur->data[field] = 0;
1629 }
1630 else
1631 {
1632 cur->data[field] = to;
1633 if (to > end_to || len > (ulong) (end_to - to))
1634 {
1635 free_rows(result);
1636 set_mysql_error(mysql, CR_MALFORMED_PACKET, unknown_sqlstate);
1637 DBUG_RETURN(0);
1638 }
1639 memcpy(to,(char*) cp,len); to[len]=0;
1640 to+=len+1;
1641 cp+=len;
1642 if (mysql_fields)
1643 {
1644 if (mysql_fields[field].max_length < len)
1645 mysql_fields[field].max_length=len;
1646 }
1647 }
1648 }
1649 cur->data[field]=to; /* End of last field */
1650 if ((pkt_len=cli_safe_read(mysql)) == packet_error)
1651 {
1652 free_rows(result);
1653 DBUG_RETURN(0);
1654 }
1655 }
1656 *prev_ptr=0; /* last pointer is null */
1657 if (pkt_len > 1) /* MySQL 4.1 protocol */
1658 {
1659 mysql->warning_count= uint2korr(cp+1);
1660 mysql->server_status= uint2korr(cp+3);
1661 DBUG_PRINT("info",("status: %u warning_count: %u",
1662 mysql->server_status, mysql->warning_count));
1663 }
1664 DBUG_PRINT("exit", ("Got %lu rows", (ulong) result->rows));
1665 DBUG_RETURN(result);
1666 }
1667
1668 /*
1669 Read one row. Uses packet buffer as storage for fields.
1670 When next packet is read, the previous field values are destroyed
1671 */
1672
1673
1674 static int
read_one_row(MYSQL * mysql,uint fields,MYSQL_ROW row,ulong * lengths)1675 read_one_row(MYSQL *mysql,uint fields,MYSQL_ROW row, ulong *lengths)
1676 {
1677 uint field;
1678 ulong pkt_len,len;
1679 uchar *pos, *prev_pos, *end_pos;
1680 NET *net= &mysql->net;
1681
1682 if ((pkt_len=cli_safe_read(mysql)) == packet_error)
1683 return -1;
1684 if (pkt_len <= 8 && net->read_pos[0] == 254)
1685 {
1686 if (pkt_len > 1) /* MySQL 4.1 protocol */
1687 {
1688 mysql->warning_count= uint2korr(net->read_pos+1);
1689 mysql->server_status= uint2korr(net->read_pos+3);
1690 }
1691 return 1; /* End of data */
1692 }
1693 prev_pos= 0; /* allowed to write at packet[-1] */
1694 pos=net->read_pos;
1695 end_pos=pos+pkt_len;
1696 for (field=0 ; field < fields ; field++)
1697 {
1698 if (pos >= end_pos) {
1699 set_mysql_error(mysql, CR_MALFORMED_PACKET, unknown_sqlstate);
1700 return -1;
1701 }
1702 len=(ulong) net_field_length_checked(&pos, (ulong)(end_pos - pos));
1703 DBUG_EXECUTE_IF("simulate_bad_field_length_1", {
1704 len= 1000000L;
1705 fields= 2;
1706 });
1707 DBUG_EXECUTE_IF("simulate_bad_field_length_2", {
1708 len= pkt_len - 1;
1709 fields= 2;
1710 });
1711
1712 if (pos > end_pos)
1713 {
1714 set_mysql_error(mysql, CR_UNKNOWN_ERROR, unknown_sqlstate);
1715 return -1;
1716 }
1717
1718 if (len == NULL_LENGTH)
1719 { /* null field */
1720 row[field] = 0;
1721 *lengths++=0;
1722 }
1723 else
1724 {
1725 row[field] = (char*) pos;
1726 pos+=len;
1727 *lengths++=len;
1728 }
1729
1730 /*
1731 It's safe to write to prev_pos here because we already check
1732 for a valid pos in the beginning of this loop.
1733 */
1734 if (prev_pos)
1735 *prev_pos=0; /* Terminate prev field */
1736 prev_pos=pos;
1737 }
1738 row[field]=(char*) prev_pos+1; /* End of last field */
1739 if (prev_pos < end_pos)
1740 *prev_pos=0; /* Terminate last field */
1741 return 0;
1742 }
1743
1744
1745 /****************************************************************************
1746 Init MySQL structure or allocate one
1747 ****************************************************************************/
1748
1749 MYSQL * STDCALL
mysql_init(MYSQL * mysql)1750 mysql_init(MYSQL *mysql)
1751 {
1752 if (mysql_server_init(0, NULL, NULL))
1753 return 0;
1754 if (!mysql)
1755 {
1756 if (!(mysql=(MYSQL*) my_malloc(sizeof(*mysql),MYF(MY_WME | MY_ZEROFILL))))
1757 {
1758 set_mysql_error(NULL, CR_OUT_OF_MEMORY, unknown_sqlstate);
1759 return 0;
1760 }
1761 mysql->free_me=1;
1762 }
1763 else
1764 memset(mysql, 0, sizeof(*(mysql)));
1765 mysql->charset=default_client_charset_info;
1766 strmov(mysql->net.sqlstate, not_error_sqlstate);
1767
1768 /*
1769 Only enable LOAD DATA INFILE by default if configured with option
1770 ENABLED_LOCAL_INFILE
1771 */
1772
1773 #if defined(ENABLED_LOCAL_INFILE) && !defined(MYSQL_SERVER)
1774 mysql->options.client_flag|= CLIENT_LOCAL_FILES;
1775 #endif
1776
1777 #ifdef HAVE_SMEM
1778 mysql->options.shared_memory_base_name= (char*) def_shared_memory_base_name;
1779 #endif
1780
1781 mysql->options.methods_to_use= MYSQL_OPT_GUESS_CONNECTION;
1782 mysql->options.report_data_truncation= TRUE; /* default */
1783
1784 /*
1785 By default we don't reconnect because it could silently corrupt data (after
1786 reconnection you potentially lose table locks, user variables, session
1787 variables (transactions but they are specifically dealt with in
1788 mysql_reconnect()).
1789 This is a change: < 5.0.3 mysql->reconnect was set to 1 by default.
1790 How this change impacts existing apps:
1791 - existing apps which relyed on the default will see a behaviour change;
1792 they will have to set reconnect=1 after mysql_real_connect().
1793 - existing apps which explicitely asked for reconnection (the only way they
1794 could do it was by setting mysql.reconnect to 1 after mysql_real_connect())
1795 will not see a behaviour change.
1796 - existing apps which explicitely asked for no reconnection
1797 (mysql.reconnect=0) will not see a behaviour change.
1798 */
1799 mysql->reconnect= 0;
1800
1801 mysql->options.secure_auth= TRUE;
1802
1803 return mysql;
1804 }
1805
1806
1807 /*
1808 Fill in SSL part of MYSQL structure and set 'use_ssl' flag.
1809 NB! Errors are not reported until you do mysql_real_connect.
1810 */
1811
1812 #define strdup_if_not_null(A) (A) == 0 ? 0 : my_strdup((A),MYF(MY_WME))
1813
1814 my_bool STDCALL
mysql_ssl_set(MYSQL * mysql MY_ATTRIBUTE ((unused)),const char * key MY_ATTRIBUTE ((unused)),const char * cert MY_ATTRIBUTE ((unused)),const char * ca MY_ATTRIBUTE ((unused)),const char * capath MY_ATTRIBUTE ((unused)),const char * cipher MY_ATTRIBUTE ((unused)))1815 mysql_ssl_set(MYSQL *mysql MY_ATTRIBUTE((unused)) ,
1816 const char *key MY_ATTRIBUTE((unused)),
1817 const char *cert MY_ATTRIBUTE((unused)),
1818 const char *ca MY_ATTRIBUTE((unused)),
1819 const char *capath MY_ATTRIBUTE((unused)),
1820 const char *cipher MY_ATTRIBUTE((unused)))
1821 {
1822 my_bool result= 0;
1823 DBUG_ENTER("mysql_ssl_set");
1824 #if defined(HAVE_OPENSSL) && !defined(EMBEDDED_LIBRARY)
1825 result=
1826 mysql_options(mysql, MYSQL_OPT_SSL_KEY, key) +
1827 mysql_options(mysql, MYSQL_OPT_SSL_CERT, cert) +
1828 mysql_options(mysql, MYSQL_OPT_SSL_CA, ca) +
1829 mysql_options(mysql, MYSQL_OPT_SSL_CAPATH, capath) +
1830 mysql_options(mysql, MYSQL_OPT_SSL_CIPHER, cipher)
1831 ? 1 : 0;
1832 #endif
1833 DBUG_RETURN(result);
1834 }
1835
1836
1837 /*
1838 Free strings in the SSL structure and clear 'use_ssl' flag.
1839 NB! Errors are not reported until you do mysql_real_connect.
1840 */
1841
1842 #if defined(HAVE_OPENSSL) && !defined(EMBEDDED_LIBRARY)
1843
1844 static void
mysql_ssl_free(MYSQL * mysql MY_ATTRIBUTE ((unused)))1845 mysql_ssl_free(MYSQL *mysql MY_ATTRIBUTE((unused)))
1846 {
1847 struct st_VioSSLFd *ssl_fd= (struct st_VioSSLFd*) mysql->connector_fd;
1848 DBUG_ENTER("mysql_ssl_free");
1849
1850 my_free(mysql->options.ssl_key);
1851 my_free(mysql->options.ssl_cert);
1852 my_free(mysql->options.ssl_ca);
1853 my_free(mysql->options.ssl_capath);
1854 my_free(mysql->options.ssl_cipher);
1855 if (mysql->options.extension)
1856 {
1857 my_free(mysql->options.extension->ssl_crl);
1858 my_free(mysql->options.extension->ssl_crlpath);
1859 }
1860 if (ssl_fd)
1861 SSL_CTX_free(ssl_fd->ssl_context);
1862 my_free(mysql->connector_fd);
1863 mysql->options.ssl_key = 0;
1864 mysql->options.ssl_cert = 0;
1865 mysql->options.ssl_ca = 0;
1866 mysql->options.ssl_capath = 0;
1867 mysql->options.ssl_cipher= 0;
1868 if (mysql->options.extension)
1869 {
1870 mysql->options.extension->ssl_crl = 0;
1871 mysql->options.extension->ssl_crlpath = 0;
1872 mysql->options.extension->ssl_mode= 0;
1873 }
1874 mysql->options.use_ssl = FALSE;
1875 mysql->connector_fd = 0;
1876 DBUG_VOID_RETURN;
1877 }
1878
1879 #endif /* HAVE_OPENSSL && !EMBEDDED_LIBRARY */
1880
1881 /*
1882 Return the SSL cipher (if any) used for current
1883 connection to the server.
1884
1885 SYNOPSYS
1886 mysql_get_ssl_cipher()
1887 mysql pointer to the mysql connection
1888
1889 */
1890
1891 const char * STDCALL
mysql_get_ssl_cipher(MYSQL * mysql MY_ATTRIBUTE ((unused)))1892 mysql_get_ssl_cipher(MYSQL *mysql MY_ATTRIBUTE((unused)))
1893 {
1894 DBUG_ENTER("mysql_get_ssl_cipher");
1895 #if defined(HAVE_OPENSSL) && !defined(EMBEDDED_LIBRARY)
1896 if (mysql->net.vio && mysql->net.vio->ssl_arg)
1897 DBUG_RETURN(SSL_get_cipher_name((SSL*)mysql->net.vio->ssl_arg));
1898 #endif /* HAVE_OPENSSL && !EMBEDDED_LIBRARY */
1899 DBUG_RETURN(NULL);
1900 }
1901
1902
1903 /*
1904 Check the server's (subject) Common Name against the
1905 hostname we connected to
1906
1907 SYNOPSIS
1908 ssl_verify_server_cert()
1909 vio pointer to a SSL connected vio
1910 server_hostname name of the server that we connected to
1911 errptr if we fail, we'll return (a pointer to a string
1912 describing) the reason here
1913
1914 RETURN VALUES
1915 0 Success
1916 1 Failed to validate server
1917
1918 */
1919
1920 #if defined(HAVE_OPENSSL) && !defined(EMBEDDED_LIBRARY)
1921
ssl_verify_server_cert(Vio * vio,const char * server_hostname,const char ** errptr)1922 static int ssl_verify_server_cert(Vio *vio, const char* server_hostname, const char **errptr)
1923 {
1924 SSL *ssl;
1925 X509 *server_cert= NULL;
1926 int ret_validation= 1;
1927
1928 #if !(OPENSSL_VERSION_NUMBER >= 0x10002000L)
1929 char *cn= NULL;
1930 int cn_loc= -1;
1931 ASN1_STRING *cn_asn1= NULL;
1932 X509_NAME_ENTRY *cn_entry= NULL;
1933 X509_NAME *subject= NULL;
1934 #endif
1935
1936 DBUG_ENTER("ssl_verify_server_cert");
1937 DBUG_PRINT("enter", ("server_hostname: %s", server_hostname));
1938
1939 if (!(ssl= (SSL*)vio->ssl_arg))
1940 {
1941 *errptr= "No SSL pointer found";
1942 goto error;
1943 }
1944
1945 if (!server_hostname)
1946 {
1947 *errptr= "No server hostname supplied";
1948 goto error;
1949 }
1950
1951 if (!(server_cert= SSL_get_peer_certificate(ssl)))
1952 {
1953 *errptr= "Could not get server certificate";
1954 goto error;
1955 }
1956
1957 if (X509_V_OK != SSL_get_verify_result(ssl))
1958 {
1959 *errptr= "Failed to verify the server certificate";
1960 goto error;
1961 }
1962 /*
1963 We already know that the certificate exchanged was valid; the SSL library
1964 handled that. Now we need to verify that the contents of the certificate
1965 are what we expect.
1966 */
1967
1968 /*
1969 Use OpenSSL certificate matching functions instead of our own if we
1970 have OpenSSL. The X509_check_* functions return 1 on success.
1971 */
1972 #if OPENSSL_VERSION_NUMBER >= 0x10002000L || defined(HAVE_WOLFSSL)
1973 if ((X509_check_host(server_cert, server_hostname, strlen(server_hostname),
1974 0, 0) != 1) &&
1975 (X509_check_ip_asc(server_cert, server_hostname, 0) != 1)) {
1976 *errptr = "Failed to verify the server certificate via X509 certificate "
1977 "matching functions";
1978 goto error;
1979
1980 } else {
1981 /* Success */
1982 ret_validation = 0;
1983 }
1984 #else /* OPENSSL_VERSION_NUMBER < 0x10002000L */
1985 /*
1986 OpenSSL prior to 1.0.2 do not support X509_check_host() function.
1987 Use deprecated X509_get_subject_name() instead.
1988 */
1989
1990 subject= X509_get_subject_name((X509 *) server_cert);
1991 // Find the CN location in the subject
1992 cn_loc= X509_NAME_get_index_by_NID(subject, NID_commonName, -1);
1993 if (cn_loc < 0)
1994 {
1995 *errptr= "Failed to get CN location in the certificate subject";
1996 goto error;
1997 }
1998
1999 // Get the CN entry for given location
2000 cn_entry= X509_NAME_get_entry(subject, cn_loc);
2001 if (cn_entry == NULL)
2002 {
2003 *errptr= "Failed to get CN entry using CN location";
2004 goto error;
2005 }
2006
2007 // Get CN from common name entry
2008 cn_asn1 = X509_NAME_ENTRY_get_data(cn_entry);
2009 if (cn_asn1 == NULL)
2010 {
2011 *errptr= "Failed to get CN from CN entry";
2012 goto error;
2013 }
2014
2015 #if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER)
2016 cn= (const char *) ASN1_STRING_data(cn_asn1);
2017 #else
2018 cn= (const char *) ASN1_STRING_get0_data(cn_asn1);
2019 #endif
2020
2021 // There should not be any NULL embedded in the CN
2022 if ((size_t)ASN1_STRING_length(cn_asn1) != strlen(cn))
2023 {
2024 *errptr= "NULL embedded in the certificate CN";
2025 goto error;
2026 }
2027
2028 DBUG_PRINT("info", ("Server hostname in cert: %s", cn));
2029 if (!strcmp(cn, server_hostname))
2030 {
2031 /* Success */
2032 ret_validation= 0;
2033 }
2034 #endif /* OPENSSL_VERSION_NUMBER >= 0x10002000L */
2035 *errptr= "SSL certificate validation failure";
2036
2037 error:
2038 if (server_cert != NULL)
2039 X509_free (server_cert);
2040 DBUG_RETURN(ret_validation);
2041 }
2042
2043 #endif /* HAVE_OPENSSL && !EMBEDDED_LIBRARY */
2044
2045
2046 /**
2047 Checks if any SSL option is set for libmysqld embedded server.
2048
2049 @param mysql the connection handle
2050 @retval 0 success
2051 @retval 1 failure
2052 */
2053 #ifdef EMBEDDED_LIBRARY
embedded_ssl_check(MYSQL * mysql)2054 int embedded_ssl_check(MYSQL *mysql)
2055 {
2056 if (mysql->options.ssl_key || mysql->options.ssl_cert ||
2057 mysql->options.ssl_ca || mysql->options.ssl_capath ||
2058 mysql->options.ssl_cipher ||
2059 mysql->options.client_flag & CLIENT_SSL_VERIFY_SERVER_CERT ||
2060 (mysql->options.extension &&
2061 (mysql->options.extension->ssl_crl ||
2062 mysql->options.extension->ssl_crlpath ||
2063 mysql->options.extension->ssl_mode == SSL_MODE_REQUIRED)))
2064 {
2065 set_mysql_extended_error(mysql, CR_SSL_CONNECTION_ERROR, unknown_sqlstate,
2066 ER(CR_SSL_CONNECTION_ERROR),
2067 "Embedded server libmysqld library doesn't support "
2068 "SSL connections");
2069 return 1;
2070 }
2071 return 0;
2072 }
2073 #endif
2074
2075
2076 /*
2077 Note that the mysql argument must be initialized with mysql_init()
2078 before calling mysql_real_connect !
2079 */
2080
2081 static my_bool cli_read_query_result(MYSQL *mysql);
2082 static MYSQL_RES *cli_use_result(MYSQL *mysql);
2083
cli_read_change_user_result(MYSQL * mysql)2084 int cli_read_change_user_result(MYSQL *mysql)
2085 {
2086 return cli_safe_read(mysql);
2087 }
2088
2089 static MYSQL_METHODS client_methods=
2090 {
2091 cli_read_query_result, /* read_query_result */
2092 cli_advanced_command, /* advanced_command */
2093 cli_read_rows, /* read_rows */
2094 cli_use_result, /* use_result */
2095 cli_fetch_lengths, /* fetch_lengths */
2096 cli_flush_use_result, /* flush_use_result */
2097 cli_read_change_user_result /* read_change_user_result */
2098 #ifndef MYSQL_SERVER
2099 ,cli_list_fields, /* list_fields */
2100 cli_read_prepare_result, /* read_prepare_result */
2101 cli_stmt_execute, /* stmt_execute */
2102 cli_read_binary_rows, /* read_binary_rows */
2103 cli_unbuffered_fetch, /* unbuffered_fetch */
2104 NULL, /* free_embedded_thd */
2105 cli_read_statistics, /* read_statistics */
2106 cli_read_query_result, /* next_result */
2107 cli_read_binary_rows /* read_rows_from_cursor */
2108 #endif
2109 };
2110
2111
2112
2113 typedef enum my_cs_match_type_enum
2114 {
2115 /* MySQL and OS charsets are fully compatible */
2116 my_cs_exact,
2117 /* MySQL charset is very close to OS charset */
2118 my_cs_approx,
2119 /*
2120 MySQL knows this charset, but it is not supported as client character set.
2121 */
2122 my_cs_unsupp
2123 } my_cs_match_type;
2124
2125
2126 typedef struct str2str_st
2127 {
2128 const char *os_name;
2129 const char *my_name;
2130 my_cs_match_type param;
2131 } MY_CSET_OS_NAME;
2132
2133 const MY_CSET_OS_NAME charsets[]=
2134 {
2135 #ifdef __WIN__
2136 {"cp437", "cp850", my_cs_approx},
2137 {"cp850", "cp850", my_cs_exact},
2138 {"cp852", "cp852", my_cs_exact},
2139 {"cp858", "cp850", my_cs_approx},
2140 {"cp866", "cp866", my_cs_exact},
2141 {"cp874", "tis620", my_cs_approx},
2142 {"cp932", "cp932", my_cs_exact},
2143 {"cp936", "gbk", my_cs_approx},
2144 {"cp949", "euckr", my_cs_approx},
2145 {"cp950", "big5", my_cs_exact},
2146 {"cp1200", "utf16le", my_cs_unsupp},
2147 {"cp1201", "utf16", my_cs_unsupp},
2148 {"cp1250", "cp1250", my_cs_exact},
2149 {"cp1251", "cp1251", my_cs_exact},
2150 {"cp1252", "latin1", my_cs_exact},
2151 {"cp1253", "greek", my_cs_exact},
2152 {"cp1254", "latin5", my_cs_exact},
2153 {"cp1255", "hebrew", my_cs_approx},
2154 {"cp1256", "cp1256", my_cs_exact},
2155 {"cp1257", "cp1257", my_cs_exact},
2156 {"cp10000", "macroman", my_cs_exact},
2157 {"cp10001", "sjis", my_cs_approx},
2158 {"cp10002", "big5", my_cs_approx},
2159 {"cp10008", "gb2312", my_cs_approx},
2160 {"cp10021", "tis620", my_cs_approx},
2161 {"cp10029", "macce", my_cs_exact},
2162 {"cp12001", "utf32", my_cs_unsupp},
2163 {"cp20107", "swe7", my_cs_exact},
2164 {"cp20127", "latin1", my_cs_approx},
2165 {"cp20866", "koi8r", my_cs_exact},
2166 {"cp20932", "ujis", my_cs_exact},
2167 {"cp20936", "gb2312", my_cs_approx},
2168 {"cp20949", "euckr", my_cs_approx},
2169 {"cp21866", "koi8u", my_cs_exact},
2170 {"cp28591", "latin1", my_cs_approx},
2171 {"cp28592", "latin2", my_cs_exact},
2172 {"cp28597", "greek", my_cs_exact},
2173 {"cp28598", "hebrew", my_cs_exact},
2174 {"cp28599", "latin5", my_cs_exact},
2175 {"cp28603", "latin7", my_cs_exact},
2176 #ifdef UNCOMMENT_THIS_WHEN_WL_4579_IS_DONE
2177 {"cp28605", "latin9", my_cs_exact},
2178 #endif
2179 {"cp38598", "hebrew", my_cs_exact},
2180 {"cp51932", "ujis", my_cs_exact},
2181 {"cp51936", "gb2312", my_cs_exact},
2182 {"cp51949", "euckr", my_cs_exact},
2183 {"cp51950", "big5", my_cs_exact},
2184 #ifdef UNCOMMENT_THIS_WHEN_WL_WL_4024_IS_DONE
2185 {"cp54936", "gb18030", my_cs_exact},
2186 #endif
2187 {"cp65001", "utf8", my_cs_exact},
2188
2189 #else /* not Windows */
2190
2191 {"646", "latin1", my_cs_approx}, /* Default on Solaris */
2192 {"ANSI_X3.4-1968", "latin1", my_cs_approx},
2193 {"ansi1251", "cp1251", my_cs_exact},
2194 {"armscii8", "armscii8", my_cs_exact},
2195 {"armscii-8", "armscii8", my_cs_exact},
2196 {"ASCII", "latin1", my_cs_approx},
2197 {"Big5", "big5", my_cs_exact},
2198 {"cp1251", "cp1251", my_cs_exact},
2199 {"cp1255", "hebrew", my_cs_approx},
2200 {"CP866", "cp866", my_cs_exact},
2201 {"eucCN", "gb2312", my_cs_exact},
2202 {"euc-CN", "gb2312", my_cs_exact},
2203 {"eucJP", "ujis", my_cs_exact},
2204 {"euc-JP", "ujis", my_cs_exact},
2205 {"eucKR", "euckr", my_cs_exact},
2206 {"euc-KR", "euckr", my_cs_exact},
2207 #ifdef UNCOMMENT_THIS_WHEN_WL_WL_4024_IS_DONE
2208 {"gb18030", "gb18030", my_cs_exact},
2209 #endif
2210 {"gb2312", "gb2312", my_cs_exact},
2211 {"gbk", "gbk", my_cs_exact},
2212 {"georgianps", "geostd8", my_cs_exact},
2213 {"georgian-ps", "geostd8", my_cs_exact},
2214 {"IBM-1252", "cp1252", my_cs_exact},
2215
2216 {"iso88591", "latin1", my_cs_approx},
2217 {"ISO_8859-1", "latin1", my_cs_approx},
2218 {"ISO8859-1", "latin1", my_cs_approx},
2219 {"ISO-8859-1", "latin1", my_cs_approx},
2220
2221 {"iso885913", "latin7", my_cs_exact},
2222 {"ISO_8859-13", "latin7", my_cs_exact},
2223 {"ISO8859-13", "latin7", my_cs_exact},
2224 {"ISO-8859-13", "latin7", my_cs_exact},
2225
2226 #ifdef UNCOMMENT_THIS_WHEN_WL_4579_IS_DONE
2227 {"iso885915", "latin9", my_cs_exact},
2228 {"ISO_8859-15", "latin9", my_cs_exact},
2229 {"ISO8859-15", "latin9", my_cs_exact},
2230 {"ISO-8859-15", "latin9", my_cs_exact},
2231 #endif
2232
2233 {"iso88592", "latin2", my_cs_exact},
2234 {"ISO_8859-2", "latin2", my_cs_exact},
2235 {"ISO8859-2", "latin2", my_cs_exact},
2236 {"ISO-8859-2", "latin2", my_cs_exact},
2237
2238 {"iso88597", "greek", my_cs_exact},
2239 {"ISO_8859-7", "greek", my_cs_exact},
2240 {"ISO8859-7", "greek", my_cs_exact},
2241 {"ISO-8859-7", "greek", my_cs_exact},
2242
2243 {"iso88598", "hebrew", my_cs_exact},
2244 {"ISO_8859-8", "hebrew", my_cs_exact},
2245 {"ISO8859-8", "hebrew", my_cs_exact},
2246 {"ISO-8859-8", "hebrew", my_cs_exact},
2247
2248 {"iso88599", "latin5", my_cs_exact},
2249 {"ISO_8859-9", "latin5", my_cs_exact},
2250 {"ISO8859-9", "latin5", my_cs_exact},
2251 {"ISO-8859-9", "latin5", my_cs_exact},
2252
2253 {"koi8r", "koi8r", my_cs_exact},
2254 {"KOI8-R", "koi8r", my_cs_exact},
2255 {"koi8u", "koi8u", my_cs_exact},
2256 {"KOI8-U", "koi8u", my_cs_exact},
2257
2258 {"roman8", "hp8", my_cs_exact}, /* Default on HP UX */
2259
2260 {"Shift_JIS", "sjis", my_cs_exact},
2261 {"SJIS", "sjis", my_cs_exact},
2262 {"shiftjisx0213", "sjis", my_cs_exact},
2263
2264 {"tis620", "tis620", my_cs_exact},
2265 {"tis-620", "tis620", my_cs_exact},
2266
2267 {"ujis", "ujis", my_cs_exact},
2268
2269 {"US-ASCII", "latin1", my_cs_approx},
2270
2271 {"utf8", "utf8", my_cs_exact},
2272 {"utf-8", "utf8", my_cs_exact},
2273 #endif
2274 {NULL, NULL, 0}
2275 };
2276
2277
2278 static const char *
my_os_charset_to_mysql_charset(const char * csname)2279 my_os_charset_to_mysql_charset(const char *csname)
2280 {
2281 const MY_CSET_OS_NAME *csp;
2282 for (csp= charsets; csp->os_name; csp++)
2283 {
2284 if (!my_strcasecmp(&my_charset_latin1, csp->os_name, csname))
2285 {
2286 switch (csp->param)
2287 {
2288 case my_cs_exact:
2289 return csp->my_name;
2290
2291 case my_cs_approx:
2292 /*
2293 Maybe we should print a warning eventually:
2294 character set correspondence is not exact.
2295 */
2296 return csp->my_name;
2297
2298 default:
2299 my_printf_error(ER_UNKNOWN_ERROR,
2300 "OS character set '%s'"
2301 " is not supported by MySQL client",
2302 MYF(0), csp->my_name);
2303 goto def;
2304 }
2305 }
2306 }
2307
2308 my_printf_error(ER_UNKNOWN_ERROR,
2309 "Unknown OS character set '%s'.",
2310 MYF(0), csname);
2311
2312 def:
2313 csname= MYSQL_DEFAULT_CHARSET_NAME;
2314 my_printf_error(ER_UNKNOWN_ERROR,
2315 "Switching to the default character set '%s'.",
2316 MYF(0), csname);
2317 return csname;
2318 }
2319
2320
2321 #ifndef __WIN__
2322 #include <stdlib.h> /* for getenv() */
2323 #ifdef HAVE_LANGINFO_H
2324 #include <langinfo.h>
2325 #endif
2326 #ifdef HAVE_LOCALE_H
2327 #include <locale.h>
2328 #endif
2329 #endif /* __WIN__ */
2330
2331
2332 static int
mysql_autodetect_character_set(MYSQL * mysql)2333 mysql_autodetect_character_set(MYSQL *mysql)
2334 {
2335 const char *csname= MYSQL_DEFAULT_CHARSET_NAME;
2336
2337 #ifdef __WIN__
2338 char cpbuf[64];
2339 {
2340 my_snprintf(cpbuf, sizeof(cpbuf), "cp%d", (int) GetConsoleCP());
2341 csname= my_os_charset_to_mysql_charset(cpbuf);
2342 }
2343 #elif defined(HAVE_SETLOCALE) && defined(HAVE_NL_LANGINFO)
2344 {
2345 if (setlocale(LC_CTYPE, "") && (csname= nl_langinfo(CODESET)))
2346 csname= my_os_charset_to_mysql_charset(csname);
2347 }
2348 #endif
2349
2350 if (mysql->options.charset_name)
2351 my_free(mysql->options.charset_name);
2352 if (!(mysql->options.charset_name= my_strdup(csname, MYF(MY_WME))))
2353 return 1;
2354 return 0;
2355 }
2356
2357
2358 static void
mysql_set_character_set_with_default_collation(MYSQL * mysql)2359 mysql_set_character_set_with_default_collation(MYSQL *mysql)
2360 {
2361 const char *save= charsets_dir;
2362 if (mysql->options.charset_dir)
2363 charsets_dir=mysql->options.charset_dir;
2364
2365 if ((mysql->charset= get_charset_by_csname(mysql->options.charset_name,
2366 MY_CS_PRIMARY, MYF(MY_WME))))
2367 {
2368 /* Try to set compiled default collation when it's possible. */
2369 CHARSET_INFO *collation;
2370 if ((collation=
2371 get_charset_by_name(MYSQL_DEFAULT_COLLATION_NAME, MYF(MY_WME))) &&
2372 my_charset_same(mysql->charset, collation))
2373 {
2374 mysql->charset= collation;
2375 }
2376 else
2377 {
2378 /*
2379 Default compiled collation not found, or is not applicable
2380 to the requested character set.
2381 Continue with the default collation of the character set.
2382 */
2383 }
2384 }
2385 charsets_dir= save;
2386 }
2387
2388
2389 C_MODE_START
mysql_init_character_set(MYSQL * mysql)2390 int mysql_init_character_set(MYSQL *mysql)
2391 {
2392 /* Set character set */
2393 if (!mysql->options.charset_name)
2394 {
2395 if (!(mysql->options.charset_name=
2396 my_strdup(MYSQL_DEFAULT_CHARSET_NAME,MYF(MY_WME))))
2397 return 1;
2398 }
2399 else if (!strcmp(mysql->options.charset_name,
2400 MYSQL_AUTODETECT_CHARSET_NAME) &&
2401 mysql_autodetect_character_set(mysql))
2402 return 1;
2403
2404 mysql_set_character_set_with_default_collation(mysql);
2405
2406 if (!mysql->charset)
2407 {
2408 if (mysql->options.charset_dir)
2409 set_mysql_extended_error(mysql, CR_CANT_READ_CHARSET, unknown_sqlstate,
2410 ER(CR_CANT_READ_CHARSET),
2411 mysql->options.charset_name,
2412 mysql->options.charset_dir);
2413 else
2414 {
2415 char cs_dir_name[FN_REFLEN];
2416 get_charsets_dir(cs_dir_name);
2417 set_mysql_extended_error(mysql, CR_CANT_READ_CHARSET, unknown_sqlstate,
2418 ER(CR_CANT_READ_CHARSET),
2419 mysql->options.charset_name,
2420 cs_dir_name);
2421 }
2422 return 1;
2423 }
2424 return 0;
2425 }
2426 C_MODE_END
2427
2428 /*********** client side authentication support **************************/
2429
2430 typedef struct st_mysql_client_plugin_AUTHENTICATION auth_plugin_t;
2431 static int client_mpvio_write_packet(struct st_plugin_vio*, const uchar*, int);
2432 static int native_password_auth_client(MYSQL_PLUGIN_VIO *vio, MYSQL *mysql);
2433 static int old_password_auth_client(MYSQL_PLUGIN_VIO *vio, MYSQL *mysql);
2434 static int clear_password_auth_client(MYSQL_PLUGIN_VIO *vio, MYSQL *mysql);
2435
2436 static auth_plugin_t native_password_client_plugin=
2437 {
2438 MYSQL_CLIENT_AUTHENTICATION_PLUGIN,
2439 MYSQL_CLIENT_AUTHENTICATION_PLUGIN_INTERFACE_VERSION,
2440 native_password_plugin_name,
2441 "R.J.Silk, Sergei Golubchik",
2442 "Native MySQL authentication",
2443 {1, 0, 0},
2444 "GPL",
2445 NULL,
2446 NULL,
2447 NULL,
2448 NULL,
2449 native_password_auth_client
2450 };
2451
2452 static auth_plugin_t old_password_client_plugin=
2453 {
2454 MYSQL_CLIENT_AUTHENTICATION_PLUGIN,
2455 MYSQL_CLIENT_AUTHENTICATION_PLUGIN_INTERFACE_VERSION,
2456 old_password_plugin_name,
2457 "R.J.Silk, Sergei Golubchik",
2458 "Old MySQL-3.23 authentication",
2459 {1, 0, 0},
2460 "GPL",
2461 NULL,
2462 NULL,
2463 NULL,
2464 NULL,
2465 old_password_auth_client
2466 };
2467
2468 static auth_plugin_t clear_password_client_plugin=
2469 {
2470 MYSQL_CLIENT_AUTHENTICATION_PLUGIN,
2471 MYSQL_CLIENT_AUTHENTICATION_PLUGIN_INTERFACE_VERSION,
2472 "mysql_clear_password",
2473 "Georgi Kodinov",
2474 "Clear password authentication plugin",
2475 {0,1,0},
2476 "GPL",
2477 NULL,
2478 NULL,
2479 NULL,
2480 NULL,
2481 clear_password_auth_client
2482 };
2483
2484 #if defined(HAVE_OPENSSL)
2485 static auth_plugin_t sha256_password_client_plugin=
2486 {
2487 MYSQL_CLIENT_AUTHENTICATION_PLUGIN,
2488 MYSQL_CLIENT_AUTHENTICATION_PLUGIN_INTERFACE_VERSION,
2489 "sha256_password",
2490 "Oracle Inc",
2491 "SHA256 based authentication with salt",
2492 {1, 0, 0},
2493 "GPL",
2494 NULL,
2495 sha256_password_init,
2496 sha256_password_deinit,
2497 NULL,
2498 sha256_password_auth_client
2499 };
2500 #endif
2501 #ifdef AUTHENTICATION_WIN
2502 extern auth_plugin_t win_auth_client_plugin;
2503 #endif
2504
2505 struct st_mysql_client_plugin *mysql_client_builtins[]=
2506 {
2507 (struct st_mysql_client_plugin *)&native_password_client_plugin,
2508 (struct st_mysql_client_plugin *)&old_password_client_plugin,
2509 (struct st_mysql_client_plugin *)&clear_password_client_plugin,
2510 #if defined(HAVE_OPENSSL)
2511 (struct st_mysql_client_plugin *) &sha256_password_client_plugin,
2512 #endif
2513 #ifdef AUTHENTICATION_WIN
2514 (struct st_mysql_client_plugin *)&win_auth_client_plugin,
2515 #endif
2516 0
2517 };
2518
2519
2520 static uchar *
write_length_encoded_string3(uchar * buf,char * string,size_t length)2521 write_length_encoded_string3(uchar *buf, char *string, size_t length)
2522 {
2523 buf= net_store_length(buf, length);
2524 memcpy(buf, string, length);
2525 buf+= length;
2526 return buf;
2527 }
2528
2529
2530 uchar *
send_client_connect_attrs(MYSQL * mysql,uchar * buf)2531 send_client_connect_attrs(MYSQL *mysql, uchar *buf)
2532 {
2533 /* check if the server supports connection attributes */
2534 if (mysql->server_capabilities & CLIENT_CONNECT_ATTRS)
2535 {
2536
2537 /* Always store the length if the client supports it */
2538 buf= net_store_length(buf,
2539 mysql->options.extension ?
2540 mysql->options.extension->connection_attributes_length :
2541 0);
2542
2543 /* check if we have connection attributes */
2544 if (mysql->options.extension &&
2545 my_hash_inited(&mysql->options.extension->connection_attributes))
2546 {
2547 HASH *attrs= &mysql->options.extension->connection_attributes;
2548 ulong idx;
2549
2550 /* loop over and dump the connection attributes */
2551 for (idx= 0; idx < attrs->records; idx++)
2552 {
2553 LEX_STRING *attr= (LEX_STRING *) my_hash_element(attrs, idx);
2554 LEX_STRING *key= attr, *value= attr + 1;
2555
2556 /* we can't have zero length keys */
2557 DBUG_ASSERT(key->length);
2558
2559 buf= write_length_encoded_string3(buf, key->str, key->length);
2560 buf= write_length_encoded_string3(buf, value->str, value->length);
2561 }
2562 }
2563 }
2564 return buf;
2565 }
2566
2567
get_length_store_length(size_t length)2568 static size_t get_length_store_length(size_t length)
2569 {
2570 /* as defined in net_store_length */
2571 #define MAX_VARIABLE_STRING_LENGTH 9
2572 uchar length_buffer[MAX_VARIABLE_STRING_LENGTH], *ptr;
2573
2574 ptr= net_store_length(length_buffer, length);
2575
2576 return ptr - &length_buffer[0];
2577 }
2578
2579
2580 /* this is a "superset" of MYSQL_PLUGIN_VIO, in C++ I use inheritance */
2581 typedef struct {
2582 int (*read_packet)(struct st_plugin_vio *vio, uchar **buf);
2583 int (*write_packet)(struct st_plugin_vio *vio, const uchar *pkt, int pkt_len);
2584 void (*info)(struct st_plugin_vio *vio, struct st_plugin_vio_info *info);
2585 /* -= end of MYSQL_PLUGIN_VIO =- */
2586 MYSQL *mysql;
2587 auth_plugin_t *plugin; /**< what plugin we're under */
2588 const char *db;
2589 struct {
2590 uchar *pkt; /**< pointer into NET::buff */
2591 uint pkt_len;
2592 } cached_server_reply;
2593 int packets_read, packets_written; /**< counters for send/received packets */
2594 int mysql_change_user; /**< if it's mysql_change_user() */
2595 int last_read_packet_len; /**< the length of the last *read* packet */
2596 } MCPVIO_EXT;
2597
2598
2599 /*
2600 Write 1-8 bytes of string length header infromation to dest depending on
2601 value of src_len, then copy src_len bytes from src to dest.
2602
2603 @param dest Destination buffer of size src_len+8
2604 @param dest_end One byte past the end of the dest buffer
2605 @param src Source buff of size src_len
2606 @param src_end One byte past the end of the src buffer
2607
2608 @return pointer dest+src_len+header size or NULL if
2609 */
2610
write_length_encoded_string4(char * dest,char * dest_end,char * src,char * src_end)2611 char *write_length_encoded_string4(char *dest, char *dest_end, char *src,
2612 char *src_end)
2613 {
2614 size_t src_len= (size_t)(src_end - src);
2615 uchar *to= net_store_length((uchar*) dest, src_len);
2616 if ((char*)(to + src_len) >= dest_end)
2617 return NULL;
2618 memcpy(to, src, src_len);
2619 return (char*)(to + src_len);
2620 }
2621
2622
2623 /*
2624 Write 1 byte of string length header information to dest and
2625 copy src_len bytes from src to dest.
2626 */
write_string(char * dest,char * dest_end,char * src,char * src_end)2627 char *write_string(char *dest, char *dest_end, char *src, char *src_end)
2628 {
2629 size_t src_len= (size_t)(src_end - src);
2630 uchar *to= NULL;
2631 if (src_len >= 251)
2632 return NULL;
2633 *dest=(uchar) src_len;
2634 to= (uchar*) dest+1;
2635 if ((char*)(to + src_len) >= dest_end)
2636 return NULL;
2637 memcpy(to, src, src_len);
2638 return (char*)(to + src_len);
2639 }
2640 /**
2641 sends a COM_CHANGE_USER command with a caller provided payload
2642
2643 Packet format:
2644
2645 Bytes Content
2646 ----- ----
2647 n user name - \0-terminated string
2648 n password
2649 3.23 scramble - \0-terminated string (9 bytes)
2650 otherwise - length (1 byte) coded
2651 n database name - \0-terminated string
2652 2 character set number (if the server >= 4.1.x)
2653 n client auth plugin name - \0-terminated string,
2654 (if the server supports plugin auth)
2655
2656 @retval 0 ok
2657 @retval 1 error
2658 */
send_change_user_packet(MCPVIO_EXT * mpvio,const uchar * data,int data_len)2659 static int send_change_user_packet(MCPVIO_EXT *mpvio,
2660 const uchar *data, int data_len)
2661 {
2662 MYSQL *mysql= mpvio->mysql;
2663 char *buff, *end;
2664 int res= 1;
2665 size_t connect_attrs_len=
2666 (mysql->server_capabilities & CLIENT_CONNECT_ATTRS &&
2667 mysql->options.extension) ?
2668 mysql->options.extension->connection_attributes_length : 0;
2669
2670 buff= my_alloca(USERNAME_LENGTH + data_len + 1 + NAME_LEN + 2 + NAME_LEN +
2671 connect_attrs_len + 9 /* for the length of the attrs */);
2672
2673 end= strmake(buff, mysql->user, USERNAME_LENGTH) + 1;
2674
2675 if (!data_len)
2676 *end++= 0;
2677 else
2678 {
2679 if (mysql->client_flag & CLIENT_SECURE_CONNECTION)
2680 {
2681 DBUG_ASSERT(data_len <= 255);
2682 if (data_len > 255)
2683 {
2684 set_mysql_error(mysql, CR_MALFORMED_PACKET, unknown_sqlstate);
2685 goto error;
2686 }
2687 *end++= data_len;
2688 }
2689 else
2690 {
2691 DBUG_ASSERT(data_len == SCRAMBLE_LENGTH_323 + 1);
2692 DBUG_ASSERT(data[SCRAMBLE_LENGTH_323] == 0);
2693 }
2694 memcpy(end, data, data_len);
2695 end+= data_len;
2696 }
2697 end= strmake(end, mpvio->db ? mpvio->db : "", NAME_LEN) + 1;
2698
2699 if (mysql->server_capabilities & CLIENT_PROTOCOL_41)
2700 {
2701 int2store(end, (ushort) mysql->charset->number);
2702 end+= 2;
2703 }
2704
2705 if (mysql->server_capabilities & CLIENT_PLUGIN_AUTH)
2706 end= strmake(end, mpvio->plugin->name, NAME_LEN) + 1;
2707
2708 end= (char *) send_client_connect_attrs(mysql, (uchar *) end);
2709
2710 res= simple_command(mysql, COM_CHANGE_USER,
2711 (uchar*)buff, (ulong)(end-buff), 1);
2712
2713 error:
2714 my_afree(buff);
2715 return res;
2716 }
2717
2718
2719 #define MAX_CONNECTION_ATTR_STORAGE_LENGTH 65536
2720
2721 /**
2722 sends a client authentication packet (second packet in the 3-way handshake)
2723
2724 Packet format (when the server is 4.0 or earlier):
2725
2726 Bytes Content
2727 ----- ----
2728 2 client capabilities
2729 3 max packet size
2730 n user name, \0-terminated
2731 9 scramble_323, \0-terminated
2732
2733 Packet format (when the server is 4.1 or newer):
2734
2735 Bytes Content
2736 ----- ----
2737 4 client capabilities
2738 4 max packet size
2739 1 charset number
2740 23 reserved (always 0)
2741 n user name, \0-terminated
2742 n plugin auth data (e.g. scramble), length encoded
2743 n database name, \0-terminated
2744 (if CLIENT_CONNECT_WITH_DB is set in the capabilities)
2745 n client auth plugin name - \0-terminated string,
2746 (if CLIENT_PLUGIN_AUTH is set in the capabilities)
2747
2748 @retval 0 ok
2749 @retval 1 error
2750 */
send_client_reply_packet(MCPVIO_EXT * mpvio,const uchar * data,int data_len)2751 static int send_client_reply_packet(MCPVIO_EXT *mpvio,
2752 const uchar *data, int data_len)
2753 {
2754 MYSQL *mysql= mpvio->mysql;
2755 NET *net= &mysql->net;
2756 char *buff, *end;
2757 size_t buff_size;
2758 size_t connect_attrs_len=
2759 (mysql->server_capabilities & CLIENT_CONNECT_ATTRS &&
2760 mysql->options.extension) ?
2761 mysql->options.extension->connection_attributes_length : 0;
2762
2763 DBUG_ASSERT(connect_attrs_len < MAX_CONNECTION_ATTR_STORAGE_LENGTH);
2764
2765
2766 /*
2767 see end= buff+32 below, fixed size of the packet is 32 bytes.
2768 +9 because data is a length encoded binary where meta data size is max 9.
2769 */
2770 buff_size= 33 + USERNAME_LENGTH + data_len + 9 + NAME_LEN + NAME_LEN + connect_attrs_len + 9;
2771 buff= my_alloca(buff_size);
2772
2773 mysql->client_flag|= mysql->options.client_flag;
2774 mysql->client_flag|= CLIENT_CAPABILITIES;
2775
2776 if (mysql->client_flag & CLIENT_MULTI_STATEMENTS)
2777 mysql->client_flag|= CLIENT_MULTI_RESULTS;
2778
2779 #if defined(HAVE_OPENSSL) && !defined(EMBEDDED_LIBRARY)
2780 if (mysql->options.ssl_key || mysql->options.ssl_cert ||
2781 mysql->options.ssl_ca || mysql->options.ssl_capath ||
2782 mysql->options.ssl_cipher ||
2783 (mysql->options.extension && mysql->options.extension->ssl_crl) ||
2784 (mysql->options.extension && mysql->options.extension->ssl_crlpath))
2785 mysql->options.use_ssl= 1;
2786 if (mysql->options.use_ssl)
2787 mysql->client_flag|= CLIENT_SSL;
2788 #endif /* HAVE_OPENSSL && !EMBEDDED_LIBRARY*/
2789 if (mpvio->db)
2790 mysql->client_flag|= CLIENT_CONNECT_WITH_DB;
2791 else
2792 mysql->client_flag&= ~CLIENT_CONNECT_WITH_DB;
2793
2794 /* Remove options that server doesn't support */
2795 mysql->client_flag= mysql->client_flag &
2796 (~(CLIENT_COMPRESS | CLIENT_SSL | CLIENT_PROTOCOL_41)
2797 | mysql->server_capabilities);
2798
2799 #ifndef HAVE_COMPRESS
2800 mysql->client_flag&= ~CLIENT_COMPRESS;
2801 #endif
2802
2803 if (mysql->client_flag & CLIENT_PROTOCOL_41)
2804 {
2805 /* 4.1 server and 4.1 client has a 32 byte option flag */
2806 int4store(buff,mysql->client_flag);
2807 int4store(buff+4, net->max_packet_size);
2808 buff[8]= (char) mysql->charset->number;
2809 memset(buff+9, 0, 32-9);
2810 end= buff+32;
2811 }
2812 else
2813 {
2814 int2store(buff, mysql->client_flag);
2815 int3store(buff+2, net->max_packet_size);
2816 end= buff+5;
2817 }
2818 #ifdef HAVE_OPENSSL
2819 /*
2820 If SSL connection is required we'll:
2821 1. check if the server supports SSL;
2822 2. check if the client is properly configured;
2823 3. try to use SSL no matter the other options given.
2824 */
2825 if (mysql->options.extension &&
2826 mysql->options.extension->ssl_mode == SSL_MODE_REQUIRED)
2827 {
2828 if (!(mysql->server_capabilities & CLIENT_SSL))
2829 {
2830 set_mysql_extended_error(mysql, CR_SSL_CONNECTION_ERROR, unknown_sqlstate,
2831 ER(CR_SSL_CONNECTION_ERROR),
2832 "Server doesn't support SSL");
2833 goto error;
2834 }
2835 if (!mysql->options.use_ssl)
2836 {
2837 set_mysql_extended_error(mysql, CR_SSL_CONNECTION_ERROR, unknown_sqlstate,
2838 ER(CR_SSL_CONNECTION_ERROR),
2839 "Client is not configured to use SSL");
2840 goto error;
2841 }
2842 mysql->client_flag|= CLIENT_SSL;
2843 }
2844 if (mysql->client_flag & CLIENT_SSL)
2845 {
2846 /* Do the SSL layering. */
2847 struct st_mysql_options *options= &mysql->options;
2848 struct st_VioSSLFd *ssl_fd;
2849 enum enum_ssl_init_error ssl_init_error;
2850 const char *cert_error;
2851 unsigned long ssl_error;
2852
2853 /*
2854 Send mysql->client_flag, max_packet_size - unencrypted otherwise
2855 the server does not know we want to do SSL
2856 */
2857 if (my_net_write(net, (uchar*)buff, (size_t) (end-buff)) || net_flush(net))
2858 {
2859 set_mysql_extended_error(mysql, CR_SERVER_LOST, unknown_sqlstate,
2860 ER(CR_SERVER_LOST_EXTENDED),
2861 "sending connection information to server",
2862 errno);
2863 goto error;
2864 }
2865
2866 /* Create the VioSSLConnectorFd - init SSL and load certs */
2867 if (!(ssl_fd= new_VioSSLConnectorFd(options->ssl_key,
2868 options->ssl_cert,
2869 options->ssl_ca,
2870 options->ssl_capath,
2871 options->ssl_cipher,
2872 &ssl_init_error,
2873 options->extension ?
2874 options->extension->ssl_crl : NULL,
2875 options->extension ?
2876 options->extension->ssl_crlpath : NULL)))
2877 {
2878 set_mysql_extended_error(mysql, CR_SSL_CONNECTION_ERROR, unknown_sqlstate,
2879 ER(CR_SSL_CONNECTION_ERROR), sslGetErrString(ssl_init_error));
2880 goto error;
2881 }
2882 mysql->connector_fd= (unsigned char *) ssl_fd;
2883
2884 /* Connect to the server */
2885 DBUG_PRINT("info", ("IO layer change in progress..."));
2886 if (sslconnect(ssl_fd, net->vio,
2887 (long) (mysql->options.connect_timeout), &ssl_error))
2888 {
2889 char buf[512];
2890 ERR_error_string_n(ssl_error, buf, 512);
2891 buf[511]= 0;
2892 set_mysql_extended_error(mysql, CR_SSL_CONNECTION_ERROR, unknown_sqlstate,
2893 ER(CR_SSL_CONNECTION_ERROR),
2894 buf);
2895 goto error;
2896 }
2897 DBUG_PRINT("info", ("IO layer change done!"));
2898
2899 /* Verify server cert */
2900 if ((mysql->client_flag & CLIENT_SSL_VERIFY_SERVER_CERT) &&
2901 ssl_verify_server_cert(net->vio, mysql->host, &cert_error))
2902 {
2903 set_mysql_extended_error(mysql, CR_SSL_CONNECTION_ERROR, unknown_sqlstate,
2904 ER(CR_SSL_CONNECTION_ERROR), cert_error);
2905 goto error;
2906 }
2907 }
2908 #endif /* HAVE_OPENSSL */
2909
2910 DBUG_PRINT("info",("Server version = '%s' capabilites: %lu status: %u client_flag: %lu",
2911 mysql->server_version, mysql->server_capabilities,
2912 mysql->server_status, mysql->client_flag));
2913
2914 compile_time_assert(MYSQL_USERNAME_LENGTH == USERNAME_LENGTH);
2915
2916 /* This needs to be changed as it's not useful with big packets */
2917 if (mysql->user[0])
2918 strmake(end, mysql->user, USERNAME_LENGTH);
2919 else
2920 read_user_name(end);
2921
2922 /* We have to handle different version of handshake here */
2923 DBUG_PRINT("info",("user: %s",end));
2924 end= strend(end) + 1;
2925 if (data_len)
2926 {
2927 if (mysql->server_capabilities & CLIENT_SECURE_CONNECTION)
2928 {
2929 /*
2930 Since the older versions of server do not have
2931 CLIENT_PLUGIN_AUTH_LENENC_CLIENT_DATA capability,
2932 a check is performed on this before sending auth data.
2933 If lenenc support is not available, the data is sent
2934 in the format of first byte representing the length of
2935 the string followed by the actual string.
2936 */
2937 if (mysql->server_capabilities & CLIENT_PLUGIN_AUTH_LENENC_CLIENT_DATA)
2938 end= write_length_encoded_string4(end, (char *)(buff + buff_size),
2939 (char *) data,
2940 (char *)(data + data_len));
2941 else
2942 end= write_string(end, (char *)(buff + buff_size),
2943 (char *) data,
2944 (char *)(data + data_len));
2945 if (end == NULL)
2946 goto error;
2947 }
2948 else
2949 {
2950 DBUG_ASSERT(data_len == SCRAMBLE_LENGTH_323 + 1); /* incl. \0 at the end */
2951 memcpy(end, data, data_len);
2952 end+= data_len;
2953 }
2954 }
2955 else
2956 *end++= 0;
2957
2958 /* Add database if needed */
2959 if (mpvio->db && (mysql->server_capabilities & CLIENT_CONNECT_WITH_DB))
2960 {
2961 end= strmake(end, mpvio->db, NAME_LEN) + 1;
2962 mysql->db= my_strdup(mpvio->db, MYF(MY_WME));
2963 }
2964
2965 if (mysql->server_capabilities & CLIENT_PLUGIN_AUTH)
2966 end= strmake(end, mpvio->plugin->name, NAME_LEN) + 1;
2967
2968 end= (char *) send_client_connect_attrs(mysql, (uchar *) end);
2969
2970 /* Write authentication package */
2971 if (my_net_write(net, (uchar*) buff, (size_t) (end-buff)) || net_flush(net))
2972 {
2973 set_mysql_extended_error(mysql, CR_SERVER_LOST, unknown_sqlstate,
2974 ER(CR_SERVER_LOST_EXTENDED),
2975 "sending authentication information",
2976 errno);
2977 goto error;
2978 }
2979 my_afree(buff);
2980 return 0;
2981
2982 error:
2983 my_afree(buff);
2984 return 1;
2985 }
2986
2987 /**
2988 vio->read_packet() callback method for client authentication plugins
2989
2990 This function is called by a client authentication plugin, when it wants
2991 to read data from the server.
2992 */
client_mpvio_read_packet(struct st_plugin_vio * mpv,uchar ** buf)2993 static int client_mpvio_read_packet(struct st_plugin_vio *mpv, uchar **buf)
2994 {
2995 MCPVIO_EXT *mpvio= (MCPVIO_EXT*)mpv;
2996 MYSQL *mysql= mpvio->mysql;
2997 ulong pkt_len;
2998
2999 /* there are cached data left, feed it to a plugin */
3000 if (mpvio->cached_server_reply.pkt)
3001 {
3002 *buf= mpvio->cached_server_reply.pkt;
3003 mpvio->cached_server_reply.pkt= 0;
3004 mpvio->packets_read++;
3005 return mpvio->cached_server_reply.pkt_len;
3006 }
3007
3008 if (mpvio->packets_read == 0)
3009 {
3010 /*
3011 the server handshake packet came from the wrong plugin,
3012 or it's mysql_change_user(). Either way, there is no data
3013 for a plugin to read. send a dummy packet to the server
3014 to initiate a dialog.
3015 */
3016 if (client_mpvio_write_packet(mpv, 0, 0))
3017 return (int)packet_error;
3018 }
3019
3020 /* otherwise read the data */
3021 pkt_len= (*mysql->methods->read_change_user_result)(mysql);
3022 mpvio->last_read_packet_len= pkt_len;
3023 *buf= mysql->net.read_pos;
3024
3025 /* was it a request to change plugins ? */
3026 if (**buf == 254)
3027 return (int)packet_error; /* if yes, this plugin shan't continue */
3028
3029 /*
3030 the server sends \1\255 or \1\254 instead of just \255 or \254 -
3031 for us to not confuse it with an error or "change plugin" packets.
3032 We remove this escaping \1 here.
3033
3034 See also server_mpvio_write_packet() where the escaping is done.
3035 */
3036 if (pkt_len && **buf == 1)
3037 {
3038 (*buf)++;
3039 pkt_len--;
3040 }
3041 mpvio->packets_read++;
3042 return pkt_len;
3043 }
3044
3045 /**
3046 vio->write_packet() callback method for client authentication plugins
3047
3048 This function is called by a client authentication plugin, when it wants
3049 to send data to the server.
3050
3051 It transparently wraps the data into a change user or authentication
3052 handshake packet, if neccessary.
3053 */
client_mpvio_write_packet(struct st_plugin_vio * mpv,const uchar * pkt,int pkt_len)3054 static int client_mpvio_write_packet(struct st_plugin_vio *mpv,
3055 const uchar *pkt, int pkt_len)
3056 {
3057 int res;
3058 MCPVIO_EXT *mpvio= (MCPVIO_EXT*)mpv;
3059
3060 if (mpvio->packets_written == 0)
3061 {
3062 if (mpvio->mysql_change_user)
3063 res= send_change_user_packet(mpvio, pkt, pkt_len);
3064 else
3065 res= send_client_reply_packet(mpvio, pkt, pkt_len);
3066 }
3067 else
3068 {
3069 NET *net= &mpvio->mysql->net;
3070 if (mpvio->mysql->thd)
3071 res= 1; /* no chit-chat in embedded */
3072 else
3073 res= my_net_write(net, pkt, pkt_len) || net_flush(net);
3074 if (res)
3075 set_mysql_extended_error(mpvio->mysql, CR_SERVER_LOST, unknown_sqlstate,
3076 ER(CR_SERVER_LOST_EXTENDED),
3077 "sending authentication information",
3078 errno);
3079 }
3080 mpvio->packets_written++;
3081 return res;
3082 }
3083
3084 /**
3085 fills MYSQL_PLUGIN_VIO_INFO structure with the information about the
3086 connection
3087 */
mpvio_info(Vio * vio,MYSQL_PLUGIN_VIO_INFO * info)3088 void mpvio_info(Vio *vio, MYSQL_PLUGIN_VIO_INFO *info)
3089 {
3090 memset(info, 0, sizeof(*info));
3091 switch (vio->type) {
3092 case VIO_TYPE_TCPIP:
3093 info->protocol= MYSQL_VIO_TCP;
3094 info->socket= vio_fd(vio);
3095 return;
3096 case VIO_TYPE_SOCKET:
3097 info->protocol= MYSQL_VIO_SOCKET;
3098 info->socket= vio_fd(vio);
3099 return;
3100 case VIO_TYPE_SSL:
3101 {
3102 struct sockaddr addr;
3103 socklen_t addrlen= sizeof(addr);
3104 if (getsockname(vio_fd(vio), &addr, &addrlen))
3105 return;
3106 info->protocol= addr.sa_family == AF_UNIX ?
3107 MYSQL_VIO_SOCKET : MYSQL_VIO_TCP;
3108 info->socket= vio_fd(vio);
3109 return;
3110 }
3111 #ifdef _WIN32
3112 case VIO_TYPE_NAMEDPIPE:
3113 info->protocol= MYSQL_VIO_PIPE;
3114 info->handle= vio->hPipe;
3115 return;
3116 #ifdef HAVE_SMEM
3117 case VIO_TYPE_SHARED_MEMORY:
3118 info->protocol= MYSQL_VIO_MEMORY;
3119 info->handle= vio->handle_file_map; /* or what ? */
3120 return;
3121 #endif
3122 #endif
3123 default: DBUG_ASSERT(0);
3124 }
3125 }
3126
client_mpvio_info(MYSQL_PLUGIN_VIO * vio,MYSQL_PLUGIN_VIO_INFO * info)3127 static void client_mpvio_info(MYSQL_PLUGIN_VIO *vio,
3128 MYSQL_PLUGIN_VIO_INFO *info)
3129 {
3130 MCPVIO_EXT *mpvio= (MCPVIO_EXT*)vio;
3131 mpvio_info(mpvio->mysql->net.vio, info);
3132 }
3133
3134
3135 my_bool libmysql_cleartext_plugin_enabled= 0;
3136
check_plugin_enabled(MYSQL * mysql,auth_plugin_t * plugin)3137 static my_bool check_plugin_enabled(MYSQL *mysql, auth_plugin_t *plugin)
3138 {
3139 if (plugin == &clear_password_client_plugin &&
3140 (!libmysql_cleartext_plugin_enabled &&
3141 (!mysql->options.extension ||
3142 !mysql->options.extension->enable_cleartext_plugin)))
3143 {
3144 set_mysql_extended_error(mysql, CR_AUTH_PLUGIN_CANNOT_LOAD,
3145 unknown_sqlstate,
3146 ER(CR_AUTH_PLUGIN_CANNOT_LOAD),
3147 clear_password_client_plugin.name,
3148 "plugin not enabled");
3149 return TRUE;
3150 }
3151 return FALSE;
3152 }
3153
3154
3155 /**
3156 Client side of the plugin driver authentication.
3157
3158 @note this is used by both the mysql_real_connect and mysql_change_user
3159
3160 @param mysql mysql
3161 @param data pointer to the plugin auth data (scramble) in the
3162 handshake packet
3163 @param data_len the length of the data
3164 @param data_plugin a plugin that data were prepared for
3165 or 0 if it's mysql_change_user()
3166 @param db initial db to use, can be 0
3167
3168 @retval 0 ok
3169 @retval 1 error
3170 */
run_plugin_auth(MYSQL * mysql,char * data,uint data_len,const char * data_plugin,const char * db)3171 int run_plugin_auth(MYSQL *mysql, char *data, uint data_len,
3172 const char *data_plugin, const char *db)
3173 {
3174 const char *auth_plugin_name;
3175 auth_plugin_t *auth_plugin;
3176 MCPVIO_EXT mpvio;
3177 ulong pkt_length;
3178 int res;
3179
3180 DBUG_ENTER ("run_plugin_auth");
3181 /* determine the default/initial plugin to use */
3182 if (mysql->options.extension && mysql->options.extension->default_auth &&
3183 mysql->server_capabilities & CLIENT_PLUGIN_AUTH)
3184 {
3185 auth_plugin_name= mysql->options.extension->default_auth;
3186 if (!(auth_plugin= (auth_plugin_t*) mysql_client_find_plugin(mysql,
3187 auth_plugin_name, MYSQL_CLIENT_AUTHENTICATION_PLUGIN)))
3188 DBUG_RETURN (1); /* oops, not found */
3189 }
3190 else
3191 {
3192 auth_plugin= mysql->server_capabilities & CLIENT_PROTOCOL_41 ?
3193 &native_password_client_plugin : &old_password_client_plugin;
3194 auth_plugin_name= auth_plugin->name;
3195 }
3196
3197 if (check_plugin_enabled(mysql, auth_plugin))
3198 DBUG_RETURN(1);
3199
3200 DBUG_PRINT ("info", ("using plugin %s", auth_plugin_name));
3201
3202 mysql->net.last_errno= 0; /* just in case */
3203
3204 if (data_plugin && strcmp(data_plugin, auth_plugin_name))
3205 {
3206 /* data was prepared for a different plugin, don't show it to this one */
3207 data= 0;
3208 data_len= 0;
3209 }
3210
3211 mpvio.mysql_change_user= data_plugin == 0;
3212 mpvio.cached_server_reply.pkt= (uchar*)data;
3213 mpvio.cached_server_reply.pkt_len= data_len;
3214 mpvio.read_packet= client_mpvio_read_packet;
3215 mpvio.write_packet= client_mpvio_write_packet;
3216 mpvio.info= client_mpvio_info;
3217 mpvio.mysql= mysql;
3218 mpvio.packets_read= mpvio.packets_written= 0;
3219 mpvio.db= db;
3220 mpvio.plugin= auth_plugin;
3221
3222 res= auth_plugin->authenticate_user((struct st_plugin_vio *)&mpvio, mysql);
3223 DBUG_PRINT ("info", ("authenticate_user returned %s",
3224 res == CR_OK ? "CR_OK" :
3225 res == CR_ERROR ? "CR_ERROR" :
3226 res == CR_OK_HANDSHAKE_COMPLETE ?
3227 "CR_OK_HANDSHAKE_COMPLETE" : "error"));
3228
3229 compile_time_assert(CR_OK == -1);
3230 compile_time_assert(CR_ERROR == 0);
3231
3232 /*
3233 The connection may be closed. If so: do not try to read from the buffer.
3234 */
3235 if (res > CR_OK &&
3236 (!my_net_is_inited(&mysql->net) || mysql->net.read_pos[0] != 254))
3237 {
3238 /*
3239 the plugin returned an error. write it down in mysql,
3240 unless the error code is CR_ERROR and mysql->net.last_errno
3241 is already set (the plugin has done it)
3242 */
3243 DBUG_PRINT ("info", ("res=%d", res));
3244 if (res > CR_ERROR)
3245 set_mysql_error(mysql, res, unknown_sqlstate);
3246 else
3247 if (!mysql->net.last_errno)
3248 set_mysql_error(mysql, CR_UNKNOWN_ERROR, unknown_sqlstate);
3249 DBUG_RETURN (1);
3250 }
3251
3252 /* read the OK packet (or use the cached value in mysql->net.read_pos */
3253 if (res == CR_OK)
3254 pkt_length= (*mysql->methods->read_change_user_result)(mysql);
3255 else /* res == CR_OK_HANDSHAKE_COMPLETE */
3256 pkt_length= mpvio.last_read_packet_len;
3257
3258 DBUG_PRINT ("info", ("OK packet length=%lu", pkt_length));
3259 if (pkt_length == packet_error)
3260 {
3261 if (mysql->net.last_errno == CR_SERVER_LOST)
3262 set_mysql_extended_error(mysql, CR_SERVER_LOST, unknown_sqlstate,
3263 ER(CR_SERVER_LOST_EXTENDED),
3264 "reading authorization packet",
3265 errno);
3266 DBUG_RETURN (1);
3267 }
3268
3269 if (mysql->net.read_pos[0] == 254)
3270 {
3271 /* The server asked to use a different authentication plugin */
3272 if (pkt_length == 1)
3273 {
3274 /* old "use short scramble" packet */
3275 DBUG_PRINT ("info", ("old use short scramble packet from server"));
3276 auth_plugin_name= old_password_plugin_name;
3277 mpvio.cached_server_reply.pkt= (uchar*)mysql->scramble;
3278 mpvio.cached_server_reply.pkt_len= SCRAMBLE_LENGTH + 1;
3279 }
3280 else
3281 {
3282 /* new "use different plugin" packet */
3283 uint len;
3284 auth_plugin_name= (char*)mysql->net.read_pos + 1;
3285 len= strlen(auth_plugin_name); /* safe as my_net_read always appends \0 */
3286 mpvio.cached_server_reply.pkt_len= pkt_length - len - 2;
3287 mpvio.cached_server_reply.pkt= mysql->net.read_pos + len + 2;
3288 DBUG_PRINT ("info", ("change plugin packet from server for plugin %s",
3289 auth_plugin_name));
3290 }
3291
3292 if (!(auth_plugin= (auth_plugin_t *) mysql_client_find_plugin(mysql,
3293 auth_plugin_name, MYSQL_CLIENT_AUTHENTICATION_PLUGIN)))
3294 DBUG_RETURN (1);
3295
3296 if (check_plugin_enabled(mysql, auth_plugin))
3297 DBUG_RETURN(1);
3298
3299 mpvio.plugin= auth_plugin;
3300 res= auth_plugin->authenticate_user((struct st_plugin_vio *)&mpvio, mysql);
3301
3302 DBUG_PRINT ("info", ("second authenticate_user returned %s",
3303 res == CR_OK ? "CR_OK" :
3304 res == CR_ERROR ? "CR_ERROR" :
3305 res == CR_OK_HANDSHAKE_COMPLETE ?
3306 "CR_OK_HANDSHAKE_COMPLETE" : "error"));
3307 if (res > CR_OK)
3308 {
3309 if (res > CR_ERROR)
3310 set_mysql_error(mysql, res, unknown_sqlstate);
3311 else
3312 if (!mysql->net.last_errno)
3313 set_mysql_error(mysql, CR_UNKNOWN_ERROR, unknown_sqlstate);
3314 DBUG_RETURN (1);
3315 }
3316
3317 if (res != CR_OK_HANDSHAKE_COMPLETE)
3318 {
3319 /* Read what server thinks about out new auth message report */
3320 if (cli_safe_read(mysql) == packet_error)
3321 {
3322 if (mysql->net.last_errno == CR_SERVER_LOST)
3323 set_mysql_extended_error(mysql, CR_SERVER_LOST, unknown_sqlstate,
3324 ER(CR_SERVER_LOST_EXTENDED),
3325 "reading final connect information",
3326 errno);
3327 DBUG_RETURN (1);
3328 }
3329 }
3330 }
3331 /*
3332 net->read_pos[0] should always be 0 here if the server implements
3333 the protocol correctly
3334 */
3335 DBUG_RETURN (mysql->net.read_pos[0] != 0);
3336 }
3337
3338
3339 /** set some default attributes */
3340 static int
set_connect_attributes(MYSQL * mysql,char * buff,size_t buf_len)3341 set_connect_attributes(MYSQL *mysql, char *buff, size_t buf_len)
3342 {
3343 int rc= 0;
3344
3345 /*
3346 Clean up any values set by the client code. We want these options as
3347 consistent as possible
3348 */
3349 rc+= mysql_options(mysql, MYSQL_OPT_CONNECT_ATTR_DELETE, "_client_name");
3350 rc+= mysql_options(mysql, MYSQL_OPT_CONNECT_ATTR_DELETE, "_os");
3351 rc+= mysql_options(mysql, MYSQL_OPT_CONNECT_ATTR_DELETE, "_platform");
3352 rc+= mysql_options(mysql, MYSQL_OPT_CONNECT_ATTR_DELETE, "_pid");
3353 rc+= mysql_options(mysql, MYSQL_OPT_CONNECT_ATTR_DELETE, "_thread");
3354 rc+= mysql_options(mysql, MYSQL_OPT_CONNECT_ATTR_DELETE, "_client_version");
3355
3356 /*
3357 Now let's set up some values
3358 */
3359 rc+= mysql_options4(mysql, MYSQL_OPT_CONNECT_ATTR_ADD,
3360 "_client_name", "libmysql");
3361 rc+= mysql_options4(mysql, MYSQL_OPT_CONNECT_ATTR_ADD,
3362 "_client_version", PACKAGE_VERSION);
3363 rc+= mysql_options4(mysql, MYSQL_OPT_CONNECT_ATTR_ADD,
3364 "_os", SYSTEM_TYPE);
3365 rc+= mysql_options4(mysql, MYSQL_OPT_CONNECT_ATTR_ADD,
3366 "_platform", MACHINE_TYPE);
3367 #ifdef __WIN__
3368 snprintf(buff, buf_len, "%lu", (ulong) GetCurrentProcessId());
3369 #else
3370 snprintf(buff, buf_len, "%lu", (ulong) getpid());
3371 #endif
3372 rc+= mysql_options4(mysql, MYSQL_OPT_CONNECT_ATTR_ADD, "_pid", buff);
3373
3374 #ifdef __WIN__
3375 snprintf(buff, buf_len, "%lu", (ulong) GetCurrentThreadId());
3376 rc+= mysql_options4(mysql, MYSQL_OPT_CONNECT_ATTR_ADD, "_thread", buff);
3377 #endif
3378
3379 return rc > 0 ? 1 : 0;
3380 }
3381
3382
3383 MYSQL * STDCALL
CLI_MYSQL_REAL_CONNECT(MYSQL * mysql,const char * host,const char * user,const char * passwd,const char * db,uint port,const char * unix_socket,ulong client_flag)3384 CLI_MYSQL_REAL_CONNECT(MYSQL *mysql,const char *host, const char *user,
3385 const char *passwd, const char *db,
3386 uint port, const char *unix_socket,ulong client_flag)
3387 {
3388 char buff[NAME_LEN+USERNAME_LENGTH+100];
3389 int scramble_data_len, pkt_scramble_len= 0;
3390 char *end,*host_info= 0, *server_version_end, *pkt_end;
3391 char *scramble_data;
3392 const char *scramble_plugin;
3393 ulong pkt_length;
3394 NET *net= &mysql->net;
3395 #ifdef __WIN__
3396 HANDLE hPipe=INVALID_HANDLE_VALUE;
3397 #endif
3398 #ifdef HAVE_SYS_UN_H
3399 struct sockaddr_un UNIXaddr;
3400 #endif
3401 DBUG_ENTER("mysql_real_connect");
3402
3403 DBUG_PRINT("enter",("host: %s db: %s user: %s (client)",
3404 host ? host : "(Null)",
3405 db ? db : "(Null)",
3406 user ? user : "(Null)"));
3407
3408 /* Test whether we're already connected */
3409 if (net->vio)
3410 {
3411 set_mysql_error(mysql, CR_ALREADY_CONNECTED, unknown_sqlstate);
3412 DBUG_RETURN(0);
3413 }
3414
3415 if (set_connect_attributes(mysql, buff, sizeof(buff)))
3416 DBUG_RETURN(0);
3417
3418 mysql->methods= &client_methods;
3419 net->vio = 0; /* If something goes wrong */
3420 mysql->client_flag=0; /* For handshake */
3421
3422 /* use default options */
3423 if (mysql->options.my_cnf_file || mysql->options.my_cnf_group)
3424 {
3425 mysql_read_default_options(&mysql->options,
3426 (mysql->options.my_cnf_file ?
3427 mysql->options.my_cnf_file : "my"),
3428 mysql->options.my_cnf_group);
3429 my_free(mysql->options.my_cnf_file);
3430 my_free(mysql->options.my_cnf_group);
3431 mysql->options.my_cnf_file=mysql->options.my_cnf_group=0;
3432 }
3433
3434 /* Some empty-string-tests are done because of ODBC */
3435 if (!host || !host[0])
3436 host=mysql->options.host;
3437 if (!user || !user[0])
3438 {
3439 user=mysql->options.user;
3440 if (!user)
3441 user= "";
3442 }
3443 if (!passwd)
3444 {
3445 passwd=mysql->options.password;
3446 #if !defined(DONT_USE_MYSQL_PWD) && !defined(MYSQL_SERVER)
3447 if (!passwd)
3448 passwd=getenv("MYSQL_PWD"); /* get it from environment */
3449 #endif
3450 if (!passwd)
3451 passwd= "";
3452 }
3453 if (!db || !db[0])
3454 db=mysql->options.db;
3455 if (!port)
3456 port=mysql->options.port;
3457 if (!unix_socket)
3458 unix_socket=mysql->options.unix_socket;
3459
3460 mysql->server_status=SERVER_STATUS_AUTOCOMMIT;
3461 DBUG_PRINT("info", ("Connecting"));
3462
3463 /*
3464 Part 0: Grab a socket and connect it to the server
3465 */
3466 #if defined(HAVE_SMEM)
3467 if ((!mysql->options.protocol ||
3468 mysql->options.protocol == MYSQL_PROTOCOL_MEMORY) &&
3469 (!host || !strcmp(host,LOCAL_HOST)))
3470 {
3471 HANDLE handle_map;
3472 DBUG_PRINT("info", ("Using shared memory"));
3473
3474 handle_map= create_shared_memory(mysql, net,
3475 get_win32_connect_timeout(mysql));
3476
3477 if (handle_map == INVALID_HANDLE_VALUE)
3478 {
3479 DBUG_PRINT("error",
3480 ("host: '%s' socket: '%s' shared memory: %s have_tcpip: %d",
3481 host ? host : "<null>",
3482 unix_socket ? unix_socket : "<null>",
3483 (int) mysql->options.shared_memory_base_name,
3484 (int) have_tcpip));
3485 if (mysql->options.protocol == MYSQL_PROTOCOL_MEMORY)
3486 goto error;
3487
3488 /*
3489 Try also with PIPE or TCP/IP. Clear the error from
3490 create_shared_memory().
3491 */
3492
3493 net_clear_error(net);
3494 }
3495 else
3496 {
3497 mysql->options.protocol=MYSQL_PROTOCOL_MEMORY;
3498 unix_socket = 0;
3499 host=mysql->options.shared_memory_base_name;
3500 my_snprintf(host_info=buff, sizeof(buff)-1,
3501 ER(CR_SHARED_MEMORY_CONNECTION), host);
3502 }
3503 }
3504 #endif /* HAVE_SMEM */
3505 #if defined(HAVE_SYS_UN_H)
3506 if (!net->vio &&
3507 (!mysql->options.protocol ||
3508 mysql->options.protocol == MYSQL_PROTOCOL_SOCKET) &&
3509 (unix_socket || mysql_unix_port) &&
3510 (!host || !strcmp(host,LOCAL_HOST)))
3511 {
3512 my_socket sock= socket(AF_UNIX, SOCK_STREAM, 0);
3513 DBUG_PRINT("info", ("Using socket"));
3514 if (sock == SOCKET_ERROR)
3515 {
3516 set_mysql_extended_error(mysql, CR_SOCKET_CREATE_ERROR,
3517 unknown_sqlstate,
3518 ER(CR_SOCKET_CREATE_ERROR),
3519 socket_errno);
3520 goto error;
3521 }
3522
3523 net->vio= vio_new(sock, VIO_TYPE_SOCKET,
3524 VIO_LOCALHOST | VIO_BUFFERED_READ);
3525 if (!net->vio)
3526 {
3527 DBUG_PRINT("error",("Unknow protocol %d ", mysql->options.protocol));
3528 set_mysql_error(mysql, CR_CONN_UNKNOW_PROTOCOL, unknown_sqlstate);
3529 closesocket(sock);
3530 goto error;
3531 }
3532
3533 host= LOCAL_HOST;
3534 if (!unix_socket)
3535 unix_socket= mysql_unix_port;
3536 host_info= (char*) ER(CR_LOCALHOST_CONNECTION);
3537 DBUG_PRINT("info", ("Using UNIX sock '%s'", unix_socket));
3538
3539 memset(&UNIXaddr, 0, sizeof(UNIXaddr));
3540 UNIXaddr.sun_family= AF_UNIX;
3541 strmake(UNIXaddr.sun_path, unix_socket, sizeof(UNIXaddr.sun_path)-1);
3542
3543 if (vio_socket_connect(net->vio, (struct sockaddr *) &UNIXaddr,
3544 sizeof(UNIXaddr), get_vio_connect_timeout(mysql)))
3545 {
3546 DBUG_PRINT("error",("Got error %d on connect to local server",
3547 socket_errno));
3548 set_mysql_extended_error(mysql, CR_CONNECTION_ERROR,
3549 unknown_sqlstate,
3550 ER(CR_CONNECTION_ERROR),
3551 unix_socket, socket_errno);
3552 vio_delete(net->vio);
3553 net->vio= 0;
3554 goto error;
3555 }
3556 mysql->options.protocol=MYSQL_PROTOCOL_SOCKET;
3557 }
3558 #elif defined(_WIN32)
3559 if (!net->vio &&
3560 (mysql->options.protocol == MYSQL_PROTOCOL_PIPE ||
3561 (host && !strcmp(host,LOCAL_HOST_NAMEDPIPE)) ||
3562 (! have_tcpip && (unix_socket || !host && is_NT()))))
3563 {
3564 hPipe= create_named_pipe(mysql, get_win32_connect_timeout(mysql),
3565 &host, &unix_socket);
3566
3567 if (hPipe == INVALID_HANDLE_VALUE)
3568 {
3569 DBUG_PRINT("error",
3570 ("host: '%s' socket: '%s' have_tcpip: %d",
3571 host ? host : "<null>",
3572 unix_socket ? unix_socket : "<null>",
3573 (int) have_tcpip));
3574 if (mysql->options.protocol == MYSQL_PROTOCOL_PIPE ||
3575 (host && !strcmp(host,LOCAL_HOST_NAMEDPIPE)) ||
3576 (unix_socket && !strcmp(unix_socket,MYSQL_NAMEDPIPE)))
3577 goto error;
3578 /* Try also with TCP/IP */
3579 }
3580 else
3581 {
3582 net->vio= vio_new_win32pipe(hPipe);
3583 my_snprintf(host_info=buff, sizeof(buff)-1,
3584 ER(CR_NAMEDPIPE_CONNECTION), unix_socket);
3585 }
3586 }
3587 #endif
3588 DBUG_PRINT("info", ("net->vio: %p protocol: %d",
3589 net->vio, mysql->options.protocol));
3590 if (!net->vio &&
3591 (!mysql->options.protocol ||
3592 mysql->options.protocol == MYSQL_PROTOCOL_TCP))
3593 {
3594 struct addrinfo *res_lst, *client_bind_ai_lst= NULL, hints, *t_res;
3595 char port_buf[NI_MAXSERV];
3596 my_socket sock= SOCKET_ERROR;
3597 int gai_errno, saved_error= 0, status= -1, bind_result= 0;
3598 uint flags= VIO_BUFFERED_READ;
3599
3600 unix_socket=0; /* This is not used */
3601
3602 if (!port)
3603 port= mysql_port;
3604
3605 if (!host)
3606 host= LOCAL_HOST;
3607
3608 my_snprintf(host_info=buff, sizeof(buff)-1, ER(CR_TCP_CONNECTION), host);
3609 DBUG_PRINT("info",("Server name: '%s'. TCP sock: %d", host, port));
3610
3611 memset(&hints, 0, sizeof(hints));
3612 hints.ai_socktype= SOCK_STREAM;
3613 hints.ai_protocol= IPPROTO_TCP;
3614 hints.ai_family= AF_UNSPEC;
3615
3616 DBUG_PRINT("info",("IPV6 getaddrinfo %s", host));
3617 my_snprintf(port_buf, NI_MAXSERV, "%d", port);
3618 gai_errno= getaddrinfo(host, port_buf, &hints, &res_lst);
3619
3620 if (gai_errno != 0)
3621 {
3622 /*
3623 For DBUG we are keeping the right message but for client we default to
3624 historical error message.
3625 */
3626 DBUG_PRINT("info",("IPV6 getaddrinfo error %d", gai_errno));
3627 set_mysql_extended_error(mysql, CR_UNKNOWN_HOST, unknown_sqlstate,
3628 ER(CR_UNKNOWN_HOST), host, errno);
3629
3630 goto error;
3631 }
3632
3633 /* Get address info for client bind name if it is provided */
3634 if (mysql->options.ci.bind_address)
3635 {
3636 int bind_gai_errno= 0;
3637
3638 DBUG_PRINT("info",("Resolving addresses for client bind: '%s'",
3639 mysql->options.ci.bind_address));
3640 /* Lookup address info for name */
3641 bind_gai_errno= getaddrinfo(mysql->options.ci.bind_address, 0,
3642 &hints, &client_bind_ai_lst);
3643 if (bind_gai_errno)
3644 {
3645 DBUG_PRINT("info",("client bind getaddrinfo error %d", bind_gai_errno));
3646 set_mysql_extended_error(mysql, CR_UNKNOWN_HOST, unknown_sqlstate,
3647 ER(CR_UNKNOWN_HOST),
3648 mysql->options.ci.bind_address,
3649 bind_gai_errno);
3650
3651 freeaddrinfo(res_lst);
3652 goto error;
3653 }
3654 DBUG_PRINT("info", (" got address info for client bind name"));
3655 }
3656
3657 /*
3658 A hostname might map to multiple IP addresses (IPv4/IPv6). Go over the
3659 list of IP addresses until a successful connection can be established.
3660 For each IP address, attempt to bind the socket to each client address
3661 for the client-side bind hostname until the bind is successful.
3662 */
3663 DBUG_PRINT("info", ("Try connect on all addresses for host."));
3664 for (t_res= res_lst; t_res; t_res= t_res->ai_next)
3665 {
3666 DBUG_PRINT("info", ("Create socket, family: %d type: %d proto: %d",
3667 t_res->ai_family, t_res->ai_socktype,
3668 t_res->ai_protocol));
3669
3670 sock= socket(t_res->ai_family, t_res->ai_socktype, t_res->ai_protocol);
3671 if (sock == SOCKET_ERROR)
3672 {
3673 DBUG_PRINT("info", ("Socket created was invalid"));
3674 /* Try next address if there is one */
3675 saved_error= socket_errno;
3676 continue;
3677 }
3678
3679 if (client_bind_ai_lst)
3680 {
3681 struct addrinfo* curr_bind_ai= NULL;
3682 DBUG_PRINT("info", ("Attempting to bind socket to bind address(es)"));
3683
3684 /*
3685 We'll attempt to bind to each of the addresses returned, until
3686 we find one that works.
3687 If none works, we'll try the next destination host address
3688 (if any)
3689 */
3690 curr_bind_ai= client_bind_ai_lst;
3691
3692 while (curr_bind_ai != NULL)
3693 {
3694 /* Attempt to bind the socket to the given address */
3695 bind_result= bind(sock,
3696 curr_bind_ai->ai_addr,
3697 curr_bind_ai->ai_addrlen);
3698 if (!bind_result)
3699 break; /* Success */
3700
3701 DBUG_PRINT("info", ("bind failed, attempting another bind address"));
3702 /* Problem with the bind, move to next address if present */
3703 curr_bind_ai= curr_bind_ai->ai_next;
3704 }
3705
3706 if (bind_result)
3707 {
3708 /*
3709 Could not bind to any client-side address with this destination
3710 Try the next destination address (if any)
3711 */
3712 DBUG_PRINT("info", ("All bind attempts with this address failed"));
3713 saved_error= socket_errno;
3714 closesocket(sock);
3715 continue;
3716 }
3717 DBUG_PRINT("info", ("Successfully bound client side of socket"));
3718 }
3719
3720 /* Create a new Vio object to abstract the socket. */
3721 if (!net->vio)
3722 {
3723 if (!(net->vio= vio_new(sock, VIO_TYPE_TCPIP, flags)))
3724 {
3725 set_mysql_error(mysql, CR_OUT_OF_MEMORY, unknown_sqlstate);
3726 closesocket(sock);
3727 freeaddrinfo(res_lst);
3728 if (client_bind_ai_lst)
3729 freeaddrinfo(client_bind_ai_lst);
3730 goto error;
3731 }
3732 }
3733 /* Just reinitialize if one is already allocated. */
3734 else if (vio_reset(net->vio, VIO_TYPE_TCPIP, sock, NULL, flags))
3735 {
3736 set_mysql_error(mysql, CR_UNKNOWN_ERROR, unknown_sqlstate);
3737 closesocket(sock);
3738 freeaddrinfo(res_lst);
3739 if (client_bind_ai_lst)
3740 freeaddrinfo(client_bind_ai_lst);
3741 goto error;
3742 }
3743
3744 DBUG_PRINT("info", ("Connect socket"));
3745 status= vio_socket_connect(net->vio, t_res->ai_addr, t_res->ai_addrlen,
3746 get_vio_connect_timeout(mysql));
3747 /*
3748 Here we rely on vio_socket_connect() to return success only if
3749 the connect attempt was really successful. Otherwise we would
3750 stop trying another address, believing we were successful.
3751 */
3752 if (!status)
3753 break;
3754
3755 /*
3756 Save either the socket error status or the error code of
3757 the failed vio_connection operation. It is necessary to
3758 avoid having it overwritten by later operations.
3759 */
3760 saved_error= socket_errno;
3761
3762 DBUG_PRINT("info", ("No success, try next address."));
3763 }
3764 DBUG_PRINT("info",
3765 ("End of connect attempts, sock: %d status: %d error: %d",
3766 sock, status, saved_error));
3767
3768 freeaddrinfo(res_lst);
3769 if (client_bind_ai_lst)
3770 freeaddrinfo(client_bind_ai_lst);
3771
3772 if (sock == SOCKET_ERROR)
3773 {
3774 set_mysql_extended_error(mysql, CR_IPSOCK_ERROR, unknown_sqlstate,
3775 ER(CR_IPSOCK_ERROR), saved_error);
3776 goto error;
3777 }
3778
3779 if (status)
3780 {
3781 DBUG_PRINT("error",("Got error %d on connect to '%s'", saved_error, host));
3782 set_mysql_extended_error(mysql, CR_CONN_HOST_ERROR, unknown_sqlstate,
3783 ER(CR_CONN_HOST_ERROR), host, saved_error);
3784 goto error;
3785 }
3786 }
3787
3788 DBUG_PRINT("info", ("net->vio: %p", net->vio));
3789 if (!net->vio)
3790 {
3791 DBUG_PRINT("error",("Unknow protocol %d ",mysql->options.protocol));
3792 set_mysql_error(mysql, CR_CONN_UNKNOW_PROTOCOL, unknown_sqlstate);
3793 goto error;
3794 }
3795
3796 if (my_net_init(net, net->vio))
3797 {
3798 vio_delete(net->vio);
3799 net->vio = 0;
3800 set_mysql_error(mysql, CR_OUT_OF_MEMORY, unknown_sqlstate);
3801 goto error;
3802 }
3803 vio_keepalive(net->vio,TRUE);
3804
3805 /* If user set read_timeout, let it override the default */
3806 if (mysql->options.read_timeout)
3807 my_net_set_read_timeout(net, mysql->options.read_timeout);
3808
3809 /* If user set write_timeout, let it override the default */
3810 if (mysql->options.write_timeout)
3811 my_net_set_write_timeout(net, mysql->options.write_timeout);
3812
3813 if (mysql->options.max_allowed_packet)
3814 net->max_packet_size= mysql->options.max_allowed_packet;
3815
3816 /* Get version info */
3817 mysql->protocol_version= PROTOCOL_VERSION; /* Assume this */
3818 if (mysql->options.connect_timeout &&
3819 (vio_io_wait(net->vio, VIO_IO_EVENT_READ,
3820 get_vio_connect_timeout(mysql)) < 1))
3821 {
3822 set_mysql_extended_error(mysql, CR_SERVER_LOST, unknown_sqlstate,
3823 ER(CR_SERVER_LOST_EXTENDED),
3824 "waiting for initial communication packet",
3825 socket_errno);
3826 goto error;
3827 }
3828
3829 /*
3830 Part 1: Connection established, read and parse first packet
3831 */
3832 DBUG_PRINT("info", ("Read first packet."));
3833
3834 if ((pkt_length=cli_safe_read(mysql)) == packet_error)
3835 {
3836 if (mysql->net.last_errno == CR_SERVER_LOST)
3837 set_mysql_extended_error(mysql, CR_SERVER_LOST, unknown_sqlstate,
3838 ER(CR_SERVER_LOST_EXTENDED),
3839 "reading initial communication packet",
3840 socket_errno);
3841 goto error;
3842 }
3843 pkt_end= (char*)net->read_pos + pkt_length;
3844 /* Check if version of protocol matches current one */
3845 mysql->protocol_version= net->read_pos[0];
3846 DBUG_DUMP("packet",(uchar*) net->read_pos,10);
3847 DBUG_PRINT("info",("mysql protocol version %d, server=%d",
3848 PROTOCOL_VERSION, mysql->protocol_version));
3849 if (mysql->protocol_version != PROTOCOL_VERSION)
3850 {
3851 set_mysql_extended_error(mysql, CR_VERSION_ERROR, unknown_sqlstate,
3852 ER(CR_VERSION_ERROR), mysql->protocol_version,
3853 PROTOCOL_VERSION);
3854 goto error;
3855 }
3856 server_version_end= end= strend((char*) net->read_pos+1);
3857 mysql->thread_id=uint4korr(end+1);
3858 end+=5;
3859 /*
3860 Scramble is split into two parts because old clients do not understand
3861 long scrambles; here goes the first part.
3862 */
3863 scramble_data= end;
3864 scramble_data_len= SCRAMBLE_LENGTH_323 + 1;
3865 scramble_plugin= old_password_plugin_name;
3866 end+= scramble_data_len;
3867
3868 if (pkt_end >= end + 1)
3869 mysql->server_capabilities=uint2korr(end);
3870 if (pkt_end >= end + 18)
3871 {
3872 /* New protocol with 16 bytes to describe server characteristics */
3873 mysql->server_language=end[2];
3874 mysql->server_status=uint2korr(end+3);
3875 mysql->server_capabilities|= uint2korr(end+5) << 16;
3876 pkt_scramble_len= end[7];
3877 if (pkt_scramble_len < 0)
3878 {
3879 set_mysql_error(mysql, CR_MALFORMED_PACKET,
3880 unknown_sqlstate); /* purecov: inspected */
3881 goto error;
3882 }
3883 }
3884 end+= 18;
3885
3886 if (mysql->options.secure_auth && passwd[0] &&
3887 !(mysql->server_capabilities & CLIENT_SECURE_CONNECTION))
3888 {
3889 set_mysql_error(mysql, CR_SECURE_AUTH, unknown_sqlstate);
3890 goto error;
3891 }
3892
3893 if (mysql_init_character_set(mysql))
3894 goto error;
3895
3896 /* Save connection information */
3897 if (!my_multi_malloc(MYF(0),
3898 &mysql->host_info, (uint) strlen(host_info)+1,
3899 &mysql->host, (uint) strlen(host)+1,
3900 &mysql->unix_socket,unix_socket ?
3901 (uint) strlen(unix_socket)+1 : (uint) 1,
3902 &mysql->server_version,
3903 (uint) (server_version_end - (char*) net->read_pos + 1),
3904 NullS) ||
3905 !(mysql->user=my_strdup(user,MYF(0))) ||
3906 !(mysql->passwd=my_strdup(passwd,MYF(0))))
3907 {
3908 set_mysql_error(mysql, CR_OUT_OF_MEMORY, unknown_sqlstate);
3909 goto error;
3910 }
3911 strmov(mysql->host_info,host_info);
3912 strmov(mysql->host,host);
3913 if (unix_socket)
3914 strmov(mysql->unix_socket,unix_socket);
3915 else
3916 mysql->unix_socket=0;
3917 strmov(mysql->server_version,(char*) net->read_pos+1);
3918 mysql->port=port;
3919
3920 if (pkt_end >= end + SCRAMBLE_LENGTH - SCRAMBLE_LENGTH_323 + 1)
3921 {
3922 /*
3923 move the first scramble part - directly in the NET buffer -
3924 to get a full continuous scramble. We've read all the header,
3925 and can overwrite it now.
3926 */
3927 memmove(end - SCRAMBLE_LENGTH_323, scramble_data,
3928 SCRAMBLE_LENGTH_323);
3929 scramble_data= end - SCRAMBLE_LENGTH_323;
3930 if (mysql->server_capabilities & CLIENT_PLUGIN_AUTH)
3931 {
3932 scramble_data_len= pkt_scramble_len;
3933 scramble_plugin= scramble_data + scramble_data_len;
3934 /*
3935 There is a possibility that we did not get a correct plugin name
3936 for some reason. For example, the packet was malformed and some
3937 of the fields had incorrect values. In such cases, we keep the
3938 plugin name empty so that the default authentication plugin
3939 gets used later on. Since we don't really know the plugin for which
3940 the scramble_data was prepared, we can discard it and set it's length
3941 to 0.
3942 */
3943 if (scramble_data + scramble_data_len > pkt_end)
3944 {
3945 scramble_plugin= (char*)"";
3946 scramble_data= 0;
3947 scramble_data_len= 0;
3948 }
3949 }
3950 else
3951 {
3952 scramble_data_len= pkt_end - scramble_data;
3953 scramble_plugin= native_password_plugin_name;
3954 }
3955 }
3956 else
3957 mysql->server_capabilities&= ~CLIENT_SECURE_CONNECTION;
3958
3959 mysql->client_flag= client_flag;
3960
3961 #ifdef EMBEDDED_LIBRARY
3962 if (embedded_ssl_check(mysql))
3963 goto error;
3964 #endif
3965
3966 /*
3967 Part 2: invoke the plugin to send the authentication data to the server
3968 */
3969
3970 if (run_plugin_auth(mysql, scramble_data, scramble_data_len,
3971 scramble_plugin, db))
3972 goto error;
3973
3974 /*
3975 Part 3: authenticated, finish the initialization of the connection
3976 */
3977
3978 if (mysql->client_flag & CLIENT_COMPRESS) /* We will use compression */
3979 net->compress=1;
3980
3981 #ifdef CHECK_LICENSE
3982 if (check_license(mysql))
3983 goto error;
3984 #endif
3985
3986 if (db && !mysql->db && mysql_select_db(mysql, db))
3987 {
3988 if (mysql->net.last_errno == CR_SERVER_LOST)
3989 set_mysql_extended_error(mysql, CR_SERVER_LOST, unknown_sqlstate,
3990 ER(CR_SERVER_LOST_EXTENDED),
3991 "Setting intital database",
3992 errno);
3993 goto error;
3994 }
3995
3996 /*
3997 Using init_commands is not supported when connecting from within the
3998 server.
3999 */
4000 #ifndef MYSQL_SERVER
4001 if (mysql->options.init_commands)
4002 {
4003 DYNAMIC_ARRAY *init_commands= mysql->options.init_commands;
4004 char **ptr= (char**)init_commands->buffer;
4005 char **end_command= ptr + init_commands->elements;
4006
4007 my_bool reconnect=mysql->reconnect;
4008 mysql->reconnect=0;
4009
4010 for (; ptr < end_command; ptr++)
4011 {
4012 int status;
4013
4014 if (mysql_real_query(mysql,*ptr, (ulong) strlen(*ptr)))
4015 goto error;
4016
4017 do {
4018 if (mysql->fields)
4019 {
4020 MYSQL_RES *res;
4021 if (!(res= cli_use_result(mysql)))
4022 goto error;
4023 mysql_free_result(res);
4024 }
4025 if ((status= mysql_next_result(mysql)) > 0)
4026 goto error;
4027 } while (status == 0);
4028 }
4029 mysql->reconnect=reconnect;
4030 }
4031 #endif
4032
4033 DBUG_PRINT("exit", ("Mysql handler: 0x%lx", (long) mysql));
4034 DBUG_RETURN(mysql);
4035
4036 error:
4037 DBUG_PRINT("error",("message: %u/%s (%s)",
4038 net->last_errno,
4039 net->sqlstate,
4040 net->last_error));
4041 {
4042 /* Free alloced memory */
4043 end_server(mysql);
4044 mysql_close_free(mysql);
4045 if (!(client_flag & CLIENT_REMEMBER_OPTIONS))
4046 mysql_close_free_options(mysql);
4047 }
4048 DBUG_RETURN(0);
4049 }
4050
4051
mysql_reconnect(MYSQL * mysql)4052 my_bool mysql_reconnect(MYSQL *mysql)
4053 {
4054 MYSQL tmp_mysql;
4055 DBUG_ENTER("mysql_reconnect");
4056 DBUG_ASSERT(mysql);
4057 DBUG_PRINT("enter", ("mysql->reconnect: %d", mysql->reconnect));
4058
4059 if (!mysql->reconnect ||
4060 (mysql->server_status & SERVER_STATUS_IN_TRANS) || !mysql->host_info)
4061 {
4062 /* Allow reconnect next time */
4063 mysql->server_status&= ~SERVER_STATUS_IN_TRANS;
4064 set_mysql_error(mysql, CR_SERVER_GONE_ERROR, unknown_sqlstate);
4065 DBUG_RETURN(1);
4066 }
4067 mysql_init(&tmp_mysql);
4068 tmp_mysql.options= mysql->options;
4069 tmp_mysql.options.my_cnf_file= tmp_mysql.options.my_cnf_group= 0;
4070
4071 if (!mysql_real_connect(&tmp_mysql,mysql->host,mysql->user,mysql->passwd,
4072 mysql->db, mysql->port, mysql->unix_socket,
4073 mysql->client_flag | CLIENT_REMEMBER_OPTIONS))
4074 {
4075 memset(&tmp_mysql.options, 0, sizeof(tmp_mysql.options));
4076 mysql_close(&tmp_mysql);
4077 mysql->net.last_errno= tmp_mysql.net.last_errno;
4078 strmov(mysql->net.last_error, tmp_mysql.net.last_error);
4079 strmov(mysql->net.sqlstate, tmp_mysql.net.sqlstate);
4080 DBUG_RETURN(1);
4081 }
4082 if (mysql_set_character_set(&tmp_mysql, mysql->charset->csname))
4083 {
4084 DBUG_PRINT("error", ("mysql_set_character_set() failed"));
4085 memset(&tmp_mysql.options, 0, sizeof(tmp_mysql.options));
4086 mysql_close(&tmp_mysql);
4087 mysql->net.last_errno= tmp_mysql.net.last_errno;
4088 strmov(mysql->net.last_error, tmp_mysql.net.last_error);
4089 strmov(mysql->net.sqlstate, tmp_mysql.net.sqlstate);
4090 DBUG_RETURN(1);
4091 }
4092
4093 DBUG_PRINT("info", ("reconnect succeded"));
4094 tmp_mysql.reconnect= 1;
4095 tmp_mysql.free_me= mysql->free_me;
4096
4097 /* Move prepared statements (if any) over to the new mysql object */
4098 tmp_mysql.stmts= mysql->stmts;
4099 mysql->stmts= 0;
4100
4101 /* Don't free options as these are now used in tmp_mysql */
4102 memset(&mysql->options, 0, sizeof(mysql->options));
4103 mysql->free_me=0;
4104 mysql_close(mysql);
4105 *mysql=tmp_mysql;
4106 net_clear(&mysql->net, 1);
4107 mysql->affected_rows= ~(my_ulonglong) 0;
4108 DBUG_RETURN(0);
4109 }
4110
4111
4112 /**************************************************************************
4113 Set current database
4114 **************************************************************************/
4115
4116 int STDCALL
mysql_select_db(MYSQL * mysql,const char * db)4117 mysql_select_db(MYSQL *mysql, const char *db)
4118 {
4119 int error;
4120 DBUG_ENTER("mysql_select_db");
4121 DBUG_PRINT("enter",("db: '%s'",db));
4122
4123 if ((error=simple_command(mysql,COM_INIT_DB, (const uchar*) db,
4124 (ulong) strlen(db),0)))
4125 DBUG_RETURN(error);
4126 my_free(mysql->db);
4127 mysql->db=my_strdup(db,MYF(MY_WME));
4128 DBUG_RETURN(0);
4129 }
4130
4131
4132 /*************************************************************************
4133 Send a QUIT to the server and close the connection
4134 If handle is alloced by mysql connect free it.
4135 *************************************************************************/
4136
mysql_close_free_options(MYSQL * mysql)4137 static void mysql_close_free_options(MYSQL *mysql)
4138 {
4139 DBUG_ENTER("mysql_close_free_options");
4140
4141 my_free(mysql->options.user);
4142 my_free(mysql->options.host);
4143 my_free(mysql->options.password);
4144 my_free(mysql->options.unix_socket);
4145 my_free(mysql->options.db);
4146 my_free(mysql->options.my_cnf_file);
4147 my_free(mysql->options.my_cnf_group);
4148 my_free(mysql->options.charset_dir);
4149 my_free(mysql->options.charset_name);
4150 my_free(mysql->options.ci.client_ip);
4151 /* ci.bind_adress is union with client_ip, already freed above */
4152 if (mysql->options.init_commands)
4153 {
4154 DYNAMIC_ARRAY *init_commands= mysql->options.init_commands;
4155 char **ptr= (char**)init_commands->buffer;
4156 char **end= ptr + init_commands->elements;
4157 for (; ptr<end; ptr++)
4158 my_free(*ptr);
4159 delete_dynamic(init_commands);
4160 my_free(init_commands);
4161 }
4162 #if defined(HAVE_OPENSSL) && !defined(EMBEDDED_LIBRARY)
4163 mysql_ssl_free(mysql);
4164 #endif /* HAVE_OPENSSL && !EMBEDDED_LIBRARY */
4165 #ifdef HAVE_SMEM
4166 if (mysql->options.shared_memory_base_name != def_shared_memory_base_name)
4167 my_free(mysql->options.shared_memory_base_name);
4168 #endif /* HAVE_SMEM */
4169 if (mysql->options.extension)
4170 {
4171 my_free(mysql->options.extension->plugin_dir);
4172 my_free(mysql->options.extension->default_auth);
4173 my_hash_free(&mysql->options.extension->connection_attributes);
4174 my_free(mysql->options.extension);
4175 }
4176 memset(&mysql->options, 0, sizeof(mysql->options));
4177 DBUG_VOID_RETURN;
4178 }
4179
4180
mysql_close_free(MYSQL * mysql)4181 static void mysql_close_free(MYSQL *mysql)
4182 {
4183 my_free(mysql->host_info);
4184 my_free(mysql->user);
4185 my_free(mysql->passwd);
4186 my_free(mysql->db);
4187 #if defined(EMBEDDED_LIBRARY) || MYSQL_VERSION_ID >= 50100
4188 my_free(mysql->info_buffer);
4189 mysql->info_buffer= 0;
4190 #endif
4191 /* Clear pointers for better safety */
4192 mysql->host_info= mysql->user= mysql->passwd= mysql->db= 0;
4193 }
4194
4195
4196 /**
4197 For use when the connection to the server has been lost (in which case
4198 the server has discarded all information about prepared statements
4199 associated with the connection).
4200
4201 Mark all statements in mysql->stmts by setting stmt->mysql= 0 if the
4202 statement has transitioned beyond the MYSQL_STMT_INIT_DONE state, and
4203 unlink the statement from the mysql->stmts list.
4204
4205 The remaining pruned list of statements (if any) is kept in mysql->stmts.
4206
4207 @param mysql pointer to the MYSQL object
4208
4209 @return none
4210 */
mysql_prune_stmt_list(MYSQL * mysql)4211 static void mysql_prune_stmt_list(MYSQL *mysql)
4212 {
4213 LIST *pruned_list= NULL;
4214
4215 while(mysql->stmts)
4216 {
4217 LIST *element= mysql->stmts;
4218 MYSQL_STMT *stmt;
4219
4220 mysql->stmts= list_delete(element, element);
4221 stmt= (MYSQL_STMT *) element->data;
4222 if (stmt->state != MYSQL_STMT_INIT_DONE)
4223 {
4224 stmt->mysql= 0;
4225 stmt->last_errno= CR_SERVER_LOST;
4226 strmov(stmt->last_error, ER(CR_SERVER_LOST));
4227 strmov(stmt->sqlstate, unknown_sqlstate);
4228 }
4229 else
4230 {
4231 pruned_list= list_add(pruned_list, element);
4232 }
4233 }
4234
4235 mysql->stmts= pruned_list;
4236 }
4237
4238
4239 /*
4240 Clear connection pointer of every statement: this is necessary
4241 to give error on attempt to use a prepared statement of closed
4242 connection.
4243
4244 SYNOPSYS
4245 mysql_detach_stmt_list()
4246 stmt_list pointer to mysql->stmts
4247 func_name name of calling function
4248
4249 NOTE
4250 There is similar code in mysql_reconnect(), so changes here
4251 should also be reflected there.
4252 */
4253
mysql_detach_stmt_list(LIST ** stmt_list MY_ATTRIBUTE ((unused)),const char * func_name MY_ATTRIBUTE ((unused)))4254 void mysql_detach_stmt_list(LIST **stmt_list MY_ATTRIBUTE((unused)),
4255 const char *func_name MY_ATTRIBUTE((unused)))
4256 {
4257 #ifdef MYSQL_CLIENT
4258 /* Reset connection handle in all prepared statements. */
4259 LIST *element= *stmt_list;
4260 char buff[MYSQL_ERRMSG_SIZE];
4261 DBUG_ENTER("mysql_detach_stmt_list");
4262
4263 my_snprintf(buff, sizeof(buff)-1, ER(CR_STMT_CLOSED), func_name);
4264 for (; element; element= element->next)
4265 {
4266 MYSQL_STMT *stmt= (MYSQL_STMT *) element->data;
4267 set_stmt_error(stmt, CR_STMT_CLOSED, unknown_sqlstate, buff);
4268 stmt->mysql= 0;
4269 /* No need to call list_delete for statement here */
4270 }
4271 *stmt_list= 0;
4272 DBUG_VOID_RETURN;
4273 #endif /* MYSQL_CLIENT */
4274 }
4275
4276
mysql_close(MYSQL * mysql)4277 void STDCALL mysql_close(MYSQL *mysql)
4278 {
4279 DBUG_ENTER("mysql_close");
4280 if (mysql) /* Some simple safety */
4281 {
4282 /* If connection is still up, send a QUIT message */
4283 if (mysql->net.vio != 0)
4284 {
4285 free_old_query(mysql);
4286 mysql->status=MYSQL_STATUS_READY; /* Force command */
4287 simple_command(mysql,COM_QUIT,(uchar*) 0,0,1);
4288 mysql->reconnect=0;
4289 end_server(mysql); /* Sets mysql->net.vio= 0 */
4290 }
4291 mysql_close_free_options(mysql);
4292 mysql_close_free(mysql);
4293 mysql_detach_stmt_list(&mysql->stmts, "mysql_close");
4294 #ifndef MYSQL_SERVER
4295 if (mysql->thd)
4296 (*mysql->methods->free_embedded_thd)(mysql);
4297 #endif
4298 if (mysql->free_me)
4299 my_free(mysql);
4300 }
4301 DBUG_VOID_RETURN;
4302 }
4303
4304
cli_read_query_result(MYSQL * mysql)4305 static my_bool cli_read_query_result(MYSQL *mysql)
4306 {
4307 uchar *pos;
4308 ulong field_count;
4309 MYSQL_DATA *fields;
4310 ulong length;
4311 DBUG_ENTER("cli_read_query_result");
4312
4313 if ((length = cli_safe_read(mysql)) == packet_error)
4314 DBUG_RETURN(1);
4315 free_old_query(mysql); /* Free old result */
4316 #ifdef MYSQL_CLIENT /* Avoid warn of unused labels*/
4317 get_info:
4318 #endif
4319 pos=(uchar*) mysql->net.read_pos;
4320 if ((field_count= net_field_length(&pos)) == 0)
4321 {
4322 mysql->affected_rows= net_field_length_ll(&pos);
4323 mysql->insert_id= net_field_length_ll(&pos);
4324 DBUG_PRINT("info",("affected_rows: %lu insert_id: %lu",
4325 (ulong) mysql->affected_rows,
4326 (ulong) mysql->insert_id));
4327 if (protocol_41(mysql))
4328 {
4329 mysql->server_status=uint2korr(pos); pos+=2;
4330 mysql->warning_count=uint2korr(pos); pos+=2;
4331 }
4332 else if (mysql->server_capabilities & CLIENT_TRANSACTIONS)
4333 {
4334 /* MySQL 4.0 protocol */
4335 mysql->server_status=uint2korr(pos); pos+=2;
4336 mysql->warning_count= 0;
4337 }
4338 DBUG_PRINT("info",("status: %u warning_count: %u",
4339 mysql->server_status, mysql->warning_count));
4340 if (pos < mysql->net.read_pos+length && net_field_length(&pos))
4341 mysql->info=(char*) pos;
4342 DBUG_RETURN(0);
4343 }
4344 #ifdef MYSQL_CLIENT
4345 if (field_count == NULL_LENGTH) /* LOAD DATA LOCAL INFILE */
4346 {
4347 int error;
4348
4349 if (!(mysql->options.client_flag & CLIENT_LOCAL_FILES))
4350 {
4351 set_mysql_error(mysql, CR_MALFORMED_PACKET, unknown_sqlstate);
4352 DBUG_RETURN(1);
4353 }
4354
4355 error= handle_local_infile(mysql,(char*) pos);
4356 if ((length= cli_safe_read(mysql)) == packet_error || error)
4357 DBUG_RETURN(1);
4358 goto get_info; /* Get info packet */
4359 }
4360 #endif
4361 if (!(mysql->server_status & SERVER_STATUS_AUTOCOMMIT))
4362 mysql->server_status|= SERVER_STATUS_IN_TRANS;
4363
4364 if (!(fields=cli_read_rows(mysql,(MYSQL_FIELD*)0, protocol_41(mysql) ? 7:5)))
4365 DBUG_RETURN(1);
4366 if (!(mysql->fields=unpack_fields(mysql, fields,&mysql->field_alloc,
4367 (uint) field_count,0,
4368 mysql->server_capabilities)))
4369 DBUG_RETURN(1);
4370 mysql->status= MYSQL_STATUS_GET_RESULT;
4371 mysql->field_count= (uint) field_count;
4372 DBUG_PRINT("exit",("ok"));
4373 DBUG_RETURN(0);
4374 }
4375
4376
4377 /*
4378 Send the query and return so we can do something else.
4379 Needs to be followed by mysql_read_query_result() when we want to
4380 finish processing it.
4381 */
4382
4383 int STDCALL
mysql_send_query(MYSQL * mysql,const char * query,ulong length)4384 mysql_send_query(MYSQL* mysql, const char* query, ulong length)
4385 {
4386 DBUG_ENTER("mysql_send_query");
4387 DBUG_RETURN(simple_command(mysql, COM_QUERY, (uchar*) query, length, 1));
4388 }
4389
4390
4391 int STDCALL
mysql_real_query(MYSQL * mysql,const char * query,ulong length)4392 mysql_real_query(MYSQL *mysql, const char *query, ulong length)
4393 {
4394 int retval;
4395 DBUG_ENTER("mysql_real_query");
4396 DBUG_PRINT("enter",("handle: %p", mysql));
4397 DBUG_PRINT("query",("Query = '%-.*s'", (int) length, query));
4398
4399 if (mysql_send_query(mysql,query,length))
4400 DBUG_RETURN(1);
4401 retval= (int) (*mysql->methods->read_query_result)(mysql);
4402 DBUG_RETURN(retval);
4403 }
4404
4405
4406 /**************************************************************************
4407 Alloc result struct for buffered results. All rows are read to buffer.
4408 mysql_data_seek may be used.
4409 **************************************************************************/
4410
mysql_store_result(MYSQL * mysql)4411 MYSQL_RES * STDCALL mysql_store_result(MYSQL *mysql)
4412 {
4413 MYSQL_RES *result;
4414 DBUG_ENTER("mysql_store_result");
4415
4416 if (!mysql->fields)
4417 DBUG_RETURN(0);
4418 if (mysql->status != MYSQL_STATUS_GET_RESULT)
4419 {
4420 set_mysql_error(mysql, CR_COMMANDS_OUT_OF_SYNC, unknown_sqlstate);
4421 DBUG_RETURN(0);
4422 }
4423 mysql->status=MYSQL_STATUS_READY; /* server is ready */
4424 if (!(result=(MYSQL_RES*) my_malloc((uint) (sizeof(MYSQL_RES)+
4425 sizeof(ulong) *
4426 mysql->field_count),
4427 MYF(MY_WME | MY_ZEROFILL))))
4428 {
4429 set_mysql_error(mysql, CR_OUT_OF_MEMORY, unknown_sqlstate);
4430 DBUG_RETURN(0);
4431 }
4432 result->methods= mysql->methods;
4433 result->eof=1; /* Marker for buffered */
4434 result->lengths=(ulong*) (result+1);
4435 if (!(result->data=
4436 (*mysql->methods->read_rows)(mysql,mysql->fields,mysql->field_count)))
4437 {
4438 my_free(result);
4439 DBUG_RETURN(0);
4440 }
4441 mysql->affected_rows= result->row_count= result->data->rows;
4442 result->data_cursor= result->data->data;
4443 result->fields= mysql->fields;
4444 result->field_alloc= mysql->field_alloc;
4445 result->field_count= mysql->field_count;
4446 /* The rest of result members is zerofilled in my_malloc */
4447 mysql->fields=0; /* fields is now in result */
4448 clear_alloc_root(&mysql->field_alloc);
4449 /* just in case this was mistakenly called after mysql_stmt_execute() */
4450 mysql->unbuffered_fetch_owner= 0;
4451 DBUG_RETURN(result); /* Data fetched */
4452 }
4453
4454
4455 /**************************************************************************
4456 Alloc struct for use with unbuffered reads. Data is fetched by domand
4457 when calling to mysql_fetch_row.
4458 mysql_data_seek is a noop.
4459
4460 No other queries may be specified with the same MYSQL handle.
4461 There shouldn't be much processing per row because mysql server shouldn't
4462 have to wait for the client (and will not wait more than 30 sec/packet).
4463 **************************************************************************/
4464
cli_use_result(MYSQL * mysql)4465 static MYSQL_RES * cli_use_result(MYSQL *mysql)
4466 {
4467 MYSQL_RES *result;
4468 DBUG_ENTER("cli_use_result");
4469
4470 if (!mysql->fields)
4471 DBUG_RETURN(0);
4472 if (mysql->status != MYSQL_STATUS_GET_RESULT)
4473 {
4474 set_mysql_error(mysql, CR_COMMANDS_OUT_OF_SYNC, unknown_sqlstate);
4475 DBUG_RETURN(0);
4476 }
4477 if (!(result=(MYSQL_RES*) my_malloc(sizeof(*result)+
4478 sizeof(ulong)*mysql->field_count,
4479 MYF(MY_WME | MY_ZEROFILL))))
4480 DBUG_RETURN(0);
4481 result->lengths=(ulong*) (result+1);
4482 result->methods= mysql->methods;
4483 if (!(result->row=(MYSQL_ROW)
4484 my_malloc(sizeof(result->row[0])*(mysql->field_count+1), MYF(MY_WME))))
4485 { /* Ptrs: to one row */
4486 my_free(result);
4487 DBUG_RETURN(0);
4488 }
4489 result->fields= mysql->fields;
4490 result->field_alloc= mysql->field_alloc;
4491 result->field_count= mysql->field_count;
4492 result->current_field=0;
4493 result->handle= mysql;
4494 result->current_row= 0;
4495 mysql->fields=0; /* fields is now in result */
4496 clear_alloc_root(&mysql->field_alloc);
4497 mysql->status=MYSQL_STATUS_USE_RESULT;
4498 mysql->unbuffered_fetch_owner= &result->unbuffered_fetch_cancelled;
4499 DBUG_RETURN(result); /* Data is read to be fetched */
4500 }
4501
4502
4503 /**************************************************************************
4504 Return next row of the query results
4505 **************************************************************************/
4506
4507 MYSQL_ROW STDCALL
mysql_fetch_row(MYSQL_RES * res)4508 mysql_fetch_row(MYSQL_RES *res)
4509 {
4510 DBUG_ENTER("mysql_fetch_row");
4511 if (!res->data)
4512 { /* Unbufferred fetch */
4513 if (!res->eof)
4514 {
4515 MYSQL *mysql= res->handle;
4516 if (mysql->status != MYSQL_STATUS_USE_RESULT)
4517 {
4518 set_mysql_error(mysql,
4519 res->unbuffered_fetch_cancelled ?
4520 CR_FETCH_CANCELED : CR_COMMANDS_OUT_OF_SYNC,
4521 unknown_sqlstate);
4522 }
4523 else if (!(read_one_row(mysql, res->field_count, res->row, res->lengths)))
4524 {
4525 res->row_count++;
4526 DBUG_RETURN(res->current_row=res->row);
4527 }
4528 DBUG_PRINT("info",("end of data"));
4529 res->eof=1;
4530 mysql->status=MYSQL_STATUS_READY;
4531 /*
4532 Reset only if owner points to us: there is a chance that somebody
4533 started new query after mysql_stmt_close():
4534 */
4535 if (mysql->unbuffered_fetch_owner == &res->unbuffered_fetch_cancelled)
4536 mysql->unbuffered_fetch_owner= 0;
4537 /* Don't clear handle in mysql_free_result */
4538 res->handle=0;
4539 }
4540 DBUG_RETURN((MYSQL_ROW) NULL);
4541 }
4542 {
4543 MYSQL_ROW tmp;
4544 if (!res->data_cursor)
4545 {
4546 DBUG_PRINT("info",("end of data"));
4547 DBUG_RETURN(res->current_row=(MYSQL_ROW) NULL);
4548 }
4549 tmp = res->data_cursor->data;
4550 res->data_cursor = res->data_cursor->next;
4551 DBUG_RETURN(res->current_row=tmp);
4552 }
4553 }
4554
4555
4556 /**************************************************************************
4557 Get column lengths of the current row
4558 If one uses mysql_use_result, res->lengths contains the length information,
4559 else the lengths are calculated from the offset between pointers.
4560 **************************************************************************/
4561
4562 ulong * STDCALL
mysql_fetch_lengths(MYSQL_RES * res)4563 mysql_fetch_lengths(MYSQL_RES *res)
4564 {
4565 MYSQL_ROW column;
4566
4567 if (!(column=res->current_row))
4568 return 0; /* Something is wrong */
4569 if (res->data)
4570 (*res->methods->fetch_lengths)(res->lengths, column, res->field_count);
4571 return res->lengths;
4572 }
4573
4574 int STDCALL
mysql_options(MYSQL * mysql,enum mysql_option option,const void * arg)4575 mysql_options(MYSQL *mysql,enum mysql_option option, const void *arg)
4576 {
4577 DBUG_ENTER("mysql_option");
4578 DBUG_PRINT("enter",("option: %d",(int) option));
4579 switch (option) {
4580 case MYSQL_OPT_CONNECT_TIMEOUT:
4581 mysql->options.connect_timeout= *(uint*) arg;
4582 break;
4583 case MYSQL_OPT_READ_TIMEOUT:
4584 mysql->options.read_timeout= *(uint*) arg;
4585 break;
4586 case MYSQL_OPT_WRITE_TIMEOUT:
4587 mysql->options.write_timeout= *(uint*) arg;
4588 break;
4589 case MYSQL_OPT_COMPRESS:
4590 mysql->options.compress= 1; /* Remember for connect */
4591 mysql->options.client_flag|= CLIENT_COMPRESS;
4592 break;
4593 case MYSQL_OPT_NAMED_PIPE: /* This option is depricated */
4594 mysql->options.protocol=MYSQL_PROTOCOL_PIPE; /* Force named pipe */
4595 break;
4596 case MYSQL_OPT_LOCAL_INFILE: /* Allow LOAD DATA LOCAL ?*/
4597 if (!arg || MY_TEST(*(uint*) arg))
4598 mysql->options.client_flag|= CLIENT_LOCAL_FILES;
4599 else
4600 mysql->options.client_flag&= ~CLIENT_LOCAL_FILES;
4601 break;
4602 case MYSQL_INIT_COMMAND:
4603 add_init_command(&mysql->options,arg);
4604 break;
4605 case MYSQL_READ_DEFAULT_FILE:
4606 my_free(mysql->options.my_cnf_file);
4607 mysql->options.my_cnf_file=my_strdup(arg,MYF(MY_WME));
4608 break;
4609 case MYSQL_READ_DEFAULT_GROUP:
4610 my_free(mysql->options.my_cnf_group);
4611 mysql->options.my_cnf_group=my_strdup(arg,MYF(MY_WME));
4612 break;
4613 case MYSQL_SET_CHARSET_DIR:
4614 my_free(mysql->options.charset_dir);
4615 mysql->options.charset_dir=my_strdup(arg,MYF(MY_WME));
4616 break;
4617 case MYSQL_SET_CHARSET_NAME:
4618 my_free(mysql->options.charset_name);
4619 mysql->options.charset_name=my_strdup(arg,MYF(MY_WME));
4620 break;
4621 case MYSQL_OPT_PROTOCOL:
4622 mysql->options.protocol= *(uint*) arg;
4623 break;
4624 case MYSQL_SHARED_MEMORY_BASE_NAME:
4625 #ifdef HAVE_SMEM
4626 if (mysql->options.shared_memory_base_name != def_shared_memory_base_name)
4627 my_free(mysql->options.shared_memory_base_name);
4628 mysql->options.shared_memory_base_name=my_strdup(arg,MYF(MY_WME));
4629 #endif
4630 break;
4631 case MYSQL_OPT_USE_REMOTE_CONNECTION:
4632 case MYSQL_OPT_USE_EMBEDDED_CONNECTION:
4633 case MYSQL_OPT_GUESS_CONNECTION:
4634 mysql->options.methods_to_use= option;
4635 break;
4636 case MYSQL_SET_CLIENT_IP:
4637 my_free(mysql->options.ci.client_ip);
4638 mysql->options.ci.client_ip= my_strdup(arg, MYF(MY_WME));
4639 break;
4640 case MYSQL_SECURE_AUTH:
4641 mysql->options.secure_auth= *(my_bool *) arg;
4642 break;
4643 case MYSQL_REPORT_DATA_TRUNCATION:
4644 mysql->options.report_data_truncation= MY_TEST(*(my_bool *) arg);
4645 break;
4646 case MYSQL_OPT_RECONNECT:
4647 mysql->reconnect= *(my_bool *) arg;
4648 break;
4649 case MYSQL_OPT_BIND:
4650 my_free(mysql->options.ci.bind_address);
4651 mysql->options.ci.bind_address= my_strdup(arg, MYF(MY_WME));
4652 break;
4653 case MYSQL_OPT_SSL_VERIFY_SERVER_CERT:
4654 #if defined(HAVE_OPENSSL) && !defined(EMBEDDED_LIBRARY)
4655 if (*(my_bool*) arg)
4656 mysql->options.client_flag|= CLIENT_SSL_VERIFY_SERVER_CERT;
4657 else
4658 mysql->options.client_flag&= ~CLIENT_SSL_VERIFY_SERVER_CERT;
4659 #elif defined(EMBEDDED_LIBRARY)
4660 DBUG_RETURN(1);
4661 #endif
4662 break;
4663 case MYSQL_PLUGIN_DIR:
4664 EXTENSION_SET_STRING(&mysql->options, plugin_dir, arg);
4665 break;
4666 case MYSQL_DEFAULT_AUTH:
4667 EXTENSION_SET_STRING(&mysql->options, default_auth, arg);
4668 break;
4669 case MYSQL_OPT_SSL_KEY:
4670 #if defined(HAVE_OPENSSL) && !defined(EMBEDDED_LIBRARY)
4671 if (mysql->options.ssl_key)
4672 my_free(mysql->options.ssl_key);
4673 mysql->options.ssl_key= set_ssl_option_unpack_path(&mysql->options, arg);
4674 #elif defined(EMBEDDED_LIBRARY)
4675 DBUG_RETURN(1);
4676 #endif
4677 break;
4678 case MYSQL_OPT_SSL_CERT:
4679 #if defined(HAVE_OPENSSL) && !defined(EMBEDDED_LIBRARY)
4680 if (mysql->options.ssl_cert)
4681 my_free(mysql->options.ssl_cert);
4682 mysql->options.ssl_cert= set_ssl_option_unpack_path(&mysql->options, arg);
4683 #elif defined(EMBEDDED_LIBRARY)
4684 DBUG_RETURN(1);
4685 #endif
4686 break;
4687 case MYSQL_OPT_SSL_CA:
4688 #if defined(HAVE_OPENSSL) && !defined(EMBEDDED_LIBRARY)
4689 if (mysql->options.ssl_ca)
4690 my_free(mysql->options.ssl_ca);
4691 mysql->options.ssl_ca= set_ssl_option_unpack_path(&mysql->options, arg);
4692 #elif defined(EMBEDDED_LIBRARY)
4693 DBUG_RETURN(1);
4694 #endif
4695 break;
4696 case MYSQL_OPT_SSL_CAPATH:
4697 #if defined(HAVE_OPENSSL) && !defined(EMBEDDED_LIBRARY)
4698 if (mysql->options.ssl_capath)
4699 my_free(mysql->options.ssl_capath);
4700 mysql->options.ssl_capath= set_ssl_option_unpack_path(&mysql->options, arg);
4701 #elif defined(EMBEDDED_LIBRARY)
4702 DBUG_RETURN(1);
4703 #endif
4704 break;
4705 case MYSQL_OPT_SSL_CIPHER:
4706 #if defined(HAVE_OPENSSL) && !defined(EMBEDDED_LIBRARY)
4707 SET_SSL_OPTION(ssl_cipher, arg);
4708 #elif defined(EMBEDDED_LIBRARY)
4709 DBUG_RETURN(1);
4710 #endif
4711 break;
4712 case MYSQL_OPT_SSL_CRL:
4713 #if defined(HAVE_OPENSSL) && !defined(EMBEDDED_LIBRARY)
4714 if (mysql->options.extension)
4715 my_free(mysql->options.extension->ssl_crl);
4716 else
4717 ALLOCATE_EXTENSIONS(&mysql->options);
4718 mysql->options.extension->ssl_crl=
4719 set_ssl_option_unpack_path(&mysql->options, arg);
4720 #elif defined(EMBEDDED_LIBRARY)
4721 DBUG_RETURN(1);
4722 #endif
4723 break;
4724 case MYSQL_OPT_SSL_CRLPATH:
4725 #if defined(HAVE_OPENSSL) && !defined(EMBEDDED_LIBRARY)
4726 if (mysql->options.extension)
4727 my_free(mysql->options.extension->ssl_crlpath);
4728 else
4729 ALLOCATE_EXTENSIONS(&mysql->options);
4730 mysql->options.extension->ssl_crlpath=
4731 set_ssl_option_unpack_path(&mysql->options, arg);
4732 #elif defined(EMBEDDED_LIBRARY)
4733 DBUG_RETURN(1);
4734 #endif
4735 break;
4736 case MYSQL_SERVER_PUBLIC_KEY:
4737 EXTENSION_SET_STRING(&mysql->options, server_public_key_path, arg);
4738 break;
4739
4740 case MYSQL_OPT_CONNECT_ATTR_RESET:
4741 ENSURE_EXTENSIONS_PRESENT(&mysql->options);
4742 if (my_hash_inited(&mysql->options.extension->connection_attributes))
4743 {
4744 my_hash_free(&mysql->options.extension->connection_attributes);
4745 mysql->options.extension->connection_attributes_length= 0;
4746 }
4747 break;
4748 case MYSQL_OPT_CONNECT_ATTR_DELETE:
4749 ENSURE_EXTENSIONS_PRESENT(&mysql->options);
4750 if (my_hash_inited(&mysql->options.extension->connection_attributes))
4751 {
4752 size_t len;
4753 uchar *elt;
4754
4755 len= arg ? strlen(arg) : 0;
4756
4757 if (len)
4758 {
4759 elt= my_hash_search(&mysql->options.extension->connection_attributes,
4760 arg, len);
4761 if (elt)
4762 {
4763 LEX_STRING *attr= (LEX_STRING *) elt;
4764 LEX_STRING *key= attr, *value= attr + 1;
4765
4766 mysql->options.extension->connection_attributes_length-=
4767 get_length_store_length(key->length) + key->length +
4768 get_length_store_length(value->length) + value->length;
4769
4770 my_hash_delete(&mysql->options.extension->connection_attributes,
4771 elt);
4772
4773 }
4774 }
4775 }
4776 break;
4777 case MYSQL_ENABLE_CLEARTEXT_PLUGIN:
4778 ENSURE_EXTENSIONS_PRESENT(&mysql->options);
4779 mysql->options.extension->enable_cleartext_plugin=
4780 (*(my_bool*) arg) ? TRUE : FALSE;
4781 break;
4782 case MYSQL_OPT_CAN_HANDLE_EXPIRED_PASSWORDS:
4783 if (*(my_bool*) arg)
4784 mysql->options.client_flag|= CLIENT_CAN_HANDLE_EXPIRED_PASSWORDS;
4785 else
4786 mysql->options.client_flag&= ~CLIENT_CAN_HANDLE_EXPIRED_PASSWORDS;
4787 break;
4788 case MYSQL_OPT_SSL_MODE:
4789 #if defined(HAVE_OPENSSL) && !defined(EMBEDDED_LIBRARY)
4790 if (*(uint *) arg == SSL_MODE_REQUIRED)
4791 {
4792 ENSURE_EXTENSIONS_PRESENT(&mysql->options);
4793 mysql->options.extension->ssl_mode= SSL_MODE_REQUIRED;
4794 }
4795 #elif defined(EMBEDDED_LIBRARY)
4796 DBUG_RETURN(1);
4797 #endif
4798 break;
4799
4800 default:
4801 DBUG_RETURN(1);
4802 }
4803 DBUG_RETURN(0);
4804 }
4805
4806
4807 /**
4808 A function to return the key from a connection attribute
4809 */
4810 uchar *
get_attr_key(LEX_STRING * part,size_t * length,my_bool not_used MY_ATTRIBUTE ((unused)))4811 get_attr_key(LEX_STRING *part, size_t *length,
4812 my_bool not_used MY_ATTRIBUTE((unused)))
4813 {
4814 *length= part[0].length;
4815 return (uchar *) part[0].str;
4816 }
4817
4818 int STDCALL
mysql_options4(MYSQL * mysql,enum mysql_option option,const void * arg1,const void * arg2)4819 mysql_options4(MYSQL *mysql,enum mysql_option option,
4820 const void *arg1, const void *arg2)
4821 {
4822 DBUG_ENTER("mysql_option");
4823 DBUG_PRINT("enter",("option: %d",(int) option));
4824
4825 switch (option)
4826 {
4827 case MYSQL_OPT_CONNECT_ATTR_ADD:
4828 {
4829 LEX_STRING *elt;
4830 char *key, *value;
4831 size_t key_len= arg1 ? strlen(arg1) : 0,
4832 value_len= arg2 ? strlen(arg2) : 0;
4833 size_t attr_storage_length= key_len + value_len;
4834
4835 /* we can't have a zero length key */
4836 if (!key_len)
4837 {
4838 set_mysql_error(mysql, CR_INVALID_PARAMETER_NO, unknown_sqlstate);
4839 DBUG_RETURN(1);
4840 }
4841
4842 /* calculate the total storage length of the attribute */
4843 attr_storage_length+= get_length_store_length(key_len);
4844 attr_storage_length+= get_length_store_length(value_len);
4845
4846 ENSURE_EXTENSIONS_PRESENT(&mysql->options);
4847
4848 /*
4849 Throw and error if the maximum combined length of the attribute value
4850 will be greater than the maximum that we can safely transmit.
4851 */
4852 if (attr_storage_length +
4853 mysql->options.extension->connection_attributes_length >
4854 MAX_CONNECTION_ATTR_STORAGE_LENGTH)
4855 {
4856 set_mysql_error(mysql, CR_INVALID_PARAMETER_NO, unknown_sqlstate);
4857 DBUG_RETURN(1);
4858 }
4859
4860 if (!my_hash_inited(&mysql->options.extension->connection_attributes))
4861 {
4862 if (my_hash_init(&mysql->options.extension->connection_attributes,
4863 &my_charset_bin, 0, 0, 0, (my_hash_get_key) get_attr_key,
4864 my_free, HASH_UNIQUE))
4865 {
4866 set_mysql_error(mysql, CR_OUT_OF_MEMORY, unknown_sqlstate);
4867 DBUG_RETURN(1);
4868 }
4869 }
4870 if (!my_multi_malloc(MY_WME,
4871 &elt, 2 * sizeof(LEX_STRING),
4872 &key, key_len + 1,
4873 &value, value_len + 1,
4874 NULL))
4875 {
4876 set_mysql_error(mysql, CR_OUT_OF_MEMORY, unknown_sqlstate);
4877 DBUG_RETURN(1);
4878 }
4879 elt[0].str= key; elt[0].length= key_len;
4880 elt[1].str= value; elt[1].length= value_len;
4881 if (key_len)
4882 memcpy(key, arg1, key_len);
4883 key[key_len]= 0;
4884 if (value_len)
4885 memcpy(value, arg2, value_len);
4886 value[value_len]= 0;
4887 if (my_hash_insert(&mysql->options.extension->connection_attributes,
4888 (uchar *) elt))
4889 {
4890 /* can't insert the value */
4891 my_free(elt);
4892 set_mysql_error(mysql, CR_DUPLICATE_CONNECTION_ATTR,
4893 unknown_sqlstate);
4894 DBUG_RETURN(1);
4895 }
4896
4897 mysql->options.extension->connection_attributes_length+=
4898 attr_storage_length;
4899
4900 break;
4901 }
4902
4903 default:
4904 DBUG_RETURN(1);
4905 }
4906 DBUG_RETURN(0);
4907 }
4908
4909
4910 /****************************************************************************
4911 Functions to get information from the MySQL structure
4912 These are functions to make shared libraries more usable.
4913 ****************************************************************************/
4914
4915 /* MYSQL_RES */
mysql_num_rows(MYSQL_RES * res)4916 my_ulonglong STDCALL mysql_num_rows(MYSQL_RES *res)
4917 {
4918 return res->row_count;
4919 }
4920
mysql_num_fields(MYSQL_RES * res)4921 unsigned int STDCALL mysql_num_fields(MYSQL_RES *res)
4922 {
4923 return res->field_count;
4924 }
4925
mysql_errno(MYSQL * mysql)4926 uint STDCALL mysql_errno(MYSQL *mysql)
4927 {
4928 return mysql ? mysql->net.last_errno : mysql_server_last_errno;
4929 }
4930
4931
mysql_error(MYSQL * mysql)4932 const char * STDCALL mysql_error(MYSQL *mysql)
4933 {
4934 return mysql ? mysql->net.last_error : mysql_server_last_error;
4935 }
4936
4937
4938 /*
4939 Get version number for server in a form easy to test on
4940
4941 SYNOPSIS
4942 mysql_get_server_version()
4943 mysql Connection
4944
4945 EXAMPLE
4946 4.1.0-alfa -> 40100
4947
4948 NOTES
4949 We will ensure that a newer server always has a bigger number.
4950
4951 RETURN
4952 Signed number > 323000
4953 Zero if there is no connection
4954 */
4955
4956 ulong STDCALL
mysql_get_server_version(MYSQL * mysql)4957 mysql_get_server_version(MYSQL *mysql)
4958 {
4959 ulong major= 0, minor= 0, version= 0;
4960
4961 if (mysql->server_version)
4962 {
4963 char *pos= mysql->server_version, *end_pos;
4964 major= strtoul(pos, &end_pos, 10); pos=end_pos+1;
4965 minor= strtoul(pos, &end_pos, 10); pos=end_pos+1;
4966 version= strtoul(pos, &end_pos, 10);
4967 }
4968 else
4969 {
4970 set_mysql_error(mysql, CR_COMMANDS_OUT_OF_SYNC, unknown_sqlstate);
4971 }
4972
4973 return major*10000 + minor*100 + version;
4974 }
4975
4976
4977 /*
4978 mysql_set_character_set function sends SET NAMES cs_name to
4979 the server (which changes character_set_client, character_set_result
4980 and character_set_connection) and updates mysql->charset so other
4981 functions like mysql_real_escape will work correctly.
4982 */
mysql_set_character_set(MYSQL * mysql,const char * cs_name)4983 int STDCALL mysql_set_character_set(MYSQL *mysql, const char *cs_name)
4984 {
4985 struct charset_info_st *cs;
4986 const char *save_csdir= charsets_dir;
4987
4988 if (mysql->options.charset_dir)
4989 charsets_dir= mysql->options.charset_dir;
4990
4991 if (!mysql->net.vio)
4992 {
4993 /* Initialize with automatic OS character set detection. */
4994 mysql_options(mysql, MYSQL_SET_CHARSET_NAME, cs_name);
4995 mysql_init_character_set(mysql);
4996 /*
4997 In case of automatic OS character set detection
4998 mysql_init_character_set changes mysql->options.charset_name
4999 from "auto" to the real character set name.
5000 Reset cs_name to the detected character set name, accordingly.
5001 */
5002 cs_name= mysql->options.charset_name;
5003 }
5004
5005 if (strlen(cs_name) < MY_CS_NAME_SIZE &&
5006 (cs= get_charset_by_csname(cs_name, MY_CS_PRIMARY, MYF(0))))
5007 {
5008 char buff[MY_CS_NAME_SIZE + 10];
5009 charsets_dir= save_csdir;
5010 if (!mysql->net.vio)
5011 {
5012 /* If there is no connection yet we don't send "SET NAMES" query */
5013 mysql->charset= cs;
5014 return 0;
5015 }
5016 /* Skip execution of "SET NAMES" for pre-4.1 servers */
5017 if (mysql_get_server_version(mysql) < 40100)
5018 return 0;
5019 sprintf(buff, "SET NAMES %s", cs_name);
5020 if (!mysql_real_query(mysql, buff, (uint) strlen(buff)))
5021 {
5022 mysql->charset= cs;
5023 }
5024 }
5025 else
5026 {
5027 char cs_dir_name[FN_REFLEN];
5028 get_charsets_dir(cs_dir_name);
5029 set_mysql_extended_error(mysql, CR_CANT_READ_CHARSET, unknown_sqlstate,
5030 ER(CR_CANT_READ_CHARSET), cs_name, cs_dir_name);
5031 }
5032 charsets_dir= save_csdir;
5033 return mysql->net.last_errno;
5034 }
5035
5036 /**
5037 client authentication plugin that does native MySQL authentication
5038 using a 20-byte (4.1+) scramble
5039 */
native_password_auth_client(MYSQL_PLUGIN_VIO * vio,MYSQL * mysql)5040 static int native_password_auth_client(MYSQL_PLUGIN_VIO *vio, MYSQL *mysql)
5041 {
5042 int pkt_len;
5043 uchar *pkt;
5044
5045 DBUG_ENTER("native_password_auth_client");
5046
5047
5048 if (((MCPVIO_EXT *)vio)->mysql_change_user)
5049 {
5050 /*
5051 in mysql_change_user() the client sends the first packet.
5052 we use the old scramble.
5053 */
5054 pkt= (uchar*)mysql->scramble;
5055 pkt_len= SCRAMBLE_LENGTH + 1;
5056 }
5057 else
5058 {
5059 /* read the scramble */
5060 if ((pkt_len= vio->read_packet(vio, &pkt)) < 0)
5061 DBUG_RETURN(CR_ERROR);
5062
5063 if (pkt_len != SCRAMBLE_LENGTH + 1)
5064 DBUG_RETURN(CR_SERVER_HANDSHAKE_ERR);
5065
5066 /* save it in MYSQL */
5067 memcpy(mysql->scramble, pkt, SCRAMBLE_LENGTH);
5068 mysql->scramble[SCRAMBLE_LENGTH] = 0;
5069 }
5070
5071 if (mysql->passwd[0])
5072 {
5073 char scrambled[SCRAMBLE_LENGTH + 1];
5074 DBUG_PRINT("info", ("sending scramble"));
5075 scramble(scrambled, (char*)pkt, mysql->passwd);
5076 if (vio->write_packet(vio, (uchar*)scrambled, SCRAMBLE_LENGTH))
5077 DBUG_RETURN(CR_ERROR);
5078 }
5079 else
5080 {
5081 DBUG_PRINT("info", ("no password"));
5082 if (vio->write_packet(vio, 0, 0)) /* no password */
5083 DBUG_RETURN(CR_ERROR);
5084 }
5085
5086 DBUG_RETURN(CR_OK);
5087 }
5088
5089 /**
5090 client authentication plugin that does old MySQL authentication
5091 using an 8-byte (4.0-) scramble
5092 */
old_password_auth_client(MYSQL_PLUGIN_VIO * vio,MYSQL * mysql)5093 static int old_password_auth_client(MYSQL_PLUGIN_VIO *vio, MYSQL *mysql)
5094 {
5095 uchar *pkt;
5096 int pkt_len;
5097
5098 DBUG_ENTER("old_password_auth_client");
5099
5100 if (((MCPVIO_EXT *)vio)->mysql_change_user)
5101 {
5102 /*
5103 in mysql_change_user() the client sends the first packet.
5104 we use the old scramble.
5105 */
5106 pkt= (uchar*)mysql->scramble;
5107 pkt_len= SCRAMBLE_LENGTH_323 + 1;
5108 }
5109 else
5110 {
5111 /* read the scramble */
5112 if ((pkt_len= vio->read_packet(vio, &pkt)) < 0)
5113 DBUG_RETURN(CR_ERROR);
5114
5115 if (pkt_len != SCRAMBLE_LENGTH_323 + 1 &&
5116 pkt_len != SCRAMBLE_LENGTH + 1)
5117 DBUG_RETURN(CR_SERVER_HANDSHAKE_ERR);
5118
5119 /*
5120 save it in MYSQL.
5121 Copy data of length SCRAMBLE_LENGTH_323 or SCRAMBLE_LENGTH
5122 to ensure that buffer overflow does not occur.
5123 */
5124 memcpy(mysql->scramble, pkt, (pkt_len - 1));
5125 mysql->scramble[pkt_len-1] = 0;
5126 }
5127
5128 if (mysql->passwd[0])
5129 {
5130 /*
5131 If --secure-auth option is used, throw an error.
5132 Note that, we do not need to check for CLIENT_SECURE_CONNECTION
5133 capability of server. If server is not capable of handling secure
5134 connections, we would have raised error before reaching here.
5135
5136 TODO: Change following code to access MYSQL structure through
5137 client-side plugin service.
5138 */
5139 if (mysql->options.secure_auth)
5140 {
5141 set_mysql_error(mysql, CR_SECURE_AUTH, unknown_sqlstate);
5142 DBUG_RETURN(CR_ERROR);
5143 }
5144 else
5145 {
5146 char scrambled[SCRAMBLE_LENGTH_323 + 1];
5147 scramble_323(scrambled, (char*)pkt, mysql->passwd);
5148 if (vio->write_packet(vio, (uchar*)scrambled, SCRAMBLE_LENGTH_323 + 1))
5149 DBUG_RETURN(CR_ERROR);
5150 }
5151 }
5152 else
5153 if (vio->write_packet(vio, 0, 0)) /* no password */
5154 DBUG_RETURN(CR_ERROR);
5155
5156 DBUG_RETURN(CR_OK);
5157 }
5158
5159 /**
5160 The main function of the mysql_clear_password authentication plugin.
5161 */
5162
clear_password_auth_client(MYSQL_PLUGIN_VIO * vio,MYSQL * mysql)5163 static int clear_password_auth_client(MYSQL_PLUGIN_VIO *vio, MYSQL *mysql)
5164 {
5165 int res;
5166
5167 /* send password in clear text */
5168 res= vio->write_packet(vio, (const unsigned char *) mysql->passwd,
5169 strlen(mysql->passwd) + 1);
5170
5171 return res ? CR_ERROR : CR_OK;
5172 }
5173
5174 #if defined(EXPORT_SYMVER16)
5175 #ifndef EMBEDDED_LIBRARY
5176
5177 // Hack to provide both libmysqlclient_16 and libmysqlclient_18 symbol versions
5178
5179 #define SYM_16(_exportedsym) __asm__(".symver symver16_" #_exportedsym "," #_exportedsym "@libmysqlclient_16")
5180
symver16_mysql_close(MYSQL * mysql)5181 void STDCALL symver16_mysql_close(MYSQL *mysql)
5182 {
5183 return mysql_close(mysql);
5184 }
5185 SYM_16(mysql_close);
5186
5187
symver16_mysql_errno(MYSQL * mysql)5188 uint STDCALL symver16_mysql_errno(MYSQL *mysql)
5189 {
5190 return mysql_errno(mysql);
5191 }
5192 SYM_16(mysql_errno);
5193
5194
symver16_mysql_error(MYSQL * mysql)5195 const char * STDCALL symver16_mysql_error(MYSQL *mysql)
5196 {
5197 return mysql_error(mysql);
5198 }
5199 SYM_16(mysql_error);
5200
5201
symver16_mysql_fetch_lengths(MYSQL_RES * res)5202 ulong * STDCALL symver16_mysql_fetch_lengths(MYSQL_RES *res)
5203 {
5204 return mysql_fetch_lengths(res);
5205 }
5206 SYM_16(mysql_fetch_lengths);
5207
5208
symver16_mysql_fetch_row(MYSQL_RES * res)5209 MYSQL_ROW STDCALL symver16_mysql_fetch_row(MYSQL_RES *res)
5210 {
5211 return mysql_fetch_row(res);
5212 }
5213 SYM_16(mysql_fetch_row);
5214
5215
symver16_mysql_free_result(MYSQL_RES * result)5216 void STDCALL symver16_mysql_free_result(MYSQL_RES *result)
5217 {
5218 return mysql_free_result(result);
5219 }
5220 SYM_16(mysql_free_result);
5221
5222
symver16_mysql_get_server_version(MYSQL * mysql)5223 ulong STDCALL symver16_mysql_get_server_version(MYSQL *mysql)
5224 {
5225 return mysql_get_server_version(mysql);
5226 }
5227 SYM_16(mysql_get_server_version);
5228
5229
symver16_mysql_get_ssl_cipher(MYSQL * mysql)5230 const char * STDCALL symver16_mysql_get_ssl_cipher(MYSQL *mysql __attribute__((unused)))
5231 {
5232 return mysql_get_ssl_cipher(mysql);
5233 }
5234 SYM_16(mysql_get_ssl_cipher);
5235
5236
symver16_mysql_init(MYSQL * mysql)5237 MYSQL * STDCALL symver16_mysql_init(MYSQL *mysql)
5238 {
5239 return mysql_init(mysql);
5240 }
5241 SYM_16(mysql_init);
5242
5243
symver16_mysql_num_fields(MYSQL_RES * res)5244 unsigned int STDCALL symver16_mysql_num_fields(MYSQL_RES *res)
5245 {
5246 return mysql_num_fields(res);
5247 }
5248 SYM_16(mysql_num_fields);
5249
5250
symver16_mysql_num_rows(MYSQL_RES * res)5251 my_ulonglong STDCALL symver16_mysql_num_rows(MYSQL_RES *res)
5252 {
5253 return mysql_num_rows(res);
5254 }
5255 SYM_16(mysql_num_rows);
5256
5257
symver16_mysql_options(MYSQL * mysql,enum mysql_option option,const void * arg)5258 int STDCALL symver16_mysql_options(MYSQL *mysql,enum mysql_option option, const void *arg)
5259 {
5260 return mysql_options(mysql, option, arg);
5261 }
5262 SYM_16(mysql_options);
5263
5264
symver16_mysql_real_query(MYSQL * mysql,const char * query,ulong length)5265 int STDCALL symver16_mysql_real_query(MYSQL *mysql, const char *query, ulong length)
5266 {
5267 return mysql_real_query(mysql, query, length);
5268 }
5269 SYM_16(mysql_real_query);
5270
5271
symver16_mysql_select_db(MYSQL * mysql,const char * db)5272 int STDCALL symver16_mysql_select_db(MYSQL *mysql, const char *db)
5273 {
5274 return mysql_select_db(mysql, db);
5275 }
5276 SYM_16(mysql_select_db);
5277
5278
symver16_mysql_send_query(MYSQL * mysql,const char * query,ulong length)5279 int STDCALL symver16_mysql_send_query(MYSQL* mysql, const char* query, ulong length)
5280 {
5281 return mysql_send_query(mysql, query, length);
5282 }
5283 SYM_16(mysql_send_query);
5284
5285
symver16_mysql_set_character_set(MYSQL * mysql,const char * cs_name)5286 int STDCALL symver16_mysql_set_character_set(MYSQL *mysql, const char *cs_name)
5287 {
5288 return mysql_set_character_set(mysql, cs_name);
5289 }
5290 SYM_16(mysql_set_character_set);
5291
5292
symver16_mysql_ssl_set(MYSQL * mysql,const char * key,const char * cert,const char * ca,const char * capath,const char * cipher)5293 my_bool STDCALL symver16_mysql_ssl_set(MYSQL *mysql __attribute__((unused)), const char *key __attribute__((unused)), const char *cert __attribute__((unused)), const char *ca __attribute__((unused)), const char *capath __attribute__((unused)), const char *cipher __attribute__((unused)))
5294 {
5295 return mysql_ssl_set(mysql, key, cert, ca, capath, cipher);
5296 }
5297 SYM_16(mysql_ssl_set);
5298
5299
symver16_mysql_store_result(MYSQL * mysql)5300 MYSQL_RES * STDCALL symver16_mysql_store_result(MYSQL *mysql)
5301 {
5302 return mysql_store_result(mysql);
5303 }
5304 SYM_16(mysql_store_result);
5305
5306 #endif
5307 #endif /* EXPORT_SYMVER16 */
5308