Blowfish password hashing support
authorJamie Cameron <jcameron@webmin.com>
Fri, 9 Jan 2009 18:03:32 +0000 (18:03 +0000)
committerJamie Cameron <jcameron@webmin.com>
Fri, 9 Jan 2009 18:03:32 +0000 (18:03 +0000)
useradmin/CHANGELOG
useradmin/config.info
useradmin/lang/en
useradmin/md5-lib.pl
useradmin/solaris-lib.pl
useradmin/user-lib.pl

index 0b9dc9f..edff1da 100644 (file)
@@ -54,3 +54,4 @@ Added a non-editable list of users who have this group as their primary to the E
 Added a Module Config option to use a text box for entering secondary group members, rather than the left/right user chooser.
 Created a page for exporting groups to a batch file, for importing on other systems.
 Added support for creating, deleting and modifying groups from a batch file. This is similar to the long-standing batch user management functionality.
+Added support for Blowfish password hashing, which can be enabled on the Module Config page. On Solaris systems, it will be used if enabled in /etc/security/policy.conf. Requires the Crypt::Eksblowfish::Bcrypt Perl module though.
index f03b22b..d45d2f4 100644 (file)
@@ -14,7 +14,7 @@ uid_calc=UID Calculation Method,4,0-Berkeley cksum,1-Custom mkuid program
 gid_calc=GID Calculation Method,4,0-Berkeley cksum,1-Custom mkgid program
 new_user_group=Create new group for new users?,1,1-Yes,0-No
 new_user_gid=Assign same ID to new user and group?,1,1-Yes,0-No
-md5=Password encryption method,1,2-MD5,1-Determine automatically,0-DES crypt
+md5=Password encryption method,1,2-MD5,1-Determine automatically,0-DES crypt,3-Blowfish
 alias_check=Check for sendmail alias clashes?,1,1-Yes,0-No
 delete_only=Only delete files owned by user?,1,1-Yes,0-No
 max_length=Maximum user and group name length,3,Unlimited
index 50236c9..dfa26ec 100644 (file)
@@ -167,7 +167,8 @@ usave_echmod=Couldn't chmod home directory : $1
 usave_eoffice=Office cannot contain a : character
 usave_eworkph=Work phone cannot contain a : character
 usave_ehomeph=Home phone cannot contain a : character
-usave_edigestmd5=Your system has MD5 passwords enabled, but neither the perl MD5 or Digest::MD5 module is not installed.<p>To force the use of normal encrypted passwords, adjust your <a href='$1'>module configuration</a>.<p>Or have Webmin <a href='$2'>download and install</a> the Digest::MD5 module for you.
+usave_edigestmd5=Your system has MD5 passwords enabled, but the Perl <tt>$3</tt> module is not installed.<p>To force the use of normal encrypted passwords, adjust your <a href='$1'>module configuration</a>.<p>Or have Webmin <a href='$2'>download and install</a> the <tt>$3</tt> module for you.
+usave_edigestblowfish=Your system has MD5 passwords enabled, but the Perl <tt>$3</tt> module is not installed.<p>To force the use of normal encrypted passwords, adjust your <a href='$1'>module configuration</a>.<p>Or have Webmin <a href='$2'>download and install</a> the <tt>$3</tt> module for you.
 usave_emaking=Before update command failed : $1
 usave_epasswd_min=Password must be at least $1 letters long
 usave_epasswd_re=Password does not match regexp $1
index b0c36b8..daf7aa7 100644 (file)
@@ -144,6 +144,35 @@ return "{SHA}$sh=";
 sub encrypt_sha1_hash
 {
 local ($pass, $salt) = @_;
+# XXX not done yet??
+}
+
+# check_blowfish()
+# Returns an missing Perl module if blowfish is not available, undef if OK
+sub check_blowfish
+{
+eval "use Crypt::Eksblowfish::Bcrypt";
+return $@ ? "Crypt::Eksblowfish::Bcrypt" : undef;
+}
+
+# encrypt_blowfish(password, [salt])
+# Returns a string encrypted in blowfish format, suitable for /etc/shadow
+sub encrypt_blowfish
+{
+local ($passwd, $salt) = @_;
+local ($plain, $base64);
+eval "use Crypt::Eksblowfish::Bcrypt";
+if (!$salt) {
+       # Generate a 22-character base-64 format salt
+       &seed_random();
+       while(length($base64) < 22) {
+               $plain .= chr(int(rand()*96)+32);
+               $base64 = Crypt::Eksblowfish::Bcrypt::en_base64($plain);
+               }
+       $base64 = substr($base64, 0, 22);
+       $salt = '$2$'.'08'.'$'.$base64;
+       }
+return Crypt::Eksblowfish::Bcrypt::bcrypt($passwd, $salt);
 }
 
 1;
index 9801bf8..9cafcb4 100644 (file)
@@ -60,7 +60,7 @@ return @rv;
 }
 
 # use_md5()
-# Returns 1 if MD5 encryption should be used
+# Returns 1 if MD5 encryption should be used, 2 if blowfish
 sub use_md5
 {
 local $lref = &read_file_lines("/etc/security/policy.conf");
@@ -70,6 +70,7 @@ foreach $l (@$lref) {
            $l =~ /^CRYPT_DEFAULT\s*=\s*'([^']*)'/ ||
            $l =~ /^CRYPT_DEFAULT\s*=\s*(\S+)/) {
                return 1 if ($1 eq "1");
+               return 2 if ($1 eq "2a");
                }
        }
 return 0;
index 2f44cf1..4db9739 100644 (file)
@@ -1599,7 +1599,7 @@ Encrypts a password using the encryption format configured for this system
 sub encrypt_password
 {
 local ($pass, $salt) = @_;
-local $md5 = 0;
+local $format = 0;
 if ($gconfig{'os_type'} eq 'macos' && &passfiles_type() == 7) {
        # New OSX directory service uses SHA1 for passwords!
        $salt ||= chr(int(rand(26))+65).chr(int(rand(26))+65). 
@@ -1625,32 +1625,48 @@ if ($gconfig{'os_type'} eq 'macos' && &passfiles_type() == 7) {
        }
 elsif ($config{'md5'} == 2) {
        # Always use MD5
-       $md5 = 1;
+       $format = 1;
+       }
+elsif ($config{'md5'} == 3) {
+       # Always use blowfish
+       $format = 2;
        }
 elsif ($config{'md5'} == 1 && !$config{'skip_md5'}) {
        # Up to system
-       $md5 = &use_md5() if (defined(&use_md5));
+       $format = &use_md5() if (defined(&use_md5));
        }
 if ($no_encrypt_password) {
        # Some operating systems don't do any encryption!
        return $pass;
        }
-elsif ($md5) {
+elsif ($format == 1) {
        # MD5 encryption is selected .. use it if possible
        local $err = &check_md5();
        if ($err) {
-               &header($text{'error'}, "");
-               print "<hr><p>\n";
+               &ui_print_header(undef, $text{'error'}, "");
                print &text('usave_edigestmd5',
                    "/config.cgi?$module_name",
-                   "/cpan/download.cgi?source=3&cpan=$err"),
+                   "/cpan/download.cgi?source=3&cpan=$err", $err),
                    "<p>\n";
-               print "<hr>\n";
-               &footer("", $text{'index_return'});
+               &ui_print_footer("", $text{'index_return'});
                exit;
                }
        return &encrypt_md5($pass, $salt);
        }
+elsif ($format == 2) {
+       # Blowfish is selected .. use it if possible
+       local $err = &check_blowfish();
+       if ($err) {
+               &ui_print_header(undef, $text{'error'}, "");
+               print &text('usave_edigestblowfish',
+                   "/config.cgi?$module_name",
+                   "/cpan/download.cgi?source=3&cpan=$err", $err),
+                   "<p>\n";
+               &ui_print_footer("", $text{'index_return'});
+               exit;
+               }
+       return &encrypt_blowfish($pass, $salt);
+       }
 else {
        # Just do old-style crypt() DES encryption
        $salt ||= chr(int(rand(26))+65) . chr(int(rand(26))+65);