全部博文(1144)
分类: LINUX
2009-12-09 12:09:28
#!/usr/local/bin/perl
# passwd replacement for solaris < 10
# try to make users select a stronger password
# copyright 2009.05.04 jeremy kister
# v2009061901
# to install, simply:
# mv /usr/bin/passwd /usr/bin/passwd.orig
# chmod 0 /usr/bin/passwd.orig
# mv passwd.pl /usr/bin/passwd
# chown root:sys /usr/bin/passwd
# chmod 6555 /usr/bin/passwd
#
# set CRYPT_DEFAULT=1 in /etc/security/policy.conf
# modify $NIS (below) - 0 if not using NIS, 1 if using NIS
use strict;
use Crypt::PasswdMD5 qw(unix_md5_crypt);
my $NIS = 1;
$SIG{INT} = $SIG{QUIT} = $SIG{HUP} = sub { cleanup(); };
foreach my $key (keys %ENV){
# make suid perl safer..
next if($key eq 'USER');
delete $ENV{$key};
}
my $user = $ENV{USER};
if(@ARGV >= 1){
if( $< ){
die "I don't support any arguments\n";
}else{
if(@ARGV == 1){
$user = shift;
}else{
die "I'll only take a username as an argument\n";
}
}
}
unless($user =~ /^[a-z]{3,12}[0-9]?$/){
die "invalid user: $user\n";
}
die "wont change root pw\n" if($user eq 'root');
srand(time() ^($$ + ($$ << 15)));
my @set = ('.', '/', '0'..'9', 'A'..'Z', 'a'..'z');
my $salt = join ('', map { $set[ rand ( @set) ] } (1 .. 8));
open(TSTMP, ">/etc/stmp.$$") || die "cannot write to /etc/stmp.$$: $!\n";
close TSTMP;
chmod(0600, "/etc/stmp.$$") || die "cannot set file mode on /etc/stmp.$$: $!\n";
my $have_link;
for(1..5){
if( link("/etc/stmp.$$", "/etc/stmp") ){
$have_link = 1;
last;
}else{
sleep 2;
}
}
unless($have_link){
print "passwd: Sorry, could not obtain stmp lock.\n";
exit_evil();
}
my $ocrypt;
open(SHADOW, "/etc/shadow") || die "cannot read shadow file: $!\n";
my @shadow = ;
close SHADOW;
foreach(@shadow){
if(/^$user:([^:]+):/){
$ocrypt = $1;
last;
}
}
unless($user && $ocrypt){
print "passwd: User unknown: $user\n";
exit_evil();
}
my $opw;
print "passwd: Changing password for $user\n";
if( $< ){
print "Enter existing login password: ";
system "stty -echo";
chomp($opw=);
print "\n";
}
if( $ocrypt eq crypt($opw, $ocrypt) || $< == 0 ){
my $npw;
system "stty -echo";
for my $round (1..3){
print "New Password: ";
chomp($npw=);
print "\n";
# check strength
my $err;
my %types;
if($npw =~ /$user/i){
print "passwd: Sorry, can't use your username in your password\n";
$err++;
}
my $rev = reverse($user);
if($npw =~ /$rev/i){
print "passwd: Sorry, can't use the reverse of your username in your password\n";
$err++;
}
if(length($npw) < 8 || length($npw) > 255){
print "passwd: Sorry, password must be 8 to 255 characters.\n";
$err++;
}
$types{uc} = 1 if($npw =~ /[A-Z]/);
$types{lc} = 1 if($npw =~ /[a-z]/);
$types{num} = 1 if($npw =~ /[0-9]/);
$types{special} = 1 if($npw =~ /[^A-Z0-9]/i);
if(keys %types < 3){
print "Password must contain characters from at least three of the following four classes:\n",
" * English Upper Case Letters (A, B, C, .. Z)\n",
" * English Lower Case Letters (a, b, c, .. z)\n",
" * Westernized Arabic Numerals (0, 1, 2, .. 9)\n",
" * Non-alphanumeric (special characters, e.g. punctuation symbols)\n";
$err++;
}
unless($err){
print "Re-enter new Password: ";
chomp(my $rpw=);
if($npw ne $rpw){
print "passwd(SYSTEM): They don't match.\n";
$err++;
}
}
if($err){
if($round == 3){
exit_evil();
}else{
print "\n",
"Please try again\n";
}
}else{
last;
}
}
system("stty echo");
print "\n";
my $ncrypt = unix_md5_crypt($npw, $salt);
my $days = sprintf( '%d', (time() / 86400) );
open(STMP, ">>/etc/stmp") || die "could not append to stmp: $!\n";
foreach(@shadow){
if(/^$user:/){
print STMP "${user}:${ncrypt}:${days}::::::\n";
}else{
print STMP;
}
}
close STMP;
rename("/etc/stmp","/etc/shadow") || die "cannot rename stmp to shadow: $!\n";
unlink("/etc/stmp.$$") || die "cannot unlink stmp.$$: $!\n";
chmod(0400, "/etc/shadow") || die "cannot set file mode on /etc/shadow: $!\n";
if($NIS){
system("cd /var/yp ; /usr/local/bin/make >/dev/null 2>&1");
}
}else{
print "passwd: Sorry, wrong passwd\n";
exit_evil();
}
sub exit_evil {
print "Permission denied\n";
cleanup();
exit 1;
}
sub cleanup {
unlink("/etc/stmp.$$");
unlink("/etc/stmp") if($have_link);
system("stty echo");
exit;
}