home *** CD-ROM | disk | FTP | other *** search
/ Chip 2001 January / Chip_2001-01_cd1.bin / tema / mysql / mysql-3.23.28g-win-source.exe / sql / password.c < prev    next >
C/C++ Source or Header  |  2000-08-31  |  6KB  |  192 lines

  1. /* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
  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 as published by
  5.    the Free Software Foundation; either version 2 of the License, or
  6.    (at your option) any later version.
  7.    
  8.    This program is distributed in the hope that it will be useful,
  9.    but WITHOUT ANY WARRANTY; without even the implied warranty of
  10.    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  11.    GNU General Public License for more details.
  12.    
  13.    You should have received a copy of the GNU General Public License
  14.    along with this program; if not, write to the Free Software
  15.    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
  16.  
  17. /* password checking routines */
  18. /*****************************************************************************
  19.   The main idea is that no password are sent between client & server on
  20.   connection and that no password are saved in mysql in a decodable form.
  21.  
  22.   On connection a random string is generated and sent to the client.
  23.   The client generates a new string with a random generator inited with
  24.   the hash values from the password and the sent string.
  25.   This 'check' string is sent to the server where it is compared with
  26.   a string generated from the stored hash_value of the password and the
  27.   random string.
  28.  
  29.   The password is saved (in user.password) by using the PASSWORD() function in
  30.   mysql.
  31.  
  32.   Example:
  33.     update user set password=PASSWORD("hello") where user="test"
  34.   This saves a hashed number as a string in the password field.
  35. *****************************************************************************/
  36.  
  37. #include <global.h>
  38. #include <my_sys.h>
  39. #include <m_string.h>
  40. #include "mysql.h"
  41.  
  42.  
  43. void randominit(struct rand_struct *rand_st,ulong seed1, ulong seed2)
  44. {                        /* For mysql 3.21.# */
  45. #ifdef HAVE_purify
  46.   bzero((char*) rand_st,sizeof(*rand_st));        /* Avoid UMC varnings */
  47. #endif
  48.   rand_st->max_value= 0x3FFFFFFFL;
  49.   rand_st->max_value_dbl=(double) rand_st->max_value;
  50.   rand_st->seed1=seed1%rand_st->max_value ;
  51.   rand_st->seed2=seed2%rand_st->max_value;
  52. }
  53.  
  54. static void old_randominit(struct rand_struct *rand_st,ulong seed1)
  55. {                        /* For mysql 3.20.# */
  56.   rand_st->max_value= 0x01FFFFFFL;
  57.   rand_st->max_value_dbl=(double) rand_st->max_value;
  58.   seed1%=rand_st->max_value;
  59.   rand_st->seed1=seed1 ; rand_st->seed2=seed1/2;
  60. }
  61.  
  62. double rnd(struct rand_struct *rand_st)
  63. {
  64.   rand_st->seed1=(rand_st->seed1*3+rand_st->seed2) % rand_st->max_value;
  65.   rand_st->seed2=(rand_st->seed1+rand_st->seed2+33) % rand_st->max_value;
  66.   return (((double) rand_st->seed1)/rand_st->max_value_dbl);
  67. }
  68.  
  69. void hash_password(ulong *result, const char *password)
  70. {
  71.   register ulong nr=1345345333L, add=7, nr2=0x12345671L;
  72.   ulong tmp;
  73.   for (; *password ; password++)
  74.   {
  75.     if (*password == ' ' || *password == '\t')
  76.       continue;            /* skipp space in password */
  77.     tmp= (ulong) (uchar) *password;
  78.     nr^= (((nr & 63)+add)*tmp)+ (nr << 8);
  79.     nr2+=(nr2 << 8) ^ nr;
  80.     add+=tmp;
  81.   }
  82.   result[0]=nr & (((ulong) 1L << 31) -1L); /* Don't use sign bit (str2int) */;
  83.   result[1]=nr2 & (((ulong) 1L << 31) -1L);
  84.   return;
  85. }
  86.  
  87. void make_scrambled_password(char *to,const char *password)
  88. {
  89.   ulong hash_res[2];
  90.   hash_password(hash_res,password);
  91.   sprintf(to,"%08lx%08lx",hash_res[0],hash_res[1]);
  92. }
  93.  
  94. static inline uint char_val(char X)
  95. {
  96.   return (uint) (X >= '0' && X <= '9' ? X-'0' :
  97.          X >= 'A' && X <= 'Z' ? X-'A'+10 :
  98.          X-'a'+10);
  99. }
  100.  
  101. /*
  102. ** This code assumes that len(password) is divideable with 8 and that
  103. ** res is big enough (2 in mysql)
  104. */
  105.  
  106. void get_salt_from_password(ulong *res,const char *password)
  107. {
  108.   res[0]=res[1]=0;
  109.   if (password)
  110.   {
  111.     while (*password)
  112.     {
  113.       ulong val=0;
  114.       uint i;
  115.       for (i=0 ; i < 8 ; i++)
  116.     val=(val << 4)+char_val(*password++);
  117.       *res++=val;
  118.     }
  119.   }
  120.   return;
  121. }
  122.  
  123. void make_password_from_salt(char *to, ulong *hash_res)
  124. {
  125.   sprintf(to,"%08lx%08lx",hash_res[0],hash_res[1]);
  126. }
  127.  
  128.  
  129. /*
  130.  * Genererate a new message based on message and password
  131.  * The same thing is done in client and server and the results are checked.
  132.  */
  133.  
  134. char *scramble(char *to,const char *message,const char *password,
  135.            my_bool old_ver)
  136. {
  137.   struct rand_struct rand_st;
  138.   ulong hash_pass[2],hash_message[2];
  139.   if (password && password[0])
  140.   {
  141.     char *to_start=to;
  142.     hash_password(hash_pass,password);
  143.     hash_password(hash_message,message);
  144.     if (old_ver)
  145.       old_randominit(&rand_st,hash_pass[0] ^ hash_message[0]);
  146.     else
  147.       randominit(&rand_st,hash_pass[0] ^ hash_message[0],
  148.          hash_pass[1] ^ hash_message[1]);
  149.     while (*message++)
  150.       *to++= (char) (floor(rnd(&rand_st)*31)+64);
  151.     if (!old_ver)
  152.     {                        /* Make it harder to break */
  153.       char extra=(char) (floor(rnd(&rand_st)*31));
  154.       while (to_start != to)
  155.     *(to_start++)^=extra;
  156.     }
  157.   }
  158.   *to=0;
  159.   return to;
  160. }
  161.  
  162.  
  163. my_bool check_scramble(const char *scrambled, const char *message,
  164.                ulong *hash_pass, my_bool old_ver)
  165. {
  166.   struct rand_struct rand_st;
  167.   ulong hash_message[2];
  168.   char buff[16],*to,extra;            /* Big enough for check */
  169.   const char *pos;
  170.  
  171.   hash_password(hash_message,message);
  172.   if (old_ver)
  173.     old_randominit(&rand_st,hash_pass[0] ^ hash_message[0]);
  174.   else
  175.     randominit(&rand_st,hash_pass[0] ^ hash_message[0],
  176.            hash_pass[1] ^ hash_message[1]);
  177.   to=buff;
  178.   for (pos=scrambled ; *pos ; pos++)
  179.     *to++=(char) (floor(rnd(&rand_st)*31)+64);
  180.   if (old_ver)
  181.     extra=0;
  182.   else
  183.     extra=(char) (floor(rnd(&rand_st)*31));
  184.   to=buff;
  185.   while (*scrambled)
  186.   {
  187.     if (*scrambled++ != (char) (*to++ ^ extra))
  188.       return 1;                    /* Wrong password */
  189.   }
  190.   return 0;
  191. }
  192.