mirror of
https://github.com/MariaDB/server.git
synced 2025-07-29 05:21:33 +03:00
Updated/added copyright headers
This commit is contained in:
@ -1,5 +1,5 @@
|
||||
/*
|
||||
Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
|
||||
Copyright (c) 2007, 2011, Oracle and/or its affiliates. All rights reserved.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
@ -15,7 +15,6 @@
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
Functions to autenticate and handle reqests for a connection
|
||||
*/
|
||||
@ -344,7 +343,7 @@ check_user(THD *thd, enum enum_server_command command,
|
||||
passwd_len != SCRAMBLE_LENGTH &&
|
||||
passwd_len != SCRAMBLE_LENGTH_323)
|
||||
{
|
||||
my_error(ER_HANDSHAKE_ERROR, MYF(0), thd->main_security_ctx.host_or_ip);
|
||||
my_error(ER_HANDSHAKE_ERROR, MYF(0));
|
||||
DBUG_RETURN(1);
|
||||
}
|
||||
|
||||
@ -375,7 +374,7 @@ check_user(THD *thd, enum enum_server_command command,
|
||||
my_net_read(net) != SCRAMBLE_LENGTH_323 + 1)
|
||||
{
|
||||
inc_host_errors(&thd->remote.sin_addr);
|
||||
my_error(ER_HANDSHAKE_ERROR, MYF(0), thd->main_security_ctx.host_or_ip);
|
||||
my_error(ER_HANDSHAKE_ERROR, MYF(0));
|
||||
DBUG_RETURN(1);
|
||||
}
|
||||
/* Final attempt to check the user based on reply */
|
||||
@ -584,8 +583,23 @@ void reset_mqh(LEX_USER *lu, bool get_them= 0)
|
||||
}
|
||||
|
||||
|
||||
void thd_init_client_charset(THD *thd, uint cs_number)
|
||||
/**
|
||||
Set thread character set variables from the given ID
|
||||
|
||||
@param thd thread handle
|
||||
@param cs_number character set and collation ID
|
||||
|
||||
@retval 0 OK; character_set_client, collation_connection and
|
||||
character_set_results are set to the new value,
|
||||
or to the default global values.
|
||||
|
||||
@retval 1 error, e.g. the given ID is not supported by parser.
|
||||
Corresponding SQL error is sent.
|
||||
*/
|
||||
|
||||
bool thd_init_client_charset(THD *thd, uint cs_number)
|
||||
{
|
||||
CHARSET_INFO *cs;
|
||||
/*
|
||||
Use server character set and collation if
|
||||
- opt_character_set_client_handshake is not set
|
||||
@ -594,10 +608,10 @@ void thd_init_client_charset(THD *thd, uint cs_number)
|
||||
- client character set doesn't exists in server
|
||||
*/
|
||||
if (!opt_character_set_client_handshake ||
|
||||
!(thd->variables.character_set_client= get_charset(cs_number, MYF(0))) ||
|
||||
!(cs= get_charset(cs_number, MYF(0))) ||
|
||||
!my_strcasecmp(&my_charset_latin1,
|
||||
global_system_variables.character_set_client->name,
|
||||
thd->variables.character_set_client->name))
|
||||
cs->name))
|
||||
{
|
||||
thd->variables.character_set_client=
|
||||
global_system_variables.character_set_client;
|
||||
@ -608,10 +622,18 @@ void thd_init_client_charset(THD *thd, uint cs_number)
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!is_supported_parser_charset(cs))
|
||||
{
|
||||
/* Disallow non-supported parser character sets: UCS2, UTF16, UTF32 */
|
||||
my_error(ER_WRONG_VALUE_FOR_VAR, MYF(0), "character_set_client",
|
||||
cs->csname);
|
||||
return true;
|
||||
}
|
||||
thd->variables.character_set_results=
|
||||
thd->variables.collation_connection=
|
||||
thd->variables.character_set_client;
|
||||
thd->variables.character_set_client= cs;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@ -632,6 +654,154 @@ bool init_new_connection_handler_thread()
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifndef EMBEDDED_LIBRARY
|
||||
|
||||
/** Get a string according to the protocol of the underlying buffer. */
|
||||
typedef char * (*get_proto_string_func_t) (char **, size_t *, size_t *);
|
||||
|
||||
/**
|
||||
Get a string formatted according to the 4.1 version of the MySQL protocol.
|
||||
|
||||
@param buffer[in, out] Pointer to the user-supplied buffer to be scanned.
|
||||
@param max_bytes_available[in, out] Limit the bytes to scan.
|
||||
@param string_length[out] The number of characters scanned not including
|
||||
the null character.
|
||||
|
||||
@remark Strings are always null character terminated in this version of the
|
||||
protocol.
|
||||
|
||||
@remark The string_length does not include the terminating null character.
|
||||
However, after the call, the buffer is increased by string_length+1
|
||||
bytes, beyond the null character if there still available bytes to
|
||||
scan.
|
||||
|
||||
@return pointer to beginning of the string scanned.
|
||||
@retval NULL The buffer content is malformed
|
||||
*/
|
||||
|
||||
static
|
||||
char *get_41_protocol_string(char **buffer,
|
||||
size_t *max_bytes_available,
|
||||
size_t *string_length)
|
||||
{
|
||||
char *str= (char *)memchr(*buffer, '\0', *max_bytes_available);
|
||||
|
||||
if (str == NULL)
|
||||
return NULL;
|
||||
|
||||
*string_length= (size_t)(str - *buffer);
|
||||
*max_bytes_available-= *string_length + 1;
|
||||
str= *buffer;
|
||||
*buffer += *string_length + 1;
|
||||
|
||||
return str;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Get a string formatted according to the 4.0 version of the MySQL protocol.
|
||||
|
||||
@param buffer[in, out] Pointer to the user-supplied buffer to be scanned.
|
||||
@param max_bytes_available[in, out] Limit the bytes to scan.
|
||||
@param string_length[out] The number of characters scanned not including
|
||||
the null character.
|
||||
|
||||
@remark If there are not enough bytes left after the current position of
|
||||
the buffer to satisfy the current string, the string is considered
|
||||
to be empty and a pointer to empty_c_string is returned.
|
||||
|
||||
@remark A string at the end of the packet is not null terminated.
|
||||
|
||||
@return Pointer to beginning of the string scanned, or a pointer to a empty
|
||||
string.
|
||||
*/
|
||||
static
|
||||
char *get_40_protocol_string(char **buffer,
|
||||
size_t *max_bytes_available,
|
||||
size_t *string_length)
|
||||
{
|
||||
char *str;
|
||||
size_t len;
|
||||
|
||||
/* No bytes to scan left, treat string as empty. */
|
||||
if ((*max_bytes_available) == 0)
|
||||
{
|
||||
*string_length= 0;
|
||||
return empty_c_string;
|
||||
}
|
||||
|
||||
str= (char *) memchr(*buffer, '\0', *max_bytes_available);
|
||||
|
||||
/*
|
||||
If the string was not null terminated by the client,
|
||||
the remainder of the packet is the string. Otherwise,
|
||||
advance the buffer past the end of the null terminated
|
||||
string.
|
||||
*/
|
||||
if (str == NULL)
|
||||
len= *string_length= *max_bytes_available;
|
||||
else
|
||||
len= (*string_length= (size_t)(str - *buffer)) + 1;
|
||||
|
||||
str= *buffer;
|
||||
*buffer+= len;
|
||||
*max_bytes_available-= len;
|
||||
|
||||
return str;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Get a length encoded string from a user-supplied buffer.
|
||||
|
||||
@param buffer[in, out] The buffer to scan; updates position after scan.
|
||||
@param max_bytes_available[in, out] Limit the number of bytes to scan
|
||||
@param string_length[out] Number of characters scanned
|
||||
|
||||
@remark In case the length is zero, then the total size of the string is
|
||||
considered to be 1 byte; the size byte.
|
||||
|
||||
@return pointer to first byte after the header in buffer.
|
||||
@retval NULL The buffer content is malformed
|
||||
*/
|
||||
|
||||
static
|
||||
char *get_length_encoded_string(char **buffer,
|
||||
size_t *max_bytes_available,
|
||||
size_t *string_length)
|
||||
{
|
||||
if (*max_bytes_available == 0)
|
||||
return NULL;
|
||||
|
||||
/* Do double cast to prevent overflow from signed / unsigned conversion */
|
||||
size_t str_len= (size_t)(unsigned char)**buffer;
|
||||
|
||||
/*
|
||||
If the length encoded string has the length 0
|
||||
the total size of the string is only one byte long (the size byte)
|
||||
*/
|
||||
if (str_len == 0)
|
||||
{
|
||||
++*buffer;
|
||||
*string_length= 0;
|
||||
/*
|
||||
Return a pointer to the 0 character so the return value will be
|
||||
an empty string.
|
||||
*/
|
||||
return *buffer-1;
|
||||
}
|
||||
|
||||
if (str_len >= *max_bytes_available)
|
||||
return NULL;
|
||||
|
||||
char *str= *buffer+1;
|
||||
*string_length= str_len;
|
||||
*max_bytes_available-= *string_length + 1;
|
||||
*buffer+= *string_length + 1;
|
||||
return str;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Perform handshake, authorize client and update thd ACL variables.
|
||||
|
||||
@ -645,7 +815,6 @@ bool init_new_connection_handler_thread()
|
||||
> 0 error code (not sent to user)
|
||||
*/
|
||||
|
||||
#ifndef EMBEDDED_LIBRARY
|
||||
static int check_connection(THD *thd)
|
||||
{
|
||||
uint connect_errors= 0;
|
||||
@ -665,7 +834,7 @@ static int check_connection(THD *thd)
|
||||
|
||||
if (vio_peer_addr(net->vio, ip, &thd->peer_port))
|
||||
{
|
||||
my_error(ER_BAD_HOST_ERROR, MYF(0), thd->main_security_ctx.host_or_ip);
|
||||
my_error(ER_BAD_HOST_ERROR, MYF(0));
|
||||
return 1;
|
||||
}
|
||||
if (!(thd->main_security_ctx.ip= my_strdup(ip,MYF(MY_WME))))
|
||||
@ -747,7 +916,7 @@ static int check_connection(THD *thd)
|
||||
part at the end of packet.
|
||||
*/
|
||||
end= strmake(end, thd->scramble, SCRAMBLE_LENGTH_323) + 1;
|
||||
|
||||
|
||||
int2store(end, server_capabilites);
|
||||
/* write server characteristics: up to 16 bytes allowed */
|
||||
end[2]=(char) default_charset_info->number;
|
||||
@ -765,8 +934,7 @@ static int check_connection(THD *thd)
|
||||
pkt_len < MIN_HANDSHAKE_SIZE)
|
||||
{
|
||||
inc_host_errors(&thd->remote.sin_addr);
|
||||
my_error(ER_HANDSHAKE_ERROR, MYF(0),
|
||||
thd->main_security_ctx.host_or_ip);
|
||||
my_error(ER_HANDSHAKE_ERROR, MYF(0));
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
@ -784,7 +952,8 @@ static int check_connection(THD *thd)
|
||||
thd->client_capabilities|= ((ulong) uint2korr(net->read_pos+2)) << 16;
|
||||
thd->max_client_packet_length= uint4korr(net->read_pos+4);
|
||||
DBUG_PRINT("info", ("client_character_set: %d", (uint) net->read_pos[8]));
|
||||
thd_init_client_charset(thd, (uint) net->read_pos[8]);
|
||||
if (thd_init_client_charset(thd, (uint) net->read_pos[8]))
|
||||
return 1;
|
||||
thd->update_charset();
|
||||
end= (char*) net->read_pos+32;
|
||||
}
|
||||
@ -809,7 +978,7 @@ static int check_connection(THD *thd)
|
||||
if (!ssl_acceptor_fd)
|
||||
{
|
||||
inc_host_errors(&thd->remote.sin_addr);
|
||||
my_error(ER_HANDSHAKE_ERROR, MYF(0), thd->main_security_ctx.host_or_ip);
|
||||
my_error(ER_HANDSHAKE_ERROR, MYF(0));
|
||||
return 1;
|
||||
}
|
||||
DBUG_PRINT("info", ("IO layer change in progress..."));
|
||||
@ -817,7 +986,7 @@ static int check_connection(THD *thd)
|
||||
{
|
||||
DBUG_PRINT("error", ("Failed to accept new SSL connection"));
|
||||
inc_host_errors(&thd->remote.sin_addr);
|
||||
my_error(ER_HANDSHAKE_ERROR, MYF(0), thd->main_security_ctx.host_or_ip);
|
||||
my_error(ER_HANDSHAKE_ERROR, MYF(0));
|
||||
return 1;
|
||||
}
|
||||
DBUG_PRINT("info", ("Reading user information over SSL layer"));
|
||||
@ -827,16 +996,16 @@ static int check_connection(THD *thd)
|
||||
DBUG_PRINT("error", ("Failed to read user information (pkt_len= %lu)",
|
||||
pkt_len));
|
||||
inc_host_errors(&thd->remote.sin_addr);
|
||||
my_error(ER_HANDSHAKE_ERROR, MYF(0), thd->main_security_ctx.host_or_ip);
|
||||
my_error(ER_HANDSHAKE_ERROR, MYF(0));
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
#endif /* HAVE_OPENSSL */
|
||||
|
||||
if (end >= (char*) net->read_pos+ pkt_len +2)
|
||||
if (end > (char *)net->read_pos + pkt_len)
|
||||
{
|
||||
inc_host_errors(&thd->remote.sin_addr);
|
||||
my_error(ER_HANDSHAKE_ERROR, MYF(0), thd->main_security_ctx.host_or_ip);
|
||||
my_error(ER_HANDSHAKE_ERROR, MYF(0));
|
||||
return 1;
|
||||
}
|
||||
|
||||
@ -846,51 +1015,102 @@ static int check_connection(THD *thd)
|
||||
opt_using_transactions)
|
||||
net->return_status= &thd->server_status;
|
||||
|
||||
char *user= end;
|
||||
char *passwd= strend(user)+1;
|
||||
uint user_len= passwd - user - 1;
|
||||
char *db= passwd;
|
||||
/*
|
||||
The 4.0 and 4.1 versions of the protocol differ on how strings
|
||||
are terminated. In the 4.0 version, if a string is at the end
|
||||
of the packet, the string is not null terminated. Do not assume
|
||||
that the returned string is always null terminated.
|
||||
*/
|
||||
get_proto_string_func_t get_string;
|
||||
|
||||
if (thd->client_capabilities & CLIENT_PROTOCOL_41)
|
||||
get_string= get_41_protocol_string;
|
||||
else
|
||||
get_string= get_40_protocol_string;
|
||||
|
||||
/*
|
||||
In order to safely scan a head for '\0' string terminators
|
||||
we must keep track of how many bytes remain in the allocated
|
||||
buffer or we might read past the end of the buffer.
|
||||
*/
|
||||
size_t bytes_remaining_in_packet= pkt_len - (end - (char *)net->read_pos);
|
||||
|
||||
size_t user_len;
|
||||
char *user= get_string(&end, &bytes_remaining_in_packet, &user_len);
|
||||
if (user == NULL)
|
||||
{
|
||||
inc_host_errors(&thd->remote.sin_addr);
|
||||
my_error(ER_HANDSHAKE_ERROR, MYF(0));
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
Old clients send a null-terminated string as password; new clients send
|
||||
the size (1 byte) + string (not null-terminated). Hence in case of empty
|
||||
password both send '\0'.
|
||||
*/
|
||||
size_t passwd_len= 0;
|
||||
char *passwd= NULL;
|
||||
|
||||
if (thd->client_capabilities & CLIENT_SECURE_CONNECTION)
|
||||
{
|
||||
/*
|
||||
4.1+ password. First byte is password length.
|
||||
*/
|
||||
passwd= get_length_encoded_string(&end, &bytes_remaining_in_packet,
|
||||
&passwd_len);
|
||||
}
|
||||
else
|
||||
{
|
||||
/*
|
||||
Old passwords are zero terminated strings.
|
||||
*/
|
||||
passwd= get_string(&end, &bytes_remaining_in_packet, &passwd_len);
|
||||
}
|
||||
|
||||
if (passwd == NULL)
|
||||
{
|
||||
inc_host_errors(&thd->remote.sin_addr);
|
||||
my_error(ER_HANDSHAKE_ERROR, MYF(0));
|
||||
return 1;
|
||||
}
|
||||
|
||||
size_t db_len= 0;
|
||||
char *db= NULL;
|
||||
|
||||
if (thd->client_capabilities & CLIENT_CONNECT_WITH_DB)
|
||||
{
|
||||
db= get_string(&end, &bytes_remaining_in_packet, &db_len);
|
||||
if (db == NULL)
|
||||
{
|
||||
inc_host_errors(&thd->remote.sin_addr);
|
||||
my_error(ER_HANDSHAKE_ERROR, MYF(0));
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
char db_buff[NAME_LEN + 1]; // buffer to store db in utf8
|
||||
char user_buff[USERNAME_LENGTH + 1]; // buffer to store user in utf8
|
||||
uint dummy_errors;
|
||||
|
||||
/*
|
||||
Old clients send null-terminated string as password; new clients send
|
||||
the size (1 byte) + string (not null-terminated). Hence in case of empty
|
||||
password both send '\0'.
|
||||
|
||||
This strlen() can't be easily deleted without changing protocol.
|
||||
|
||||
Cast *passwd to an unsigned char, so that it doesn't extend the sign for
|
||||
*passwd > 127 and become 2**32-127+ after casting to uint.
|
||||
Copy and convert the user and database names to the character set used
|
||||
by the server. Since 4.1 all database names are stored in UTF-8. Also,
|
||||
ensure that the names are properly null-terminated as this is relied
|
||||
upon later.
|
||||
*/
|
||||
uint passwd_len= thd->client_capabilities & CLIENT_SECURE_CONNECTION ?
|
||||
(uchar)(*passwd++) : strlen(passwd);
|
||||
db= thd->client_capabilities & CLIENT_CONNECT_WITH_DB ?
|
||||
db + passwd_len + 1 : 0;
|
||||
/* strlen() can't be easily deleted without changing protocol */
|
||||
uint db_len= db ? strlen(db) : 0;
|
||||
|
||||
if (passwd + passwd_len + db_len > (char *)net->read_pos + pkt_len)
|
||||
{
|
||||
inc_host_errors(&thd->remote.sin_addr);
|
||||
my_error(ER_HANDSHAKE_ERROR, MYF(0), thd->main_security_ctx.host_or_ip);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Since 4.1 all database names are stored in utf8 */
|
||||
if (db)
|
||||
{
|
||||
db_buff[copy_and_convert(db_buff, sizeof(db_buff)-1,
|
||||
system_charset_info,
|
||||
db, db_len,
|
||||
thd->charset(), &dummy_errors)]= 0;
|
||||
db_len= copy_and_convert(db_buff, sizeof(db_buff)-1, system_charset_info,
|
||||
db, db_len, thd->charset(), &dummy_errors);
|
||||
db_buff[db_len]= '\0';
|
||||
db= db_buff;
|
||||
}
|
||||
|
||||
user_buff[user_len= copy_and_convert(user_buff, sizeof(user_buff)-1,
|
||||
system_charset_info, user, user_len,
|
||||
thd->charset(), &dummy_errors)]= '\0';
|
||||
user_len= copy_and_convert(user_buff, sizeof(user_buff)-1,
|
||||
system_charset_info, user, user_len,
|
||||
thd->charset(), &dummy_errors);
|
||||
user_buff[user_len]= '\0';
|
||||
user= user_buff;
|
||||
|
||||
/* If username starts and ends in "'", chop them off */
|
||||
|
Reference in New Issue
Block a user