diff options
-rw-r--r-- | client/mysqladmin.c | 2 | ||||
-rw-r--r-- | include/mysql_com.h | 5 | ||||
-rw-r--r-- | libmysql/Makefile.shared | 2 | ||||
-rwxr-xr-x[-rw-r--r--] | libmysql/password.c | 191 | ||||
-rw-r--r-- | mysql-test/r/func_crypt.result | 6 | ||||
-rw-r--r-- | mysql-test/t/func_crypt.test | 2 | ||||
-rw-r--r-- | sql/item_create.cc | 7 | ||||
-rw-r--r-- | sql/item_create.h | 1 | ||||
-rw-r--r-- | sql/item_strfunc.cc | 18 | ||||
-rw-r--r-- | sql/item_strfunc.h | 18 | ||||
-rw-r--r-- | sql/lex.h | 1 | ||||
-rw-r--r-- | sql/password.c | 47 | ||||
-rw-r--r-- | sql/sql_acl.cc | 17 | ||||
-rw-r--r-- | sql/sql_yacc.yy | 4 |
14 files changed, 101 insertions, 220 deletions
diff --git a/client/mysqladmin.c b/client/mysqladmin.c index 01e36509c30..81e7e7c05de 100644 --- a/client/mysqladmin.c +++ b/client/mysqladmin.c @@ -731,7 +731,7 @@ static int execute_commands(MYSQL *mysql,int argc, char **argv) return 1; } if (argv[1][0]) - make_scrambled_password(crypted_pw,argv[1]); + make_scrambled_password(crypted_pw,argv[1],0); /* New passwords only */ else crypted_pw[0]=0; /* No password */ sprintf(buff,"set password='%s',sql_log_off=0",crypted_pw); diff --git a/include/mysql_com.h b/include/mysql_com.h index 5ed65e993d9..a529dbc127b 100644 --- a/include/mysql_com.h +++ b/include/mysql_com.h @@ -274,8 +274,9 @@ extern unsigned long net_buffer_length; void randominit(struct rand_struct *,unsigned long seed1, unsigned long seed2); double rnd(struct rand_struct *); -void make_scrambled_password(char *to,const char *password); -uint get_password_length(); +void make_scrambled_password(char *to,const char *password,my_bool force_old_scramble); +uint get_password_length(my_bool force_old_scramble); +uint8 get_password_version(const char* password); void get_salt_from_password(unsigned long *res,const char *password); void make_password_from_salt(char *to, unsigned long *hash_res); char *scramble(char *to,const char *message,const char *password, diff --git a/libmysql/Makefile.shared b/libmysql/Makefile.shared index 0f7cb713d54..76ec06c8c51 100644 --- a/libmysql/Makefile.shared +++ b/libmysql/Makefile.shared @@ -60,7 +60,7 @@ mysysobjects1 = my_init.lo my_static.lo my_malloc.lo my_realloc.lo \ my_compress.lo array.lo my_once.lo list.lo my_net.lo \ charset.lo hash.lo mf_iocache.lo \ mf_iocache2.lo my_seek.lo \ - my_pread.lo mf_cache.lo my_vsnprintf.lo md5.lo \ + my_pread.lo mf_cache.lo my_vsnprintf.lo md5.lo sha1.lo\ my_getopt.lo my_gethostbyname.lo my_port.lo sqlobjects = net.lo diff --git a/libmysql/password.c b/libmysql/password.c index 9b154603b98..e69de29bb2d 100644..100755 --- a/libmysql/password.c +++ b/libmysql/password.c @@ -1,191 +0,0 @@ -/* Copyright (C) 2000 MySQL 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. -*****************************************************************************/ - -#include <my_global.h> -#include <my_sys.h> -#include <m_string.h> -#include "mysql.h" - - -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; -} - -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; -} - -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); -} - -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; -} - -void make_scrambled_password(char *to,const char *password) -{ - ulong hash_res[2]; - hash_password(hash_res,password); - sprintf(to,"%08lx%08lx",hash_res[0],hash_res[1]); -} - -static inline uint char_val(char X) -{ - return (uint) (X >= '0' && X <= '9' ? X-'0' : - X >= 'A' && X <= 'Z' ? X-'A'+10 : - X-'a'+10); -} - -/* -** This code assumes that len(password) is divideable with 8 and that -** res is big enough (2 in mysql) -*/ - -void get_salt_from_password(ulong *res,const char *password) -{ - res[0]=res[1]=0; - if (password) - { - while (*password) - { - ulong val=0; - uint i; - for (i=0 ; i < 8 ; i++) - val=(val << 4)+char_val(*password++); - *res++=val; - } - } - return; -} - -void make_password_from_salt(char *to, ulong *hash_res) -{ - sprintf(to,"%08lx%08lx",hash_res[0],hash_res[1]); -} - - -/* - * Genererate a new message based on message and password - * The same thing is done in client and server and the results are checked. - */ - -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]; - if (password && password[0]) - { - char *to_start=to; - hash_password(hash_pass,password); - hash_password(hash_message,message); - 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 (*message++) - *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; -} - - -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; - - hash_password(hash_message,message); - 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; -} diff --git a/mysql-test/r/func_crypt.result b/mysql-test/r/func_crypt.result index cf464ec21b2..ad3a64ccd1d 100644 --- a/mysql-test/r/func_crypt.result +++ b/mysql-test/r/func_crypt.result @@ -1,6 +1,6 @@ select length(encrypt('foo', 'ff')) <> 0; length(encrypt('foo', 'ff')) <> 0 1 -select password('test'),length(encrypt('test')),encrypt('test','aa'); -password('test') length(encrypt('test')) encrypt('test','aa') -378b243e220ca493 13 aaqPiZY5xR5l. +select old_password('test'),length(password("1")),length(encrypt('test')),encrypt('test','aa'); +old_password('test') length(password("1")) length(encrypt('test')) encrypt('test','aa') +378b243e220ca493 45 13 aaqPiZY5xR5l. diff --git a/mysql-test/t/func_crypt.test b/mysql-test/t/func_crypt.test index f01504d3691..812bdade39f 100644 --- a/mysql-test/t/func_crypt.test +++ b/mysql-test/t/func_crypt.test @@ -1,3 +1,3 @@ select length(encrypt('foo', 'ff')) <> 0; --replace_result $1$aa$4OSUA5cjdx0RUQ08opV27/ aaqPiZY5xR5l. -select password('test'),length(encrypt('test')),encrypt('test','aa'); +select old_password('test'),length(password("1")),length(encrypt('test')),encrypt('test','aa'); diff --git a/sql/item_create.cc b/sql/item_create.cc index e4c9a160686..838396d9b15 100644 --- a/sql/item_create.cc +++ b/sql/item_create.cc @@ -52,6 +52,13 @@ Item *create_func_ord(Item* a) return new Item_func_ord(a); } +Item *create_func_old_password(Item* a) +{ + return new Item_func_old_password(a); +} + + + Item *create_func_asin(Item* a) { return new Item_func_asin(a); diff --git a/sql/item_create.h b/sql/item_create.h index 6d9cef04c13..937ea782273 100644 --- a/sql/item_create.h +++ b/sql/item_create.h @@ -66,6 +66,7 @@ Item *create_func_monthname(Item* a); Item *create_func_nullif(Item* a, Item *b); Item *create_func_oct(Item *); Item *create_func_ord(Item* a); +Item *create_func_old_password(Item* a); Item *create_func_period_add(Item* a, Item *b); Item *create_func_period_diff(Item* a, Item *b); Item *create_func_pi(void); diff --git a/sql/item_strfunc.cc b/sql/item_strfunc.cc index 24320d98576..198ab42558d 100644 --- a/sql/item_strfunc.cc +++ b/sql/item_strfunc.cc @@ -1273,11 +1273,25 @@ String *Item_func_password::val_str(String *str) return 0; if (res->length() == 0) return &empty_string; - make_scrambled_password(tmp_value,res->c_ptr()); - str->set(tmp_value,get_password_length(),res->charset()); + make_scrambled_password(tmp_value,res->c_ptr(),opt_old_passwords); + str->set(tmp_value,get_password_length(opt_old_passwords),res->charset()); return str; } +String *Item_func_old_password::val_str(String *str) +{ + String *res =args[0]->val_str(str); + if ((null_value=args[0]->null_value)) + return 0; + if (res->length() == 0) + return &empty_string; + make_scrambled_password(tmp_value,res->c_ptr(),1); + str->set(tmp_value,16,res->charset()); + return str; +} + + + #define bin_to_ascii(c) ((c)>=38?((c)-38+'a'):(c)>=12?((c)-12+'A'):(c)+'.') String *Item_func_encrypt::val_str(String *str) diff --git a/sql/item_strfunc.h b/sql/item_strfunc.h index d416f09d458..616c9b6a11f 100644 --- a/sql/item_strfunc.h +++ b/sql/item_strfunc.h @@ -21,6 +21,9 @@ #pragma interface /* gcc class implementation */ #endif +extern my_bool opt_old_passwords; /* Need this variable for some functions */ + + class Item_str_func :public Item_func { public: @@ -247,10 +250,23 @@ class Item_func_password :public Item_str_func public: Item_func_password(Item *a) :Item_str_func(a) {} String *val_str(String *); - void fix_length_and_dec() { max_length = get_password_length(); } + void fix_length_and_dec() { max_length = get_password_length(opt_old_passwords); } const char *func_name() const { return "password"; } }; + +class Item_func_old_password :public Item_str_func +{ + char tmp_value[16]; /* old password length */ +public: + Item_func_old_password(Item *a) :Item_str_func(a) {} + String *val_str(String *); + void fix_length_and_dec() { max_length = get_password_length(1); } + const char *func_name() const { return "old_password"; } +}; + + + class Item_func_des_encrypt :public Item_str_func { String tmp_value; diff --git a/sql/lex.h b/sql/lex.h index 6e36e01fbe7..a6bb4605aa5 100644 --- a/sql/lex.h +++ b/sql/lex.h @@ -513,6 +513,7 @@ static SYMBOL sql_functions[] = { { "NUMPOINTS", SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_numpoints)}, { "OCTET_LENGTH", SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_length)}, { "OCT", SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_oct)}, + { "OLD_PASSWORD", SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_old_password)}, { "ORD", SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_ord)}, { "OVERLAPS", SYM(FUNC_ARG2),0,CREATE_FUNC(create_func_overlaps)}, { "PERIOD_ADD", SYM(FUNC_ARG2),0,CREATE_FUNC(create_func_period_add)}, diff --git a/sql/password.c b/sql/password.c index 1875bb0ef04..ba7dc17c671 100644 --- a/sql/password.c +++ b/sql/password.c @@ -46,7 +46,6 @@ #define PVERSION41_CHAR '*' -extern my_bool opt_old_passwords; /* If prior 4.1 functions to be used */ @@ -95,14 +94,17 @@ void hash_password(ulong *result, const char *password) } -void make_scrambled_password(char *to,const char *password) + + + +void make_scrambled_password(char *to,const char *password,my_bool force_old_scramble) { ulong hash_res[2]; /* Used for pre 4.1 password hashing */ static uint salt=0; /* Salt for 4.1 version password */ unsigned char* slt=(unsigned char*)&salt; SHA1_CONTEXT context; uint8 digest[SHA1_HASH_SIZE]; - if (opt_old_passwords) /* Pre 4.1 password encryption */ + if (force_old_scramble) /* Pre 4.1 password encryption */ { hash_password(hash_res,password); sprintf(to,"%08lx%08lx",hash_res[0],hash_res[1]); @@ -125,23 +127,33 @@ void make_scrambled_password(char *to,const char *password) sha1_input(&context,(int8*)&password[0],1); } sha1_result(&context,digest); + /* Hash one more time */ + sha1_reset(&context); + sha1_input(&context,digest,SHA1_HASH_SIZE); + sha1_result(&context,digest); /* 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]); - + digest[14],digest[15],digest[16],digest[17],digest[18],digest[19]); } } -uint get_password_length() +uint get_password_length(my_bool force_old_scramble) { - if (opt_old_passwords) + if (force_old_scramble) return 16; else return SHA1_HASH_SIZE*2+4+1; } +uint8 get_password_version(const char* password) +{ + if (password==NULL) return 0; + if (password[0]==PVERSION41_CHAR) return PVERSION41_CHAR; + return 0; +} + inline uint char_val(char X) { @@ -151,15 +163,27 @@ inline uint char_val(char X) } /* -** This code assumes that len(password) is divideable with 8 and that -** res is big enough (2 in mysql) +** This code detects new version password by leading char. +** Old password has to be divisible by 8 length +** do not forget to increase array length if you need longer passwords */ void get_salt_from_password(ulong *res,const char *password) { - res[0]=res[1]=0; + bzero(res,5*sizeof(res[0])); if (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; + } while (*password) { ulong val=0; @@ -167,13 +191,14 @@ void get_salt_from_password(ulong *res,const char *password) for (i=0 ; i < 8 ; i++) val=(val << 4)+char_val(*password++); *res++=val; - } + } } return; } void make_password_from_salt(char *to, ulong *hash_res) { + // warning this does not work for new passwords yet sprintf(to,"%08lx%08lx",hash_res[0],hash_res[1]); } diff --git a/sql/sql_acl.cc b/sql/sql_acl.cc index 5f8cf42c2bf..2012b565dae 100644 --- a/sql/sql_acl.cc +++ b/sql/sql_acl.cc @@ -63,7 +63,8 @@ public: uint hostname_length; USER_RESOURCES user_resource; char *user,*password; - ulong salt[2]; + ulong salt[6]; // New password has longer length + uint8 pversion; // password version enum SSL_type ssl_type; const char *ssl_cipher, *x509_issuer, *x509_subject; }; @@ -231,7 +232,7 @@ my_bool acl_init(bool dont_read_acl_tables) "Found old style password for user '%s'. Ignoring user. (You may want to restart mysqld using --old-protocol)", user.user ? user.user : ""); /* purecov: tested */ } - else if (length % 8) // This holds true for passwords + else if (length % 8 && length!=45) // This holds true for passwords { sql_print_error( "Found invalid password for user: '%s@%s'; Ignoring user", @@ -240,6 +241,7 @@ my_bool acl_init(bool dont_read_acl_tables) continue; /* purecov: tested */ } get_salt_from_password(user.salt,user.password); + user.pversion=get_password_version(user.password); user.access=get_access(table,3) & GLOBAL_ACLS; user.sort=get_sort(2,user.host.hostname,user.user); user.hostname_length= (user.host.hostname ? @@ -671,6 +673,7 @@ static void acl_update_user(const char *user, const char *host, { acl_user->password=(char*) ""; // Just point at something get_salt_from_password(acl_user->salt,password); + acl_user->pversion=get_password_version(acl_user->password); } } break; @@ -706,6 +709,7 @@ static void acl_insert_user(const char *user, const char *host, { acl_user.password=(char*) ""; // Just point at something get_salt_from_password(acl_user.salt,password); + acl_user.pversion=get_password_version(acl_user.password); } VOID(push_dynamic(&acl_users,(gptr) &acl_user)); @@ -1052,9 +1056,11 @@ bool change_password(THD *thd, const char *host, const char *user, if (check_change_password(thd, host, user)) DBUG_RETURN(1); - /* password should always be 0 or 16 chars; simple hack to avoid cracking */ + /* password should always be 0,16 or 45 chars; simple hack to avoid cracking */ length=(uint) strlen(new_password); - new_password[length & 16]=0; + + if (length!=45) + new_password[length & 16]=0; VOID(pthread_mutex_lock(&acl_cache->lock)); ACL_USER *acl_user; @@ -1074,6 +1080,7 @@ bool change_password(THD *thd, const char *host, const char *user, DBUG_RETURN(1); /* purecov: deadcode */ } get_salt_from_password(acl_user->salt,new_password); + acl_user->pversion=get_password_version(new_password); if (!new_password[0]) acl_user->password=0; else @@ -1081,7 +1088,7 @@ bool change_password(THD *thd, const char *host, const char *user, acl_cache->clear(1); // Clear locked hostname cache VOID(pthread_mutex_unlock(&acl_cache->lock)); - char buff[460]; + char buff[512]; /* Extend with extended password length*/ ulong query_length= my_sprintf(buff, (buff,"SET PASSWORD FOR \"%-.120s\"@\"%-.120s\"=\"%-.120s\"", diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index dbc401b3ddc..2cb0904c3b5 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -3592,7 +3592,7 @@ text_or_password: else { char *buff=(char*) sql_alloc(HASH_PASSWORD_LENGTH+1); - make_scrambled_password(buff,$3.str); + make_scrambled_password(buff,$3.str,opt_old_passwords); $$=buff; } }; @@ -3872,7 +3872,7 @@ grant_user: char *buff=(char*) sql_alloc(HASH_PASSWORD_LENGTH+1); if (buff) { - make_scrambled_password(buff,$4.str); + make_scrambled_password(buff,$4.str,opt_old_passwords); $1->password.str=buff; $1->password.length=HASH_PASSWORD_LENGTH; } |