password.c 19.6 KB
Newer Older
unknown's avatar
unknown committed
1
/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
unknown's avatar
unknown committed
2

unknown's avatar
unknown committed
3 4 5 6
   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.
unknown's avatar
unknown committed
7

unknown's avatar
unknown committed
8 9 10 11
   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.
unknown's avatar
unknown committed
12

unknown's avatar
unknown committed
13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34
   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.
35 36


37
  New in MySQL 4.1 authentication works even more secure way.
38
  At the first step client sends user name to the sever, and password if
39 40
  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
41 42
  password stage2 hash stored in the password  database as well as salt, needed
  for client to build stage2 password to decrypt scramble.
43 44
  Client decrypts the scramble and encrypts it once again with stage1 password.
  This information is sent to server.
45
  Server decrypts the scramble to get stage1 password and hashes it to get
46
  stage2 hash. This hash is when compared to hash stored in the database.
47 48 49

  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
50
  to break into MySQL.
unknown's avatar
unknown committed
51 52

  New Password handling functions by Peter Zaitsev
53 54


unknown's avatar
unknown committed
55 56
*****************************************************************************/

unknown's avatar
unknown committed
57
#include <my_global.h>
unknown's avatar
unknown committed
58 59
#include <my_sys.h>
#include <m_string.h>
60
#include <sha1.h>
unknown's avatar
unknown committed
61 62 63
#include "mysql.h"


64 65 66 67

/* Character to use as version identifier for version 4.1 */
#define PVERSION41_CHAR '*'

68
/* Scramble length for new password version */
69 70


71 72
/*
  New (MySQL 3.21+) random generation structure initialization
73

74 75 76 77 78
  SYNOPSIS
    randominit()
    rand_st    OUT  Structure to initialize
    seed1      IN   First initialization parameter
    seed2      IN   Second initialization parameter
79

80 81 82
  RETURN
    none
*/
83

unknown's avatar
unknown committed
84 85 86
void randominit(struct rand_struct *rand_st,ulong seed1, ulong seed2)
{						/* For mysql 3.21.# */
#ifdef HAVE_purify
87
  bzero((char*) rand_st,sizeof(*rand_st));	/* Avoid UMC varnings */
unknown's avatar
unknown committed
88 89 90 91 92 93 94
#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;
}

95 96 97

/*
  Old (MySQL 3.20) random generation structure initialization
98

99 100 101 102
  SYNOPSIS
    old_randominit()
    rand_st    OUT  Structure to initialize
    seed1      IN   First initialization parameter
103

104 105 106 107
  RETURN
    none
*/

unknown's avatar
unknown committed
108 109 110 111 112 113 114 115
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;
}

116 117 118

/*
  Generate Random number
119

120
  SYNOPSIS
unknown's avatar
unknown committed
121
    my_rnd()
122
    rand_st    INOUT  Structure used for number generation
123

124 125 126 127
  RETURN
    Generated pseudo random number
*/

128
double my_rnd(struct rand_struct *rand_st)
unknown's avatar
unknown committed
129 130 131 132 133 134
{
  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);
}

135 136 137 138

/*
  Generate String of printable random characters of requested length
  String will not be zero terminated.
139

140 141
  SYNOPSIS
    create_random_string()
142
    length     IN     Lenght of
143 144
    rand_st    INOUT  Structure used for number generation
    target     OUT    Buffer for generation
145

146 147 148 149
  RETURN
    none
*/

150
void create_random_string(int length,struct rand_struct *rand_st,char *target)
151
{
152
  char *end=target+length;
153
  /* Use pointer arithmetics as it is faster way to do so. */
unknown's avatar
unknown committed
154
  for (; target<end ; target++)
unknown's avatar
unknown committed
155
    *target= (char) (my_rnd(rand_st)*94+33);
156 157 158 159 160 161
}


/*
  Encrypt/Decrypt function used for password encryption in authentication
  Simple XOR is used here but it is OK as we crypt random strings
162

163 164 165 166
  SYNOPSIS
    password_crypt()
    from     IN     Data for encryption
    to       OUT    Encrypt data to the buffer (may be the same)
167
    password IN     Password used for encryption (same length)
168
    length   IN     Length of data to encrypt
169

170 171 172 173
  RETURN
    none
*/

