113 lines
3.9 KiB
Perl
113 lines
3.9 KiB
Perl
#!/usr/bin/perl
|
|
|
|
use Net::LDAP;
|
|
use Term::ReadPassword;
|
|
use Digest::SHA1;
|
|
use MIME::Base64;
|
|
use Data::UUID;
|
|
use Crypt::Cracklib;
|
|
|
|
my $PASSWD_MIN_LEN = 8;
|
|
my $password;
|
|
|
|
# parse RC file
|
|
# $ENV{GL_RC} = "/home/gitolite/.gitolite.rc";
|
|
die "parse $ENV{GL_RC} failed: " . ($! or $@) unless do $ENV{GL_RC};
|
|
|
|
# These come from .gitolite.rc file
|
|
our ($GL_LDAP_HOST, $GL_LDAP_BIND_DN, $GL_LDAP_BIND_PASSWORD, $GL_LDAP_USER_DN);
|
|
|
|
$Term::ReadPassword::ALLOW_STDIN = 1;
|
|
|
|
# NOTICE: For some reason Perl fails to disable terminal echo
|
|
# so following warning about ECHO must be given to the user
|
|
|
|
# Warn about password echo because of bugs in Perl ReadPasword
|
|
print "\nNOTE THAT THE PASSWORD WILL BE ECHOED TO THE SCREEN!\n" .
|
|
"Please make sure no one is shoulder-surfing, and make sure\n" .
|
|
"you clear your screen and scrollback history after you are done\n" .
|
|
"(or close your terminal session).\n\n";
|
|
|
|
print "Please type in your new password at the prompt.\n\n" .
|
|
"Following special keys are available while typing:\n" .
|
|
" <BackSpace> key to remove the last character\n" .
|
|
" <Ctrl-U> to remove all characters\n" .
|
|
" <Ctrl-C> to terminate password change operation\n" .
|
|
" <Enter> to end password typing\n";
|
|
|
|
while ( 1 ) {
|
|
|
|
print "\n"; # Start reading with new line
|
|
$password = read_password("Enter new password: ", 0, 1);
|
|
|
|
# Check the validity of new password
|
|
if ( length( $password ) >= $PASSWD_MIN_LEN # require minimum length
|
|
&& $password =~ /([\x20-\x7E])/ # require printable characters
|
|
&& $password =~ /[a-z]/ # require lower case letter
|
|
&& $password =~ /[A-Z]/ # require upper case letter
|
|
&& $password =~ /[0-9]/ # require number
|
|
&& check( $password ) ) # require other than dictionary words
|
|
{
|
|
# Re-enter new password to check possible typos
|
|
if ( $password ne read_password("Enter password again: ") ) {
|
|
|
|
print "Passwords do not match!\n";
|
|
redo;
|
|
} else {
|
|
|
|
last; # Password is valid and there are no typos, so break out
|
|
}
|
|
} else { # Given password is not valid
|
|
|
|
print "Password must contain at least $PASSWD_MIN_LEN characters and numbers,\n" .
|
|
"must have both upper and lower case characters,\n" .
|
|
"can have special characters like !,",#,...\n" .
|
|
"but cannot be any valid dictionary word.\n";
|
|
redo;
|
|
}
|
|
}
|
|
|
|
# Create hash from the password to be stored to the LDAP
|
|
my $ctx = Digest::SHA1->new();
|
|
my $ug = new Data::UUID;
|
|
my $salt = $ug->create_b64();
|
|
$ctx->add( $password );
|
|
$ctx->add( $salt );
|
|
$password = '{SSHA}' . encode_base64( $ctx->digest . $salt, '' );
|
|
|
|
# Create communication structure for LDAP connection
|
|
my $ldap = Net::LDAP->new( $GL_LDAP_HOST ) or die "$@";
|
|
my $r = $ldap->start_tls( verify => 'none',
|
|
sslversion => 'tlsv1' );
|
|
if ( $r->code ) {
|
|
print "Password handling failed with $r->code return code!\n";
|
|
log_it( "Password change, LDAP connection failed for $ENV{GL_USER}" );
|
|
exit 1;
|
|
}
|
|
|
|
# Bind to LDAP with proper user
|
|
$r = $ldap->bind( $GL_LDAP_BIND_DN,
|
|
password => $GL_LDAP_BIND_PASSWORD );
|
|
if ( $r->code ) {
|
|
print "Password update failed with $r->code return code!\n";
|
|
log_it( "Password change, LDAP bind failed for $ENV{GL_USER}" );
|
|
exit 1;
|
|
}
|
|
|
|
# Update new password to the LDAP
|
|
$r = $ldap->modify( "uid=$ENV{GL_USER},
|
|
$GL_LDAP_USER_DN",
|
|
replace => { 'userPassword', $password } );
|
|
|
|
if ( $r->code ) {
|
|
print "Password change failed!\n" .
|
|
"Please contact administrator to change password.\n";
|
|
# log_it( "Password change, LDAP modify failed for $ENV{GL_USER}" );
|
|
} else {
|
|
print "Password changed succesfully.\n";
|
|
# log_it( "Password change, LDAP modify done for $ENV{GL_USER}" );
|
|
}
|
|
|
|
$r = $ldap->unbind();
|
|
|