gitolite/contrib/ldap/passwd

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();