mirror of
https://github.com/MariaDB/server.git
synced 2025-01-16 20:12:31 +01:00
05ba93c279
Implement mysql_change_user Get rid of double user search at authentication Some cleanups client/mysqladmin.c: Fix long line include/mysql_com.h: Fix long lines libmysql/libmysql.c: mysql_change_user() for new auth + some fixes sql/password.c: Add author info so who is guilty in errors would be known :) sql/sql_acl.cc: Move class definitions to .h sql/sql_acl.h: Add class definitions sql/sql_parse.cc: Get rid of double user search. Implement mysql_change_user
725 lines
20 KiB
C
725 lines
20 KiB
C
/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
|
|
|
|
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
|
|
the Free Software Foundation; either version 2 of the License, or
|
|
(at your option) any later version.
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with this program; if not, write to the Free Software
|
|
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
|
|
|
|
/* password checking routines */
|
|
/*****************************************************************************
|
|
The main idea is that no password are sent between client & server on
|
|
connection and that no password are saved in mysql in a decodable form.
|
|
|
|
On connection a random string is generated and sent to the client.
|
|
The client generates a new string with a random generator inited with
|
|
the hash values from the password and the sent string.
|
|
This 'check' string is sent to the server where it is compared with
|
|
a string generated from the stored hash_value of the password and the
|
|
random string.
|
|
|
|
The password is saved (in user.password) by using the PASSWORD() function in
|
|
mysql.
|
|
|
|
Example:
|
|
update user set password=PASSWORD("hello") where user="test"
|
|
This saves a hashed number as a string in the password field.
|
|
|
|
|
|
New in MySQL 4.1 authentication works even more secure way.
|
|
At the first step client sends user name to the sever, and password if
|
|
it is empty. So in case of empty password authentication is as fast as before.
|
|
At the second stap servers sends scramble to client, which is encoded with
|
|
password stage2 hash stored in the password database as well as salt, needed
|
|
for client to build stage2 password to decrypt scramble.
|
|
Client decrypts the scramble and encrypts it once again with stage1 password.
|
|
This information is sent to server.
|
|
Server decrypts the scramble to get stage1 password and hashes it to get
|
|
stage2 hash. This hash is when compared to hash stored in the database.
|
|
|
|
This authentication needs 2 packet round trips instead of one but it is much
|
|
stronger. Now if one will steal mysql database content he will not be able
|
|
to break into MySQL.
|
|
|
|
New Password handling functions by Peter Zaitsev
|
|
|
|
|
|
*****************************************************************************/
|
|
|
|
#include <my_global.h>
|
|
#include <my_sys.h>
|
|
#include <m_string.h>
|
|
#include <sha1.h>
|
|
#include "mysql.h"
|
|
|
|
|
|
|
|
/* Character to use as version identifier for version 4.1 */
|
|
#define PVERSION41_CHAR '*'
|
|
|
|
/* Scramble length for new password version */
|
|
#define SCRAMBLE41_LENGTH 20
|
|
|
|
|
|
/*
|
|
New (MySQL 3.21+) random generation structure initialization
|
|
|
|
SYNOPSIS
|
|
randominit()
|
|
rand_st OUT Structure to initialize
|
|
seed1 IN First initialization parameter
|
|
seed2 IN Second initialization parameter
|
|
|
|
RETURN
|
|
none
|
|
*/
|
|
|
|
void randominit(struct rand_struct *rand_st,ulong seed1, ulong seed2)
|
|
{ /* For mysql 3.21.# */
|
|
#ifdef HAVE_purify
|
|
bzero((char*) rand_st,sizeof(*rand_st)); /* Avoid UMC varnings */
|
|
#endif
|
|
rand_st->max_value= 0x3FFFFFFFL;
|
|
rand_st->max_value_dbl=(double) rand_st->max_value;
|
|
rand_st->seed1=seed1%rand_st->max_value ;
|
|
rand_st->seed2=seed2%rand_st->max_value;
|
|
}
|
|
|
|
|
|
/*
|
|
Old (MySQL 3.20) random generation structure initialization
|
|
|
|
SYNOPSIS
|
|
old_randominit()
|
|
rand_st OUT Structure to initialize
|
|
seed1 IN First initialization parameter
|
|
|
|
RETURN
|
|
none
|
|
*/
|
|
|
|
static void old_randominit(struct rand_struct *rand_st,ulong seed1)
|
|
{ /* For mysql 3.20.# */
|
|
rand_st->max_value= 0x01FFFFFFL;
|
|
rand_st->max_value_dbl=(double) rand_st->max_value;
|
|
seed1%=rand_st->max_value;
|
|
rand_st->seed1=seed1 ; rand_st->seed2=seed1/2;
|
|
}
|
|
|
|
|
|
/*
|
|
Generate Random number
|
|
|
|
SYNOPSIS
|
|
rnd()
|
|
rand_st INOUT Structure used for number generation
|
|
|
|
RETURN
|
|
Generated pseudo random number
|
|
*/
|
|
|
|
double rnd(struct rand_struct *rand_st)
|
|
{
|
|
rand_st->seed1=(rand_st->seed1*3+rand_st->seed2) % rand_st->max_value;
|
|
rand_st->seed2=(rand_st->seed1+rand_st->seed2+33) % rand_st->max_value;
|
|
return (((double) rand_st->seed1)/rand_st->max_value_dbl);
|
|
}
|
|
|
|
|
|
/*
|
|
Generate String of printable random characters of requested length
|
|
String will not be zero terminated.
|
|
|
|
SYNOPSIS
|
|
create_random_string()
|
|
length IN Lenght of
|
|
rand_st INOUT Structure used for number generation
|
|
target OUT Buffer for generation
|
|
|
|
RETURN
|
|
none
|
|
*/
|
|
|
|
void create_random_string(int length,struct rand_struct *rand_st,char* target)
|
|
{
|
|
char* end=target+length;
|
|
/* Use pointer arithmetics as it is faster way to do so. */
|
|
while (target<end)
|
|
{
|
|
*target=rnd(rand_st)*94+33;
|
|
target++;
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
Encrypt/Decrypt function used for password encryption in authentication
|
|
Simple XOR is used here but it is OK as we crypt random strings
|
|
|
|
SYNOPSIS
|
|
password_crypt()
|
|
from IN Data for encryption
|
|
to OUT Encrypt data to the buffer (may be the same)
|
|
password IN Password used for encryption (same length)
|
|
length IN Length of data to encrypt
|
|
|
|
RETURN
|
|
none
|
|
*/
|
|
|
|
inline void password_crypt(const char* from,char* to, const char* password,int length)
|
|
{
|
|
const char *from_end=from+length;
|
|
|
|
while(from<from_end)
|
|
{
|
|
*to=*from^*password;
|
|
from++;
|
|
to++;
|
|
password++;
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
Generate binary hash from raw text password
|
|
Used for Pre-4.1 Password handling
|
|
|
|
SYNOPSIS
|
|
hash_pasword()
|
|
result OUT Store hash in this location
|
|
password IN Plain text password to build hash
|
|
|
|
RETURN
|
|
none
|
|
*/
|
|
|
|
void hash_password(ulong *result, const char *password)
|
|
{
|
|
register ulong nr=1345345333L, add=7, nr2=0x12345671L;
|
|
ulong tmp;
|
|
for (; *password ; password++)
|
|
{
|
|
if (*password == ' ' || *password == '\t')
|
|
continue; /* skipp space in password */
|
|
tmp= (ulong) (uchar) *password;
|
|
nr^= (((nr & 63)+add)*tmp)+ (nr << 8);
|
|
nr2+=(nr2 << 8) ^ nr;
|
|
add+=tmp;
|
|
}
|
|
result[0]=nr & (((ulong) 1L << 31) -1L); /* Don't use sign bit (str2int) */;
|
|
result[1]=nr2 & (((ulong) 1L << 31) -1L);
|
|
return;
|
|
}
|
|
|
|
|
|
/*
|
|
Stage one password hashing.
|
|
Used in MySQL 4.1 password handling
|
|
|
|
SYNOPSIS
|
|
password_hash_stage1()
|
|
to OUT Store stage one hash to this location
|
|
password IN Plain text password to build hash
|
|
|
|
RETURN
|
|
none
|
|
*/
|
|
|
|
void password_hash_stage1(char *to, const char *password)
|
|
{
|
|
SHA1_CONTEXT context;
|
|
sha1_reset(&context);
|
|
for (; *password ; password++)
|
|
{
|
|
if (*password == ' ' || *password == '\t')
|
|
continue;/* skip space in password */
|
|
sha1_input(&context,(int8*)&password[0],1);
|
|
}
|
|
sha1_result(&context,(uint8*)to);
|
|
}
|
|
|
|
|
|
/*
|
|
Stage two password hashing.
|
|
Used in MySQL 4.1 password handling
|
|
|
|
SYNOPSIS
|
|
password_hash_stage2()
|
|
to INOUT Use this as stage one hash and store stage two hash here
|
|
salt IN Salt used for stage two hashing
|
|
|
|
RETURN
|
|
none
|
|
*/
|
|
|
|
void password_hash_stage2(char *to,const char *salt)
|
|
{
|
|
SHA1_CONTEXT context;
|
|
sha1_reset(&context);
|
|
sha1_input(&context,(uint8*)salt,4);
|
|
sha1_input(&context,to,SHA1_HASH_SIZE);
|
|
sha1_result(&context,(uint8*)to);
|
|
}
|
|
|
|
|
|
/*
|
|
Create password to be stored in user database from raw string
|
|
Handles both MySQL 4.1 and Pre-MySQL 4.1 passwords
|
|
|
|
SYNOPSIS
|
|
make_scramble_password()
|
|
to OUT Store scrambled password here
|
|
password IN Raw string password
|
|
force_old_scramle
|
|
IN Force generation of old scramble variant
|
|
rand_st INOUT Structure for temporary number generation.
|
|
RETURN
|
|
none
|
|
*/
|
|
|
|
void make_scrambled_password(char *to,const char *password,my_bool force_old_scramble,struct rand_struct *rand_st)
|
|
{
|
|
ulong hash_res[2]; /* Used for pre 4.1 password hashing */
|
|
unsigned short salt; /* Salt for 4.1 version password */
|
|
uint8 digest[SHA1_HASH_SIZE];
|
|
if (force_old_scramble) /* Pre 4.1 password encryption */
|
|
{
|
|
hash_password(hash_res,password);
|
|
sprintf(to,"%08lx%08lx",hash_res[0],hash_res[1]);
|
|
}
|
|
else /* New password 4.1 password scrambling */
|
|
{
|
|
to[0]=PVERSION41_CHAR; /* New passwords have version prefix */
|
|
/* Random returns number from 0 to 1 so this would be good salt generation.*/
|
|
salt=rnd(rand_st)*65535+1;
|
|
/* Use only 2 first bytes from it */
|
|
sprintf(to+1,"%04x",salt);
|
|
/* First hasing is done without salt */
|
|
password_hash_stage1(digest,password);
|
|
/* Second stage is done with salt */
|
|
password_hash_stage2(digest,(char*)to+1),
|
|
/* Print resulting hash into the password*/
|
|
sprintf(to+5,
|
|
"%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x",
|
|
digest[0],digest[1],digest[2],digest[3],digest[4],digest[5],digest[6],
|
|
digest[7],digest[8],digest[9],digest[10],digest[11],digest[12],digest[13],
|
|
digest[14],digest[15],digest[16],digest[17],digest[18],digest[19]);
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
Convert password from binary string form to salt form
|
|
Used for MySQL 4.1 password handling
|
|
|
|
SYNOPSIS
|
|
get_salt_from_bin_password()
|
|
res OUT Store salt form password here
|
|
password IN Binary password to be converted
|
|
salt IN hashing-salt to be used for salt form generation
|
|
|
|
RETURN
|
|
none
|
|
*/
|
|
|
|
void get_salt_from_bin_password(ulong *res,unsigned char *password,ulong salt)
|
|
{
|
|
unsigned char* password_end=password+SCRAMBLE41_LENGTH;
|
|
*res=salt;
|
|
res++;
|
|
bzero(res,5*sizeof(res[0]));
|
|
|
|
/* Process password of known length*/
|
|
while (password<password_end)
|
|
{
|
|
ulong val=0;
|
|
uint i;
|
|
for (i=0 ; i < 4 ; i++)
|
|
val=(val << 8)+(*password++);
|
|
*res++=val;
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
Validate password for MySQL 4.1 password handling.
|
|
|
|
SYNOPSIS
|
|
validate_password()
|
|
password IN Encrypted Scramble which we got from the client
|
|
message IN Original scramble which we have sent to the client before
|
|
salt IN Password in the salted form to match to
|
|
|
|
RETURN
|
|
0 for correct password
|
|
!0 for invalid password
|
|
*/
|
|
|
|
my_bool validate_password(const char* password, const char* message, ulong* salt)
|
|
{
|
|
char buffer[SCRAMBLE41_LENGTH]; /* Used for password validation */
|
|
char tmpsalt[8]; /* Temporary value to convert salt to string form */
|
|
int i;
|
|
ulong salt_candidate[6]; /* Computed candidate salt */
|
|
|
|
/* Now we shall get stage1 encrypted password in buffer*/
|
|
password_crypt(password,buffer,message,SCRAMBLE41_LENGTH);
|
|
|
|
/* For compatibility reasons we use ulong to store salt while we need char */
|
|
sprintf(tmpsalt,"%04x",(unsigned short)salt[0]);
|
|
|
|
password_hash_stage2(buffer,tmpsalt);
|
|
/* Convert password to salt to compare */
|
|
get_salt_from_bin_password(salt_candidate,buffer,salt[0]);
|
|
|
|
/* Now we shall get exactly the same password as we have stored for user */
|
|
for(i=1;i<6;i++)
|
|
if (salt[i]!=salt_candidate[i]) return 1;
|
|
/* Or password correct*/
|
|
return 0;
|
|
}
|
|
|
|
|
|
/*
|
|
Get length of password string which is stored in mysql.user table
|
|
|
|
SYNOPSIS
|
|
get_password_length()
|
|
force_old_scramble IN If we wish to use pre 4.1 scramble format
|
|
|
|
RETURN
|
|
password length >0
|
|
*/
|
|
|
|
inline int get_password_length(my_bool force_old_scramble)
|
|
{
|
|
if (force_old_scramble)
|
|
return 16;
|
|
else return SHA1_HASH_SIZE*2+4+1;
|
|
}
|
|
|
|
|
|
/*
|
|
Get version of the password based on mysql.user password string
|
|
|
|
SYNOPSIS
|
|
get_password_version()
|
|
password IN Password string as stored in mysql.user
|
|
|
|
RETURN
|
|
0 for pre 4.1 passwords
|
|
!0 password version char for newer passwords
|
|
*/
|
|
|
|
inline char get_password_version(const char* password)
|
|
{
|
|
if (password==NULL) return 0;
|
|
if (password[0]==PVERSION41_CHAR) return PVERSION41_CHAR;
|
|
return 0;
|
|
}
|
|
|
|
|
|
/*
|
|
Get integer value of Hex character
|
|
|
|
SYNOPSIS
|
|
char_val()
|
|
X IN Character to find value for
|
|
|
|
RETURN
|
|
Appropriate integer value
|
|
*/
|
|
|
|
|
|
|
|
inline uint char_val(char X)
|
|
{
|
|
return (uint) (X >= '0' && X <= '9' ? X-'0' :
|
|
X >= 'A' && X <= 'Z' ? X-'A'+10 :
|
|
X-'a'+10);
|
|
}
|
|
|
|
|
|
/*
|
|
Get Binary salt from password as in mysql.user format
|
|
|
|
SYNOPSIS
|
|
get_salt_from_password()
|
|
res OUT Store binary salt here
|
|
password IN Password string as stored in mysql.user
|
|
|
|
RETURN
|
|
none
|
|
|
|
NOTE
|
|
This function does not have length check for passwords. It will just crash
|
|
Password hashes in old format must have length divisible by 8
|
|
*/
|
|
|
|
void get_salt_from_password(ulong *res,const char *password)
|
|
{
|
|
bzero(res,6*sizeof(res[0]));
|
|
if (password) /* zero salt corresponds to empty password */
|
|
{
|
|
if (password[0]==PVERSION41_CHAR) /* if new password */
|
|
{
|
|
uint val=0;
|
|
uint i;
|
|
password++; /* skip version identifier */
|
|
|
|
/*get hashing salt from password and store in in the start of array */
|
|
for (i=0 ; i < 4 ; i++)
|
|
val=(val << 4)+char_val(*password++);
|
|
*res++=val;
|
|
}
|
|
/* We process old passwords the same way as new ones in other case */
|
|
#ifdef EXTRA_DEBUG
|
|
if (strlen(password)%8!=0)
|
|
fprintf(stderr,"Warning: Incorrect password length for salting: %d\n",
|
|
strlen(password));
|
|
#endif
|
|
while (*password)
|
|
{
|
|
ulong val=0;
|
|
uint i;
|
|
for (i=0 ; i < 8 ; i++)
|
|
val=(val << 4)+char_val(*password++);
|
|
*res++=val;
|
|
}
|
|
}
|
|
return;
|
|
}
|
|
|
|
|
|
/*
|
|
Get string version as stored in mysql.user from salt form
|
|
|
|
SYNOPSIS
|
|
make_password_from_salt()
|
|
to OUT Store resulting string password here
|
|
hash_res IN Password in salt format
|
|
password_version
|
|
IN According to which version salt should be treated
|
|
|
|
RETURN
|
|
none
|
|
*/
|
|
|
|
void make_password_from_salt(char *to, ulong *hash_res,uint8 password_version)
|
|
{
|
|
if (!password_version) /* Handling of old passwords. */
|
|
sprintf(to,"%08lx%08lx",hash_res[0],hash_res[1]);
|
|
else
|
|
if (password_version==PVERSION41_CHAR)
|
|
sprintf(to,"%c%04x%08lx%08lx%08lx%08lx%08lx",PVERSION41_CHAR,(unsigned short)hash_res[0],hash_res[1],
|
|
hash_res[2],hash_res[3],hash_res[4],hash_res[5]);
|
|
else /* Just use empty password if we can't handle it. This should not happen */
|
|
to[0]='\0';
|
|
}
|
|
|
|
|
|
/*
|
|
Convert password in salted form to binary string password and hash-salt
|
|
For old password this involes one more hashing
|
|
|
|
SYNOPSIS
|
|
get_hash_and_password()
|
|
salt IN Salt to convert from
|
|
pversion IN Password version to use
|
|
hash OUT Store zero ended hash here
|
|
bin_password OUT Store binary password here (no zero at the end)
|
|
|
|
RETURN
|
|
0 for pre 4.1 passwords
|
|
!0 password version char for newer passwords
|
|
*/
|
|
|
|
void get_hash_and_password(ulong* salt, uint8 pversion, char* hash, unsigned char* bin_password)
|
|
{
|
|
int t;
|
|
ulong* salt_end;
|
|
ulong val;
|
|
SHA1_CONTEXT context;
|
|
unsigned char* bp; /* Binary password loop pointer */
|
|
|
|
if (pversion) /* New password version assumed */
|
|
{
|
|
salt_end=salt+6;
|
|
sprintf(hash,"%04x",(unsigned short)salt[0]);
|
|
salt++; /* position to the second element */
|
|
while (salt<salt_end) /* Iterate over these elements*/
|
|
{
|
|
val=*salt;
|
|
for(t=3;t>=0;t--)
|
|
{
|
|
bin_password[t]=val%256;
|
|
val>>=8; /* Scroll 8 bits to get next part*/
|
|
}
|
|
bin_password+=4; /* Get to next 4 chars*/
|
|
salt++;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/* Use zero starting hash as an indication of old password */
|
|
hash[0]=0;
|
|
salt_end=salt+2;
|
|
bp=bin_password;
|
|
/* Encode salt using SHA1 here */
|
|
sha1_reset(&context);
|
|
while (salt<salt_end) /* Iterate over these elements*/
|
|
{
|
|
val=*salt;
|
|
for(t=3;t>=0;t--)
|
|
{
|
|
bp[t]=val%256;
|
|
|
|
val>>=8; /* Scroll 8 bits to get next part*/
|
|
}
|
|
bp+=4; /* Get to next 4 chars*/
|
|
salt++;
|
|
}
|
|
/* Use 8 bytes of binary password for hash */
|
|
sha1_input(&context,(uint8*)bin_password,8);
|
|
sha1_result(&context,(uint8*)bin_password);
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
Create key from old password to decode scramble
|
|
Used in 4.1 authentication with passwords stored old way
|
|
|
|
SYNOPSIS
|
|
create_key_from_old_password()
|
|
passwd IN Password used for key generation
|
|
key OUT Created 20 bytes key
|
|
|
|
RETURN
|
|
None
|
|
*/
|
|
|
|
|
|
void create_key_from_old_password(const char* passwd, char* key)
|
|
{
|
|
char buffer[20]; /* Buffer for various needs */
|
|
ulong salt[6]; /* Salt (large for safety) */
|
|
/* At first hash password to the string stored in password */
|
|
make_scrambled_password(buffer,passwd,1,(struct rand_struct *)NULL);
|
|
/* Now convert it to the salt form */
|
|
get_salt_from_password(salt,buffer);
|
|
/* Finally get hash and bin password from salt */
|
|
get_hash_and_password(salt,0,buffer,(unsigned char*) key);
|
|
}
|
|
|
|
|
|
/*
|
|
Scramble string with password
|
|
Used at pre 4.1 authentication phase.
|
|
|
|
SYNOPSIS
|
|
scramble()
|
|
to OUT Store scrambled message here
|
|
message IN Message to scramble
|
|
password IN Password to use while scrambling
|
|
old_ver IN Forse old version random number generator
|
|
|
|
RETURN
|
|
End of scrambled string
|
|
*/
|
|
|
|
char *scramble(char *to,const char *message,const char *password,
|
|
my_bool old_ver)
|
|
{
|
|
struct rand_struct rand_st;
|
|
ulong hash_pass[2],hash_message[2];
|
|
char message_buffer[9]; /* Real message buffer */
|
|
char* msg=message_buffer;
|
|
|
|
/* We use special message buffer now as new server can provide longer hash */
|
|
|
|
memcpy(message_buffer,message,8);
|
|
message_buffer[8]=0;
|
|
|
|
if (password && password[0])
|
|
{
|
|
char *to_start=to;
|
|
hash_password(hash_pass,password);
|
|
hash_password(hash_message,message_buffer);
|
|
if (old_ver)
|
|
old_randominit(&rand_st,hash_pass[0] ^ hash_message[0]);
|
|
else
|
|
randominit(&rand_st,hash_pass[0] ^ hash_message[0],
|
|
hash_pass[1] ^ hash_message[1]);
|
|
while (*msg++)
|
|
*to++= (char) (floor(rnd(&rand_st)*31)+64);
|
|
if (!old_ver)
|
|
{ /* Make it harder to break */
|
|
char extra=(char) (floor(rnd(&rand_st)*31));
|
|
while (to_start != to)
|
|
*(to_start++)^=extra;
|
|
}
|
|
}
|
|
*to=0;
|
|
return to;
|
|
}
|
|
|
|
|
|
/*
|
|
Check scrambled message
|
|
Used for pre 4.1 password handling
|
|
|
|
SYNOPSIS
|
|
scramble()
|
|
scrambled IN Scrambled message to check
|
|
message IN Original message which was scramble
|
|
hash_pass IN Password which should be used for scrambling
|
|
old_ver IN Forse old version random number generator
|
|
|
|
RETURN
|
|
0 Password correct
|
|
!0 Password invalid
|
|
*/
|
|
|
|
my_bool check_scramble(const char *scrambled, const char *message,
|
|
ulong *hash_pass, my_bool old_ver)
|
|
{
|
|
struct rand_struct rand_st;
|
|
ulong hash_message[2];
|
|
char buff[16],*to,extra; /* Big enough for check */
|
|
const char *pos;
|
|
char message_buffer[9]; /* Copy of message */
|
|
|
|
memcpy(message_buffer,message,8); /* Old auth uses 8 bytes at maximum */
|
|
message_buffer[8]=0;
|
|
|
|
hash_password(hash_message,message_buffer);
|
|
if (old_ver)
|
|
old_randominit(&rand_st,hash_pass[0] ^ hash_message[0]);
|
|
else
|
|
randominit(&rand_st,hash_pass[0] ^ hash_message[0],
|
|
hash_pass[1] ^ hash_message[1]);
|
|
to=buff;
|
|
for (pos=scrambled ; *pos ; pos++)
|
|
*to++=(char) (floor(rnd(&rand_st)*31)+64);
|
|
if (old_ver)
|
|
extra=0;
|
|
else
|
|
extra=(char) (floor(rnd(&rand_st)*31));
|
|
to=buff;
|
|
while (*scrambled)
|
|
{
|
|
if (*scrambled++ != (char) (*to++ ^ extra))
|
|
return 1; /* Wrong password */
|
|
}
|
|
return 0;
|
|
}
|