174
void password_crypt(const char *from,char *to, const char *password,int length)
175 176
{
 const char *from_end=from+length;
177

unknown's avatar
unknown committed
178 179
 while (from < from_end)
   *to++= *(from++) ^* (password++);
180 181 182 183 184 185
}


/*
  Generate binary hash from raw text password
  Used for Pre-4.1 Password handling
186

187 188 189 190
  SYNOPSIS
    hash_pasword()
    result   OUT    Store hash in this location
    password IN     Plain text password to build hash
191

192 193 194 195
  RETURN
    none
*/

unknown's avatar
unknown committed
196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213
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;
}

214

215
/*
216
  Stage one password hashing.
217
  Used in MySQL 4.1 password handling
218

219 220 221 222
  SYNOPSIS
    password_hash_stage1()
    to       OUT    Store stage one hash to this location
    password IN     Plain text password to build hash
223

224 225 226
  RETURN
    none
*/
227

228
void password_hash_stage1(char *to, const char *password)
229
{
230
  SHA1_CONTEXT context;
231 232 233
  sha1_reset(&context);
  for (; *password ; password++)
  {
234
    if (*password == ' ' || *password == '\t')
235
      continue;/* skip space in password */
unknown's avatar
unknown committed
236
    sha1_input(&context,(uint8*) &password[0],1);
237
  }
238
  sha1_result(&context,(uint8*)to);
239
}
240 241


242
/*
243
  Stage two password hashing.
244
  Used in MySQL 4.1 password handling
245

246 247 248 249
  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
250

251 252 253 254
  RETURN
    none
*/

255
void password_hash_stage2(char *to, const char *salt)
256
{
257
  SHA1_CONTEXT context;
258
  sha1_reset(&context);
unknown's avatar
unknown committed
259 260 261
  sha1_input(&context,(uint8*) salt, 4);
  sha1_input(&context,(uint8*) to, SHA1_HASH_SIZE);
  sha1_result(&context,(uint8*) to);
262 263 264 265 266
}


/*
  Create password to be stored in user database from raw string
267 268
  Handles both MySQL 4.1 and Pre-MySQL 4.1 passwords

269 270
  SYNOPSIS
    make_scramble_password()
271
    to       OUT   Store scrambled password here
272
    password IN    Raw string password
273
    force_old_scramle
274
             IN    Force generation of old scramble variant
275
    rand_st  INOUT Structure for temporary number generation.
276 277 278 279
  RETURN
    none
*/

unknown's avatar
unknown committed
280 281 282
void make_scrambled_password(char *to,const char *password,
                             my_bool force_old_scramble,
                             struct rand_struct *rand_st)
283
{
284 285
  ulong hash_res[2];   /* Used for pre 4.1 password hashing */
  unsigned short salt; /* Salt for 4.1 version password */
286
  uint8 digest[SHA1_HASH_SIZE];
287
  if (force_old_scramble) /* Pre 4.1 password encryption */
288 289 290 291
  {
    hash_password(hash_res,password);
    sprintf(to,"%08lx%08lx",hash_res[0],hash_res[1]);
  }
292
  else /* New password 4.1 password scrambling */
293 294
  {
    to[0]=PVERSION41_CHAR; /* New passwords have version prefix */
unknown's avatar
unknown committed
295
   /* Rnd returns number from 0 to 1 so this would be good salt generation.*/
unknown's avatar
unknown committed
296
    salt=(unsigned short) (my_rnd(rand_st)*65535+1);
297
    /* Use only 2 first bytes from it */
298 299
    sprintf(to+1,"%04x",salt);
    /* First hasing is done without salt */
unknown's avatar
unknown committed
300
    password_hash_stage1((char*) digest, password);
301
    /* Second stage is done with salt */
unknown's avatar
unknown committed
302
    password_hash_stage2((char*) digest,(char*)to+1),
303
    /* Print resulting hash into the password*/
304
    sprintf(to+5,
305
      "%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x",
306 307
      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],
308
      digest[14],digest[15],digest[16],digest[17],digest[18],digest[19]);
309 310 311
  }
}

