- # generate an md5 password
- if ($self->_GeneratePassword($value) eq $self->__Value('Password')) {
- return(1);
- }
-
- # if it's a historical password we say ok.
- if ($self->__Value('Password') eq crypt(encode_utf8($value), $self->__Value('Password'))
- or $self->_GeneratePasswordBase64($value) eq $self->__Value('Password'))
- {
- # ...but upgrade the legacy password inplace.
- $self->SUPER::SetPassword( $self->_GeneratePassword($value) );
- return(1);
+ my $stored = $self->__Value('Password');
+ if (length $stored == 40) {
+ # The truncated SHA256(salt,MD5(passwd)) form from 2010/12 is 40 characters long
+ my $hash = MIME::Base64::decode_base64($stored);
+ # The first 4 bytes are the salt, the rest is substr(SHA256,0,26)
+ my $salt = substr($hash, 0, 4, "");
+ return substr(Digest::SHA::sha256($salt . Digest::MD5::md5($value)), 0, 26) eq $hash;
+ } elsif (length $stored == 32) {
+ # Hex nonsalted-md5
+ return 0 unless Digest::MD5::md5_hex(encode_utf8($value)) eq $stored;
+ } elsif (length $stored == 22) {
+ # Base64 nonsalted-md5
+ return 0 unless Digest::MD5::md5_base64(encode_utf8($value)) eq $stored;
+ } elsif (length $stored == 13) {
+ # crypt() output
+ return 0 unless crypt(encode_utf8($value), $stored) eq $stored;
+ } else {
+ $RT::Logger->warn("Unknown password form");
+ return 0;