Commit 30ced7f7 authored by unknown's avatar unknown

Style fixes, comments for 4.1.1 authorization

Now special 1-byte packet is used for request of old password
Fixed bug with --skip-grant-tables and acl_getroot


include/mysql.h:
  removed scramble_323 member as now scramble_323 function does not count
  on trailing zero for scramble
include/mysql_com.h:
  updated declarations
libmysql/libmysql.c:
  now server sends special 1-byte packet instead of old scramble
  to re-request password.
  mysql->scramble_323 replaced with mysql->scramble
sql-common/client.c:
  now server sends special 1-byte packet instead of old scramble
  to re-request password.
  mysql->scramble_323 replaces with mysql->scramble
sql/password.c:
  comments beautified
  hash_password now accepts password length
sql/protocol.cc:
  added send_old_password_request function
sql/protocol.h:
  added send_old_password_request function
sql/sql_acl.cc:
  style fixes, bug with --skip-grant-tables and acl_getroot
  fixed
sql/sql_class.h:
  thd->scramble_323 removed as now
  old functions accept not null-terminated scrambles
sql/sql_crypt.cc:
  fixed with new hash_password proto
sql/sql_parse.cc:
  style fixes
  few comments added
parent 84afd56e
......@@ -228,8 +228,8 @@ typedef struct st_mysql
my_bool free_me; /* If free in mysql_close */
my_bool reconnect; /* set to 1 if automatic reconnect */
char scramble[SCRAMBLE_LENGTH+1]; /* for new servers */
char scramble_323[SCRAMBLE_LENGTH_323+1]; /* for old servers */
/* session-wide random string */
char scramble[max(SCRAMBLE_LENGTH,SCRAMBLE_LENGTH_323)+1];
/*
Set if this is the original connection, not a master or a slave we have
......
......@@ -318,9 +318,9 @@ void randominit(struct rand_struct *, unsigned long seed1,
double my_rnd(struct rand_struct *);
void create_random_string(char *to, uint length, struct rand_struct *rand_st);
void hash_password(ulong *to, const char *password);
void hash_password(ulong *to, const char *password, uint password_len);
void make_scrambled_password_323(char *to, const char *password);
char *scramble_323(char *to, const char *message, const char *password);
void scramble_323(char *to, const char *message, const char *password);
my_bool check_scramble_323(const char *, const char *message,
unsigned long *salt);
void get_salt_from_password_323(unsigned long *res, const char *password);
......
......@@ -626,7 +626,10 @@ my_bool STDCALL mysql_change_user(MYSQL *mysql, const char *user,
end+= SCRAMBLE_LENGTH;
}
else
end= scramble_323(end, mysql->scramble_323, passwd);
{
scramble_323(end, mysql->scramble, passwd);
end+= SCRAMBLE_LENGTH_323 + 1;
}
}
else
*end++= '\0'; // empty password
......@@ -642,15 +645,14 @@ my_bool STDCALL mysql_change_user(MYSQL *mysql, const char *user,
if (pkt_length == packet_error)
goto error;
if (net->read_pos[0] == mysql->scramble_323[0] &&
pkt_length == SCRAMBLE_LENGTH_323 + 1 &&
if (pkt_length == 1 && net->read_pos[0] == 254 &&
mysql->server_capabilities & CLIENT_SECURE_CONNECTION)
{
/*
By sending this very specific reply server asks us to send scrambled
password in old format. The reply contains scramble_323.
*/
scramble_323(buff, mysql->scramble_323, passwd);
scramble_323(buff, mysql->scramble, passwd);
if (my_net_write(net, buff, SCRAMBLE_LENGTH_323 + 1) || net_flush(net))
{
net->last_errno= CR_SERVER_LOST;
......
......@@ -1641,9 +1641,8 @@ mysql_real_connect(MYSQL *mysql,const char *host, const char *user,
Scramble is split into two parts because old clients does not understand
long scrambles; here goes the first part.
*/
strmake(mysql->scramble_323, end, SCRAMBLE_LENGTH_323);
strmake(mysql->scramble, end, SCRAMBLE_LENGTH_323);
end+= SCRAMBLE_LENGTH_323+1;
memcpy(mysql->scramble, mysql->scramble_323, SCRAMBLE_LENGTH_323);
if (pkt_length >= (uint) (end+1 - (char*) net->read_pos))
mysql->server_capabilities=uint2korr(end);
......@@ -1842,7 +1841,10 @@ mysql_real_connect(MYSQL *mysql,const char *host, const char *user,
end+= SCRAMBLE_LENGTH;
}
else
end= scramble_323(end, mysql->scramble_323, passwd) + 1;
{
scramble_323(end, mysql->scramble, passwd);
end+= SCRAMBLE_LENGTH_323 + 1;
}
}
else
*end++= '\0'; /* empty password */
......@@ -1871,15 +1873,14 @@ mysql_real_connect(MYSQL *mysql,const char *host, const char *user,
if ((pkt_length=net_safe_read(mysql)) == packet_error)
goto error;
if (net->read_pos[0] == mysql->scramble_323[0] &&
pkt_length == SCRAMBLE_LENGTH_323 + 1 &&
if (pkt_length == 1 && net->read_pos[0] == 254 &&
mysql->server_capabilities & CLIENT_SECURE_CONNECTION)
{
/*
By sending this very specific reply server asks us to send scrambled
password in old format. The reply contains scramble_323.
*/
scramble_323(buff, mysql->scramble_323, passwd);
scramble_323(buff, mysql->scramble, passwd);
if (my_net_write(net, buff, SCRAMBLE_LENGTH_323 + 1) || net_flush(net))
{
net->last_errno= CR_SERVER_LOST;
......
......@@ -110,15 +110,17 @@ double my_rnd(struct rand_struct *rand_st)
Used for Pre-4.1 password handling
SYNOPSIS
hash_password()
result OUT store hash in this location
password IN plain text password to build hash
result OUT store hash in this location
password IN plain text password to build hash
password_len IN password length (password may be not null-terminated)
*/
void hash_password(ulong *result, const char *password)
void hash_password(ulong *result, const char *password, uint password_len)
{
register ulong nr=1345345333L, add=7, nr2=0x12345671L;
ulong tmp;
for (; *password ; password++)
const char *password_end= password + password_len;
for (; password < password_end; password++)
{
if (*password == ' ' || *password == '\t')
continue; /* skip space in password */
......@@ -129,7 +131,6 @@ void hash_password(ulong *result, const char *password)
}
result[0]=nr & (((ulong) 1L << 31) -1L); /* Don't use sign bit (str2int) */;
result[1]=nr2 & (((ulong) 1L << 31) -1L);
return;
}
......@@ -145,7 +146,7 @@ void hash_password(ulong *result, const char *password)
void make_scrambled_password_323(char *to, const char *password)
{
ulong hash_res[2];
hash_password(hash_res, password);
hash_password(hash_res, password, strlen(password));
sprintf(to, "%08lx%08lx", hash_res[0], hash_res[1]);
}
......@@ -157,14 +158,12 @@ void make_scrambled_password_323(char *to, const char *password)
scramble_323()
to OUT Store scrambled message here. Buffer must be at least
SCRAMBLE_LENGTH_323+1 bytes long
message IN Message to scramble. Message must be exactly
SRAMBLE_LENGTH_323 long and NULL terminated.
message IN Message to scramble. Message must be at least
SRAMBLE_LENGTH_323 bytes long.
password IN Password to use while scrambling
RETURN
End of scrambled string
*/
char *scramble_323(char *to, const char *message, const char *password)
void scramble_323(char *to, const char *message, const char *password)
{
struct rand_struct rand_st;
ulong hash_pass[2], hash_message[2];
......@@ -172,18 +171,18 @@ char *scramble_323(char *to, const char *message, const char *password)
if (password && password[0])
{
char *to_start=to;
hash_password(hash_pass,password);
hash_password(hash_message, message);
hash_password(hash_pass,password, strlen(password));
hash_password(hash_message, message, SCRAMBLE_LENGTH_323);
randominit(&rand_st,hash_pass[0] ^ hash_message[0],
hash_pass[1] ^ hash_message[1]);
while (*message++)
const char *message_end= message + SCRAMBLE_LENGTH_323;
for (; message < message_end; message++)
*to++= (char) (floor(my_rnd(&rand_st)*31)+64);
char extra=(char) (floor(my_rnd(&rand_st)*31));
while (to_start != to)
*(to_start++)^=extra;
}
*to= 0;
return to;
}
......@@ -192,11 +191,13 @@ char *scramble_323(char *to, const char *message, const char *password)
Used in pre 4.1 password handling
SYNOPSIS
check_scramble_323()
scrambled IN scrambled message to check.
message IN original random message which was used for scrambling; must
be exactly SCRAMBLED_LENGTH_323 bytes long and
NULL-terminated.
hash_pass IN password which should be used for scrambling
scrambled scrambled message to check.
message original random message which was used for scrambling; must
be exactly SCRAMBLED_LENGTH_323 bytes long and
NULL-terminated.
hash_pass password which should be used for scrambling
All params are IN.
RETURN VALUE
0 - password correct
!0 - password invalid
......@@ -211,11 +212,7 @@ check_scramble_323(const char *scrambled, const char *message,
char buff[16],*to,extra; /* Big enough for check */
const char *pos;
/* Check if this exactly N bytes. Overwise this is something fishy */
if (strlen(message) != SCRAMBLE_LENGTH_323)
return 1; /* Wrong password */
hash_password(hash_message,message);
hash_password(hash_message, message, SCRAMBLE_LENGTH_323);
randominit(&rand_st,hash_pass[0] ^ hash_message[0],
hash_pass[1] ^ hash_message[1]);
to=buff;
......@@ -231,7 +228,7 @@ check_scramble_323(const char *scrambled, const char *message,
return 0;
}
static uint8 char_val(uint8 X)
static inline uint8 char_val(uint8 X)
{
return (uint) (X >= '0' && X <= '9' ? X-'0' :
X >= 'A' && X <= 'Z' ? X-'A'+10 : X-'a'+10);
......@@ -280,7 +277,10 @@ void make_password_from_salt_323(char *to, const ulong *salt)
}
/******************* MySQL 4.1.1 authentification routines ******************/
/*
**************** MySQL 4.1.1 authentification routines *************
*/
/*
Generate string of printable random characters of requested length
SYNOPSIS
......@@ -315,19 +315,16 @@ void create_random_string(char *to, uint length, struct rand_struct *rand_st)
str, len IN the beginning and the length of the input string
*/
static
void
static void
octet2hex(char *to, const uint8 *str, uint len)
{
static const char alphabet[] = { '0', '1', '2', '3', '4', '5', '6', '7',
'8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };
const uint8 *str_end= str + len;
for (; str != str_end; ++str)
{
*to++= alphabet[(*str & 0xF0) >> 4];
*to++= alphabet[*str & 0x0F];
*to++= _dig_vec[(*str & 0xF0) >> 4];
*to++= _dig_vec[*str & 0x0F];
}
*to++= '\0';
*to= '\0';
}
......@@ -341,15 +338,14 @@ octet2hex(char *to, const uint8 *str, uint len)
overlap; len % 2 == 0
*/
static
void
static void
hex2octet(uint8 *to, const char *str, uint len)
{
const char *str_end= str + len;
while (str < str_end)
{
*to= char_val(*str++) << 4;
*to++|= char_val(*str++);
register char tmp= char_val(*str++);
*to++= (tmp << 4) | char_val(*str++);
}
}
......@@ -366,9 +362,8 @@ hex2octet(uint8 *to, const char *str, uint len)
len IN length of s1 and s2
*/
static
void
my_crypt(char *to, const uint8 *s1, const uint8 *s2, uint len)
static void
my_crypt(char *to, const uchar *s1, const uchar *s2, uint len)
{
const uint8 *s1_end= s1 + len;
while (s1 < s1_end)
......@@ -447,7 +442,7 @@ scramble(char *to, const char *message, const char *password)
sha1_input(&sha1_context, hash_stage2, SHA1_HASH_SIZE);
/* xor allows 'from' and 'to' overlap: lets take advantage of it */
sha1_result(&sha1_context, (uint8 *) to);
my_crypt(to, (const uint8 *) to, hash_stage1, SCRAMBLE_LENGTH);
my_crypt(to, (const uchar *) to, hash_stage1, SCRAMBLE_LENGTH);
}
......@@ -459,11 +454,13 @@ scramble(char *to, const char *message, const char *password)
long (if not, something fishy is going on).
SYNOPSIS
check_scramble()
scramble IN clients' reply, presumably produced by scramble()
message IN original random string, previously sent to client
(presumably second argument of scramble()), must be
exactly SCRAMBLE_LENGTH long and NULL-terminated.
hash_stage2 IN hex2octet-decoded database entry
scramble clients' reply, presumably produced by scramble()
message original random string, previously sent to client
(presumably second argument of scramble()), must be
exactly SCRAMBLE_LENGTH long and NULL-terminated.
hash_stage2 hex2octet-decoded database entry
All params are IN.
RETURN VALUE
0 password is correct
!0 password is invalid
......@@ -483,7 +480,7 @@ check_scramble(const char *scramble, const char *message,
sha1_input(&sha1_context, hash_stage2, SHA1_HASH_SIZE);
sha1_result(&sha1_context, buf);
/* encrypt scramble */
my_crypt((char *) buf, buf, (const uint8 *) scramble, SCRAMBLE_LENGTH);
my_crypt((char *) buf, buf, (const uchar *) scramble, SCRAMBLE_LENGTH);
/* now buf supposedly contains hash_stage1: so we can get hash_stage2 */
sha1_reset(&sha1_context);
sha1_input(&sha1_context, buf, SHA1_HASH_SIZE);
......
......@@ -348,6 +348,25 @@ send_eof(THD *thd, bool no_flush)
}
DBUG_VOID_RETURN;
}
/*
Please client to send scrambled_password in old format.
SYNOPSYS
send_old_password_request()
thd thread handle
RETURN VALUE
0 ok
!0 error
*/
bool send_old_password_request(THD *thd)
{
static char buff[1]= { (char) 254 };
NET *net= &thd->net;
return my_net_write(net, buff, 1) || net_flush(net);
}
#endif /* EMBEDDED_LIBRARY */
......
......@@ -164,6 +164,7 @@ void net_printf(THD *thd,uint sql_errno, ...);
void send_ok(THD *thd, ha_rows affected_rows=0L, ulonglong id=0L,
const char *info=0);
void send_eof(THD *thd, bool no_flush=0);
bool send_old_password_request(THD *thd);
char *net_store_length(char *packet,ulonglong length);
char *net_store_length(char *packet,uint length);
char *net_store_data(char *to,const char *from, uint length);
......
......@@ -264,10 +264,11 @@ my_bool acl_init(THD *org_thd, bool dont_read_acl_tables)
{
switch (password_len) {
case 45: /* 4.1: to be removed */
sql_print_error("Found 4.1 style password for user '%s'. "
sql_print_error("Found 4.1 style password for user '%s@%s'. "
"Ignoring user. "
"You should change password for this user.",
user.user ? user.user : "");
user.user ? user.user : "",
user.host.hostname ? user.host.hostname : "");
break;
default:
sql_print_error("Found invalid password for user: '%s@%s'; "
......@@ -526,23 +527,30 @@ static int acl_compare(ACL_ACCESS *a,ACL_ACCESS *b)
/*
Seek ACL entry for a user, check password, SSL cypher, and if
everything is OK, update THD user data and USER_RESOURCES struct.
IMPLEMENTATION
This function does not check if the user has any sensible privileges:
only user's existence and validity is checked.
Note, that entire operation is protected by acl_cache_lock.
SYNOPSIS
thd INOUT thread handle. If all checks are OK,
thd->priv_user, thd->master_access are updated.
thd->host, thd->ip, thd->user are used for checks.
mqh OUT user resources; on success mqh is reset, else
unchanged
passwd IN scrambled & crypted password, recieved from client
(to check): thd->scramble or thd->scramble_323 is
used to decrypt passwd, so they must contain
original random string,
passwd_len IN length of passwd, must be one of 0, 8,
SCRAMBLE_LENGTH_323, SCRAMBLE_LENGTH
acl_getroot()
thd thread handle. If all checks are OK,
thd->priv_user, thd->master_access are updated.
thd->host, thd->ip, thd->user are used for checks.
mqh user resources; on success mqh is reset, else
unchanged
passwd scrambled & crypted password, recieved from client
(to check): thd->scramble or thd->scramble_323 is
used to decrypt passwd, so they must contain
original random string,
passwd_len length of passwd, must be one of 0, 8,
SCRAMBLE_LENGTH_323, SCRAMBLE_LENGTH
'thd' and 'mqh' are updated on success; other params are IN.
RETURN VALUE
0 success: thread data and mqh are updated
0 success: thd->priv_user, thd->priv_host, thd->master_access, mqh are
updated
1 user not found or authentification failure
2 user found, has long (4.1.1) salt, but passwd is in old (3.23) format.
-1 user found, has short (3.23) salt, but passwd is in new (4.1.1) format.
......@@ -553,9 +561,16 @@ int acl_getroot(THD *thd, USER_RESOURCES *mqh,
{
DBUG_ENTER("acl_getroot");
if (!initialized) /* if no data allow anything */
{
DBUG_RETURN(1);
if (!initialized)
{
/*
here if mysqld's been started with --skip-grant-tables option.
*/
thd->priv_user= (char *) ""; // privileges for
*thd->priv_host= '\0'; // the user are unknown
thd->master_access= ~NO_ACCESS; // everything is allowed
bzero(mqh, sizeof(*mqh));
DBUG_RETURN(0);
}
int res= 1;
......@@ -582,7 +597,7 @@ int acl_getroot(THD *thd, USER_RESOURCES *mqh,
if (user_i->salt_len == 0 ||
user_i->salt_len == SCRAMBLE_LENGTH &&
check_scramble(passwd, thd->scramble, user_i->salt) == 0 ||
check_scramble_323(passwd, thd->scramble_323,
check_scramble_323(passwd, thd->scramble,
(ulong *) user_i->salt) == 0)
{
acl_user= user_i;
......@@ -1346,8 +1361,7 @@ static int replace_user_table(THD *thd, TABLE *table, const LEX_USER &combo,
{
int error = -1;
bool old_row_exists=0;
char empty_string[]= { '\0' };
char *password= empty_string;
const char *password= "";
uint password_len= 0;
char what= (revoke_grant) ? 'N' : 'Y';
DBUG_ENTER("replace_user_table");
......
......@@ -547,13 +547,7 @@ class THD :public ilink
DYNAMIC_ARRAY user_var_events;
/* scramble - random string sent to client on handshake */
char scramble[SCRAMBLE_LENGTH+1];
/*
The same as scramble but for old password checking routines. It always
contains first N bytes of scramble.
See check_connection() at sql_parse.cc for authentification details.
*/
char scramble_323[SCRAMBLE_LENGTH_323+1];
char scramble[max(SCRAMBLE_LENGTH, SCRAMBLE_LENGTH_323)+1];
uint8 query_cache_type; // type of query cache processing
bool slave_thread;
......
......@@ -32,7 +32,7 @@
SQL_CRYPT::SQL_CRYPT(const char *password)
{
ulong rand_nr[2];
hash_password(rand_nr,password);
hash_password(rand_nr,password, strlen(password));
crypt_init(rand_nr);
}
......
......@@ -181,17 +181,20 @@ static int get_or_create_user_conn(THD *thd, const char *user,
Check if user exist and password supplied is correct.
SYNOPSIS
check_user()
thd INOUT thread handle, thd->{host,user,ip} are used
command IN originator of the check: now check_user is called
during connect and change user procedures; used for
logging.
passwd IN scrambled password recieved from client
passwd_len IN length of scrambled password
db IN database name to connect to, may be NULL
check_count IN dont know exactly
thd thread handle, thd->{host,user,ip} are used
command originator of the check: now check_user is called
during connect and change user procedures; used for
logging.
passwd scrambled password recieved from client
passwd_len length of scrambled password
db database name to connect to, may be NULL
check_count dont know exactly
Note, that host, user and passwd may point to communication buffer.
Current implementation does not depened on that, but future changes
should be done with this in mind.
should be done with this in mind; 'thd' is INOUT, all other params
are 'IN'.
RETURN VALUE
0 OK; thd->user, thd->master_access, thd->priv_user, thd->db and
thd->db_access are updated; OK is sent to client;
......@@ -226,8 +229,10 @@ static int check_user(THD *thd, enum enum_server_command command,
DBUG_RETURN(ER_HANDSHAKE_ERROR);
/*
Why this is set here? - probably to reset current DB to 'no database
selected' in case of 'change user' failure.
Clear thd->db as it points to something, that will be freed when
connection is closed. We don't want to accidently free a wrong pointer
if connect failed. Also in case of 'CHANGE USER' failure, current
database will be switched to 'no database selected'.
*/
thd->db= 0;
thd->db_length= 0;
......@@ -244,6 +249,7 @@ static int check_user(THD *thd, enum enum_server_command command,
scramble_323()). Here we please client to send scrambled_password
in old format.
*/
NET *net= &thd->net;
if (opt_secure_auth_local)
{
net_printf(thd, ER_SERVER_IS_IN_SECURE_AUTH_MODE,
......@@ -258,9 +264,7 @@ static int check_user(THD *thd, enum enum_server_command command,
strmake(buff, db, NAME_LEN);
db= buff;
}
NET *net= &thd->net;
if (my_net_write(net, thd->scramble_323, SCRAMBLE_LENGTH_323 + 1) ||
net_flush(net) ||
if (send_old_password_request(thd) ||
my_net_read(net) != SCRAMBLE_LENGTH_323 + 1) // We have to read very
{ // specific packet size
inc_host_errors(&thd->remote.sin_addr);
......@@ -288,7 +292,7 @@ static int check_user(THD *thd, enum enum_server_command command,
{
VOID(pthread_mutex_lock(&LOCK_thread_count));
bool count_ok= thread_count < max_connections + delayed_insert_threads
|| thd->master_access & SUPER_ACL;
|| (thd->master_access & SUPER_ACL);
VOID(pthread_mutex_unlock(&LOCK_thread_count));
if (!count_ok)
{ // too many connections
......@@ -305,7 +309,11 @@ static int check_user(THD *thd, enum enum_server_command command,
thd->user, thd->host_or_ip,
db ? db : (char*) "");
/* Why is it set here? */
/*
This is the default access rights for the current database. It's
set to 0 here because we don't have an active database yet (and we
may not have an active database to set.
*/
thd->db_access=0;
/* Don't allow user to connect if he has done too many queries */
......@@ -554,9 +562,10 @@ static void reset_mqh(THD *thd, LEX_USER *lu, bool get_them= 0)
Perform handshake, authorize client and update thd ACL variables.
SYNOPSIS
check_connection()
thd INOUT thread handle
thd thread handle
RETURN
0 success, OK is sent to user
0 success, OK is sent to user, thd is updated.
-1 error, which is sent to user
> 0 error code (not sent to user)
*/
......@@ -644,14 +653,12 @@ check_connection(THD *thd)
each handshake.
*/
create_random_string(thd->scramble, SCRAMBLE_LENGTH, &thd->rand);
strmake(thd->scramble_323, thd->scramble, SCRAMBLE_LENGTH_323);
/*
Old clients does not understand long scrambles, but can ignore packet
tail: that's why first part of the scramble is placed here, and second
part at the end of packet.
*/
end= strmake(end, thd->scramble_323, SCRAMBLE_LENGTH_323) + 1;
end= strmake(end, thd->scramble, SCRAMBLE_LENGTH_323) + 1;
int2store(end, client_flags);
/* write server characteristics: up to 16 bytes allowed */
......@@ -754,8 +761,6 @@ check_connection(THD *thd)
return(ER_HANDSHAKE_ERROR);
}
/* why has it been put here? */
if (thd->client_capabilities & CLIENT_INTERACTIVE)
thd->variables.net_wait_timeout= thd->variables.net_interactive_timeout;
if ((thd->client_capabilities & CLIENT_TRANSACTIONS) &&
......@@ -778,9 +783,8 @@ check_connection(THD *thd)
if (thd->user)
x_free(thd->user);
thd->user= my_strdup(user, MYF(0));
if (!thd->user)
return(ER_OUT_OF_RESOURCES);
if (!(thd->user= my_strdup(user, MYF(0))))
return (ER_OUT_OF_RESOURCES);
return check_user(thd, COM_CONNECT, passwd, passwd_len, db, true);
}
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment