mirror of
https://github.com/webmin/webmin.git
synced 2026-06-21 11:50:25 +01:00
MD5 support for Webmin users using modules
This commit is contained in:
@@ -46,4 +46,4 @@ Updated the user interface to use the Webmin UI library.
|
||||
Fixed the display of modules granted to groups.
|
||||
Added a per-user option to opt out of forced password changes after a certain number of days.
|
||||
A human-readable description of the password restrictions regular expression can be entered, for use in error messages.
|
||||
Webmin users can now be given temporary passwords, which they are forced to change at the next login.
|
||||
Webmin users can now be given temporary passwords, which they are forced to change at the next login. Thanks to GE Medical Systems for supporting this feature.
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
do '../web-lib.pl';
|
||||
&init_config();
|
||||
do '../ui-lib.pl';
|
||||
do 'md5-lib.pl';
|
||||
%access = &get_module_acl();
|
||||
$access{'switch'} = 0 if (&is_readonly_mode());
|
||||
|
||||
@@ -658,14 +659,17 @@ else {
|
||||
}
|
||||
|
||||
# encrypt_password(password, [salt])
|
||||
# Encrypts a Webmin user password
|
||||
sub encrypt_password
|
||||
{
|
||||
local ($pass, $salt) = @_;
|
||||
if ($gconfig{'md5pass'}) {
|
||||
$salt ||= '$1$'.substr(time(), -8);
|
||||
return crypt($pass, $salt);
|
||||
# Use MD5 encryption
|
||||
$salt ||= '$1$'.substr(time(), -8).'$xxxxxxxxxxxxxxxxxxxxxx';
|
||||
return &encrypt_md5($pass, $salt);
|
||||
}
|
||||
else {
|
||||
# Use Unix DES
|
||||
&seed_random();
|
||||
$salt ||= chr(int(rand(26))+65).chr(int(rand(26))+65);
|
||||
return &unix_crypt($pass, $salt);
|
||||
@@ -797,7 +801,7 @@ local $use_md5 = &md5_perl_module();
|
||||
if (!$hash_session_id_cache{$sid}) {
|
||||
if ($use_md5) {
|
||||
# Take MD5 hash
|
||||
$hash_session_id_cache{$sid} = &encrypt_md5($sid);
|
||||
$hash_session_id_cache{$sid} = &hash_md5_session($sid);
|
||||
}
|
||||
else {
|
||||
# Unix crypt
|
||||
@@ -807,9 +811,9 @@ if (!$hash_session_id_cache{$sid}) {
|
||||
return $hash_session_id_cache{$sid};
|
||||
}
|
||||
|
||||
# encrypt_md5(string)
|
||||
# hash_md5_session(string)
|
||||
# Returns a string encrypted in MD5 format
|
||||
sub encrypt_md5
|
||||
sub hash_md5_session
|
||||
{
|
||||
local $passwd = $_[0];
|
||||
local $use_md5 = &md5_perl_module();
|
||||
@@ -860,18 +864,6 @@ $rv .= &to64($l, 2);
|
||||
return $rv;
|
||||
}
|
||||
|
||||
sub to64
|
||||
{
|
||||
local ($v, $n) = @_;
|
||||
local @itoa64 = split(//, "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz");
|
||||
local $r;
|
||||
while(--$n >= 0) {
|
||||
$r .= $itoa64[$v & 0x3f];
|
||||
$v >>= 6;
|
||||
}
|
||||
return $r;
|
||||
}
|
||||
|
||||
# Returns a Perl module for MD5 hashing, or undef if none
|
||||
sub md5_perl_module
|
||||
{
|
||||
|
||||
1
acl/md5-lib.pl
Symbolic link
1
acl/md5-lib.pl
Symbolic link
@@ -0,0 +1 @@
|
||||
../useradmin/md5-lib.pl
|
||||
62
miniserv.pl
62
miniserv.pl
@@ -2963,7 +2963,8 @@ elsif ($canmode == 0) {
|
||||
}
|
||||
elsif ($canmode == 1) {
|
||||
# Attempt Webmin authentication
|
||||
if ($users{$webminuser} eq &unix_crypt($pass, $users{$webminuser})) {
|
||||
if ($users{$webminuser} eq
|
||||
&password_crypt($pass, $users{$webminuser})) {
|
||||
# Password is valid .. but check for expiry
|
||||
local $lc = $lastchanges{$user};
|
||||
if ($config{'pass_maxdays'} && $lc && !$nochange{$user}) {
|
||||
@@ -3066,7 +3067,8 @@ elsif ($config{'passwd_file'}) {
|
||||
if (/^\s*(\S+):/ && $1 eq $_[0]) {
|
||||
$_ = <FILE>;
|
||||
if (/^\s*password\s*=\s*(\S+)\s*$/) {
|
||||
$rv = $1 eq &unix_crypt($_[1], $1) ? 1 : 0;
|
||||
$rv = $1 eq &password_crypt($_[1], $1) ?
|
||||
1 : 0;
|
||||
}
|
||||
last;
|
||||
}
|
||||
@@ -3079,7 +3081,7 @@ elsif ($config{'passwd_file'}) {
|
||||
local $u = $l[$config{'passwd_uindex'}];
|
||||
local $p = $l[$config{'passwd_pindex'}];
|
||||
if ($u eq $_[0]) {
|
||||
$rv = $p eq &unix_crypt($_[1], $p) ? 1 : 0;
|
||||
$rv = $p eq &password_crypt($_[1], $p) ? 1 : 0;
|
||||
if ($config{'passwd_cindex'} ne '' && $rv) {
|
||||
# Password may have expired!
|
||||
local $c = $l[$config{'passwd_cindex'}];
|
||||
@@ -3105,7 +3107,7 @@ elsif ($config{'passwd_file'}) {
|
||||
|
||||
# Fallback option - check password returned by getpw*
|
||||
local @uinfo = getpwnam($_[0]);
|
||||
if ($uinfo[1] ne '' && &unix_crypt($_[1], $uinfo[1]) eq $uinfo[1]) {
|
||||
if ($uinfo[1] ne '' && &password_crypt($_[1], $uinfo[1]) eq $uinfo[1]) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -4161,6 +4163,22 @@ if (!defined($logout_time_cache{$user,$sid})) {
|
||||
return $logout_time_cache{$user,$sid};
|
||||
}
|
||||
|
||||
# password_crypt(password, salt)
|
||||
# If the salt looks like MD5 and we have a library for it, perform MD5 hashing
|
||||
# of a password. Otherwise, do Unix crypt.
|
||||
sub password_crypt
|
||||
{
|
||||
local ($pass, $salt) = @_;
|
||||
if ($salt =~ /^\$1\$/ && $use_md5) {
|
||||
return &encrypt_md5($pass, $salt);
|
||||
}
|
||||
else {
|
||||
return &unix_crypt($pass, $salt);
|
||||
}
|
||||
}
|
||||
|
||||
# unix_crypt(password, salt)
|
||||
# Performs standard Unix hashing for a password
|
||||
sub unix_crypt
|
||||
{
|
||||
local ($pass, $salt) = @_;
|
||||
@@ -4591,19 +4609,31 @@ if (!$hash_session_id_cache{$sid}) {
|
||||
return $hash_session_id_cache{$sid};
|
||||
}
|
||||
|
||||
# encrypt_md5(string)
|
||||
# encrypt_md5(string, [salt])
|
||||
# Returns a string encrypted in MD5 format
|
||||
sub encrypt_md5
|
||||
{
|
||||
local $passwd = $_[0];
|
||||
local ($passwd, $salt) = @_;
|
||||
local $magic = '$1$';
|
||||
if ($salt =~ /^\$1\$(.{8})/) {
|
||||
# Extract actual salt from already encrypted password
|
||||
$salt = $1;
|
||||
}
|
||||
|
||||
# Add the password
|
||||
local $ctx = eval "new $use_md5";
|
||||
$ctx->add($passwd);
|
||||
if ($salt) {
|
||||
$ctx->add($magic);
|
||||
$ctx->add($salt);
|
||||
}
|
||||
|
||||
# Add some more stuff from the hash of the password and salt
|
||||
local $ctx1 = eval "new $use_md5";
|
||||
$ctx1->add($passwd);
|
||||
if ($salt) {
|
||||
$ctx1->add($salt);
|
||||
}
|
||||
$ctx1->add($passwd);
|
||||
local $final = $ctx1->digest();
|
||||
for($pl=length($passwd); $pl>0; $pl-=16) {
|
||||
@@ -4624,6 +4654,18 @@ for($i=length($passwd); $i; $i >>= 1) {
|
||||
}
|
||||
$final = $ctx->digest();
|
||||
|
||||
if ($salt) {
|
||||
# This loop exists only to waste time
|
||||
for($i=0; $i<1000; $i++) {
|
||||
$ctx1 = eval "new $use_md5";
|
||||
$ctx1->add($i & 1 ? $passwd : $final);
|
||||
$ctx1->add($salt) if ($i % 3);
|
||||
$ctx1->add($passwd) if ($i % 7);
|
||||
$ctx1->add($i & 1 ? $final : $passwd);
|
||||
$final = $ctx1->digest();
|
||||
}
|
||||
}
|
||||
|
||||
# Convert the 16-byte final string into a readable form
|
||||
local $rv;
|
||||
local @final = map { ord($_) } split(//, $final);
|
||||
@@ -4640,7 +4682,13 @@ $rv .= &to64($l, 4);
|
||||
$l = $final[11];
|
||||
$rv .= &to64($l, 2);
|
||||
|
||||
return $rv;
|
||||
# Add salt if needed
|
||||
if ($salt) {
|
||||
return $magic.$salt.'$'.$rv;
|
||||
}
|
||||
else {
|
||||
return $rv;
|
||||
}
|
||||
}
|
||||
|
||||
sub to64
|
||||
|
||||
@@ -5,6 +5,10 @@
|
||||
# are not installed, or undef if they are
|
||||
sub check_md5
|
||||
{
|
||||
# On some systems, the crypt function just works!
|
||||
return undef if (&unix_crypt_supports_md5());
|
||||
|
||||
# Try Perl modules
|
||||
eval "use MD5";
|
||||
if (!$@) {
|
||||
eval "use Digest::MD5";
|
||||
@@ -27,6 +31,11 @@ if ($salt =~ /^\$1\$(.{8})/) {
|
||||
$salt = $1;
|
||||
}
|
||||
|
||||
# Use built-in crypt support for MD5, if we can
|
||||
if (&unix_crypt_supports_md5()) {
|
||||
return &unix_crypt($passwd, $magic.$salt.'$xxxxxxxxxxxxxxxxxxxxxx');
|
||||
}
|
||||
|
||||
# Add the password, magic and salt
|
||||
local $cls = "MD5";
|
||||
eval "use MD5";
|
||||
@@ -95,6 +104,14 @@ $rv .= &to64($l, 2);
|
||||
return $rv;
|
||||
}
|
||||
|
||||
# unix_crypt_supports_md5()
|
||||
# Returns 1 if the built-in crypt() function can already do MD5
|
||||
sub unix_crypt_supports_md5
|
||||
{
|
||||
return &unix_crypt('test', '$1$A9wB3O18$zaZgqrEmb9VNltWTL454R/') eq
|
||||
'$1$A9wB3O18$zaZgqrEmb9VNltWTL454R/';
|
||||
}
|
||||
|
||||
@itoa64 = split(//, "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz");
|
||||
sub to64
|
||||
{
|
||||
|
||||
@@ -111,11 +111,10 @@ else {
|
||||
$gconfig{'loginbanner'} = $in{'banner'};
|
||||
}
|
||||
if ($in{'md5pass'}) {
|
||||
# MD5 enabled .. but is it supported by crypt?
|
||||
if (&unix_crypt('test', '$1$A9wB3O18$zaZgqrEmb9VNltWTL454R/') ne
|
||||
'$1$A9wB3O18$zaZgqrEmb9VNltWTL454R/') {
|
||||
&error($text{'session_emd5'});
|
||||
}
|
||||
# MD5 enabled .. but is it supported by this system?
|
||||
&foreign_require("acl", "acl-lib.pl");
|
||||
$need = &acl::check_md5();
|
||||
$need && &error(&text('session_emd5mod', "<tt>$need</tt>"));
|
||||
}
|
||||
$gconfig{'md5pass'} = $in{'md5pass'};
|
||||
&write_file("$config_directory/config", \%gconfig);
|
||||
|
||||
@@ -543,7 +543,7 @@ session_pmode1=Always allow users with expired passwords
|
||||
session_pmode2=Prompt users with expired passwords to enter a new one
|
||||
session_md5off=Use standard Unix <tt>crypt</tt> encryption for Webmin passwords
|
||||
session_md5on=Use MD5 encryption for Webmin passwords (allows long passwords)
|
||||
session_emd5=MD5 encryption cannot be used, as Perl does not have built-in <tt>crypt</tt> MD5 support on your system
|
||||
session_emd5mod=MD5 encryption cannot be used, as Perl $1 module is not installed.
|
||||
session_blocklock=Also lock users with failed logins
|
||||
|
||||
assignment_title=Reassign Modules
|
||||
|
||||
Reference in New Issue
Block a user