312 313

/*
314
  Convert password from binary string form to salt form
315
  Used for MySQL 4.1 password handling
316

317 318 319 320 321
  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
322

323 324 325 326 327 328
  RETURN
    none
*/

void get_salt_from_bin_password(ulong *res,unsigned char *password,ulong salt)
{
329
  unsigned char *password_end=password+SCRAMBLE41_LENGTH;
330 331
  *res=salt;
  res++;
332

333 334 335 336 337 338 339 340
  /* 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;
341
  }
342 343 344 345
}


/*
346 347
  Validate password for MySQL 4.1 password handling.

348 349 350 351
  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
352 353
    salt     IN   Password in the salted form to match to

354 355 356 357 358
  RETURN
    0 for correct password
   !0 for invalid password
*/

359 360
my_bool validate_password(const char *password, const char *message,
                          ulong *salt)
361 362 363 364
{
  char buffer[SCRAMBLE41_LENGTH]; /* Used for password validation */
  char tmpsalt[8]; /* Temporary value to convert salt to string form */
  ulong salt_candidate[6]; /* Computed candidate salt */
365 366
  ulong *sc=salt_candidate; /* we need to be able to increment */
  ulong *salt_end;
367

368 369
  /* Now we shall get stage1 encrypted password in buffer*/
  password_crypt(password,buffer,message,SCRAMBLE41_LENGTH);
370

371 372
  /* For compatibility reasons we use ulong to store salt while we need char */
  sprintf(tmpsalt,"%04x",(unsigned short)salt[0]);
373

374 375
  password_hash_stage2(buffer,tmpsalt);
  /* Convert password to salt to compare */
unknown's avatar
unknown committed
376
  get_salt_from_bin_password(salt_candidate,(uchar*) buffer,salt[0]);
377 378

  /* Now we shall get exactly the same password as we have stored for user  */
unknown's avatar
unknown committed
379 380 381
  for (salt_end=salt+5 ; salt < salt_end; )
    if (*++salt != *++sc)
      return 1;
382 383

  /* Or password correct*/
384
  return 0;
385
}
386 387 388 389


/*
  Get length of password string which is stored in mysql.user table
390

391 392
  SYNOPSIS
    get_password_length()
393 394
    force_old_scramble  IN  If we wish to use pre 4.1 scramble format

395 396 397 398
  RETURN
    password length >0
*/

unknown's avatar
unknown committed
399
int get_password_length(my_bool force_old_scramble)
unknown's avatar
unknown committed
400
{
unknown's avatar
unknown committed
401
  return (force_old_scramble) ? 16 : SHA1_HASH_SIZE*2+4+1;
unknown's avatar
unknown committed
402 403
}

404 405 406

/*
  Get version of the password based on mysql.user password string
407

408 409 410
  SYNOPSIS
    get_password_version()
    password IN   Password string as stored in mysql.user
411

412 413 414 415 416
  RETURN
    0 for pre 4.1 passwords
   !0 password version char for newer passwords
*/

417
char get_password_version(const char *password)
418
{
419
  if (password==NULL) return 0;
420 421 422 423
  if (password[0]==PVERSION41_CHAR) return PVERSION41_CHAR;
  return 0;
}

424

425
/*
426 427
  Get integer value of Hex character

428 429 430
  SYNOPSIS
    char_val()
    X        IN   Character to find value for
431

432 433 434 435 436 437
  RETURN
    Appropriate integer value
*/



438
static inline unsigned int char_val(char X)
unknown's avatar
unknown committed
439 440 441 442 443 444
{
  return (uint) (X >= '0' && X <= '9' ? X-'0' :
		 X >= 'A' && X <= 'Z' ? X-'A'+10 :
		 X-'a'+10);
}

445

unknown's avatar
unknown committed
446
/*
447
  Get Binary salt from password as in mysql.user format
448

449 450 451 452
  SYNOPSIS
    get_salt_from_password()
    res      OUT  Store binary salt here
    password IN   Password string as stored in mysql.user
453

454 455
  RETURN
    none
456

457 458
  NOTE
    This function does not have length check for passwords. It will just crash
459
    Password hashes in old format must have length divisible by 8
unknown's avatar
unknown committed
460 461 462 463
*/

void get_salt_from_password(ulong *res,const char *password)
{
464
  if (password) /* zero salt corresponds to empty password */
unknown's avatar
unknown committed
465
  {
466
    if (password[0]==PVERSION41_CHAR) /* if new password */
467 468 469
    {
      uint val=0;
      uint i;
470
      password++; /* skip version identifier */
471

472
      /*get hashing salt from password and store in in the start of array */
473 474
      for (i=0 ; i < 4 ; i++)
	val=(val << 4)+char_val(*password++);
475
      *res++=val;
476
    }
477 478 479 480
     /* 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",
481 482
              strlen(password));
#endif
unknown's avatar
unknown committed
483 484 485 486 487 488 489
    while (*password)
    {
      ulong val=0;
      uint i;
      for (i=0 ; i < 8 ; i++)
	val=(val << 4)+char_val(*password++);
      *res++=val;
490
    }
unknown's avatar
unknown committed
491 492 493 494
  }
  return;
}

495 496 497

/*
  Get string version as stored in mysql.user from salt form
498

499 500 501 502 503 504
  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
505

506 507 508 509
  RETURN
    none
*/

510
void make_password_from_salt(char *to, ulong *hash_res,uint8 password_version)
unknown's avatar
unknown committed
511
{
512
  if (!password_version) /* Handling of old passwords. */
513 514 515
    sprintf(to,"%08lx%08lx",hash_res[0],hash_res[1]);
  else
    if (password_version==PVERSION41_CHAR)
516
      sprintf(to,"%c%04x%08lx%08lx%08lx%08lx%08lx",PVERSION41_CHAR,(unsigned short)hash_res[0],hash_res[1],
517
              hash_res[2],hash_res[3],hash_res[4],hash_res[5]);
518
    else /* Just use empty password if we can't handle it. This should not happen */
519
      to[0]='\0';
unknown's avatar
unknown committed
520 521 522 523
}


/*
524 525
  Convert password in salted form to binary string password and hash-salt
  For old password this involes one more hashing
526

527 528 529 530
  SYNOPSIS
    get_hash_and_password()
    salt         IN  Salt to convert from
    pversion     IN  Password version to use
531
    hash         OUT Store zero ended hash here
532
    bin_password OUT Store binary password here (no zero at the end)
533

534 535 536 537
  RETURN
    0 for pre 4.1 passwords
   !0 password version char for newer passwords
*/
unknown's avatar
unknown committed
538

539 540
void get_hash_and_password(ulong *salt, uint8 pversion, char *hash,
			   unsigned char *bin_password)
541 542 543 544
{
  int t;
  ulong* salt_end;
  ulong val;
545 546
  SHA1_CONTEXT context;

547
  if (pversion)				/* New password version assumed */
548
  {
unknown's avatar
unknown committed
549
    salt_end=salt+5;
550
    sprintf(hash,"%04x",(unsigned short)salt[0]);
551
    while (salt<salt_end)
552
    {
unknown's avatar
unknown committed
553 554
      val=*(++salt);
      for (t=3; t>=0; t--)
555
      {
unknown's avatar
unknown committed
556
        bin_password[t]= (char) (val & 255);
557
        val>>=8;			/* Scroll 8 bits to get next part*/
558
      }
559
      bin_password+=4;			/* Get to next 4 chars*/
560 561
    }
  }
562
  else
563
  {
564 565
    unsigned char *bp= bin_password;	/* Binary password loop pointer */

566
    /* Use zero starting hash as an indication of old password */
567
    hash[0]=0;
568 569 570
    salt_end=salt+2;
    /* Encode salt using SHA1 here */
    sha1_reset(&context);
571
    while (salt<salt_end)		/* Iterate over these elements*/
572
    {
573
      val= *salt;
unknown's avatar
unknown committed
574
      for (t=3;t>=0;t--)
575
      {
unknown's avatar
unknown committed
576
        bp[t]= (uchar) (val & 255);
577
        val>>=8;			/* Scroll 8 bits to get next part*/
578
      }
579
      bp+= 4;				/* Get to next 4 chars*/
580 581 582
      salt++;
    }
    /* Use 8 bytes of binary password for hash */
583 584 585
    sha1_input(&context,(uint8*)bin_password,8);
    sha1_result(&context,(uint8*)bin_password);
  }
586 587 588 589
}


/*
590
  Create key from old password to decode scramble
591
  Used in 4.1 authentication with passwords stored old way
592

593 594 595
  SYNOPSIS
    create_key_from_old_password()
    passwd    IN  Password used for key generation
596 597
    key       OUT Created 20 bytes key

598 599 600 601 602
  RETURN
    None
*/


603
void create_key_from_old_password(const char *passwd, char *key)
604
{
unknown's avatar
unknown committed
605
  char  buffer[SCRAMBLE41_LENGTH]; /* Buffer for various needs */
606 607 608 609 610 611 612 613 614
  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);
}

615

616
/*
617
  Scramble string with password
618
  Used at pre 4.1 authentication phase.
619

620 621 622 623 624 625
  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
626

627 628 629
  RETURN
    End of scrambled string
*/
630

unknown's avatar
unknown committed
631 632 633 634 635
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];
636
  char message_buffer[9]; /* Real message buffer */
637
  char *msg=message_buffer;
638

639
  /* We use special message buffer now as new server can provide longer hash */
640

641 642
  memcpy(message_buffer,message,8);
  message_buffer[8]=0;
643

unknown's avatar
unknown committed
644 645 646 647
  if (password && password[0])
  {
    char *to_start=to;
    hash_password(hash_pass,password);
648
    hash_password(hash_message,message_buffer);
unknown's avatar
unknown committed
649 650 651 652 653
    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]);
654
    while (*msg++)
655
      *to++= (char) (floor(my_rnd(&rand_st)*31)+64);
unknown's avatar
unknown committed
656 657
    if (!old_ver)
    {						/* Make it harder to break */
658
      char extra=(char) (floor(my_rnd(&rand_st)*31));
unknown's avatar
unknown committed
659 660 661 662 663 664 665 666 667
      while (to_start != to)
	*(to_start++)^=extra;
    }
  }
  *to=0;
  return to;
}


668
/*
669
  Check scrambled message
670
  Used for pre 4.1 password handling
671

672 673 674 675 676 677
  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
678

679 680 681 682 683
  RETURN
    0  Password correct
   !0  Password invalid
*/

unknown's avatar
unknown committed
684 685 686 687 688
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];
unknown's avatar
unknown committed
689
  char buff[16],*to,extra;		   /* Big enough for check */
unknown's avatar
unknown committed
690
  const char *pos;
unknown's avatar
unknown committed
691 692 693 694 695 696 697 698 699 700 701 702 703 704
  char message_buffer[SCRAMBLE_LENGTH+1];  /* Copy of message */
  
  /* We need to copy the message as this function can be called for MySQL 4.1
     scramble which is not zero ended and can have zeroes inside
     We could just write zero to proper place in original message but
     this would make it harder to understand code for next generations
  */      

  memcpy(message_buffer,message,SCRAMBLE_LENGTH); /* Ignore the rest */
  message_buffer[SCRAMBLE_LENGTH]=0;
  
  /* Check if this exactly N bytes. Overwise this is something fishy */
  if (strlen(message_buffer)!=SCRAMBLE_LENGTH)
    return 1; /* Wrong password */
705

706
  hash_password(hash_message,message_buffer);
unknown's avatar
unknown committed
707 708 709 710 711 712 713
  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++)
714
    *to++=(char) (floor(my_rnd(&rand_st)*31)+64);
unknown's avatar
unknown committed
715 716 717
  if (old_ver)
    extra=0;
  else
718
    extra=(char) (floor(my_rnd(&rand_st)*31));
unknown's avatar
unknown committed
719 720 721 722 723 724 725 726
  to=buff;
  while (*scrambled)
  {
    if (*scrambled++ != (char) (*to++ ^ extra))
      return 1;					/* Wrong password */
  }
  return 0;
}