#!/usr/local/bin/perl -w use strict; use File::Copy; use Cwd; # Set these as needed my $DEBUG = 0; my $SHADOW = "/etc/shadow"; my $SHADOW_TMP = "/etc/.shadow.tmp"; my $FORMS_FILE = "/tmp/pwchg.tmp"; my $GENPASS = "/usr/local/bin/genpasswd"; my $YP_DIR = ""; # define this if you use yp my $MAKE = "/bin/make"; my $LP = "/bin/lp"; my %shadow; # These are sanity checks (make and yp_dir checked later) die "File not found: $SHADOW\n" unless -e $SHADOW; die "File not found: $GENPASS\n" unless -e $GENPASS; die "File not found: $LP\n" unless -e $LP; die "$GENPASS is not executable.\n" unless -x $GENPASS; die "$LP is not executable.\n" unless -x $LP; die "Usage: $0 <username>+\n" unless @ARGV; print STDERR map { "$_\n" } @ARGV if $DEBUG; # If we want to read in from file, here's # a way to scan them all in at once my @users; foreach my $file (@ARGV) { if (-e $file) { $file =~ s/\W//g; # de-Taint the filename open USERS, $file or die "Couldn't get users: $!\n"; push @users, <USERS>; close USERS or warn "Couldn't close file $file: $!\n"; } else { push @users, $file; } } chomp @users; # clean up spare "\n"'s from files and command line # de-Taint usernames foreach my $tainted (@users) { $tainted =~ s/\W//g; } print STDERR map { "$_\n" } @users if $DEBUG; # we don't want to work on the actual shadow file, in case we botch copy($SHADOW, $SHADOW_TMP) or die "Couldn't move files: $!\n"; open SHAD, $SHADOW_TMP or die "Couldn't open shadow: $!\n"; %shadow = map {/([^:]+):(.*)/ && ($1 => "$1:$2")} <SHAD>; close SHAD or warn "Couldn't close shadow: $!\n"; # The hard work of the script... open FORMS, ">$FORMS_FILE" or die "Couldn't open forms file: $!\n"; my ($new_pass, $new_crypt, $salt); foreach my $user (@users) { if ($shadow{$user}) { chomp( $new_pass =`$GENPASS` ); $new_pass =~//; $salt = gen_salt(); $new_crypt = crypt($new_pass, $salt); $shadow{$user} =~ s/([^:]+):[^:]+:(.*)/$1:$new_crypt:$2/; print FORMS pass_info($user,$new_pass); print FORMS "^L" unless $user eq $users[$#users]; } else { print FORMS no_account($user); print FORMS "^L" unless $user eq $users[$#users]; } } close FORMS or die "Couldn't close $FORMS_FILE: $!\n"; # While we're here, why not sort the shadow file? open SHAD, ">$SHADOW_TMP" or die "Couldn't open shadow: $!\n"; print SHAD map {$_->[1],"\n"} sort{$a->[0] cmp $b->[0]} map {[$_,$shadow{$_}]} keys %shadow; close SHAD or die "Couldn't close shadow: $!\n"; copy($SHADOW_TMP, $SHADOW) or warn "Couldn't move tmp to shadow: $!\n" +; # The newly thought out YP section (now tested and working) { last unless $YP_DIR; warn "Failed to find/run $MAKE for yp.\n",last unless -e $MAKE && -x + _; my $cur_dir = cwd; if (chdir($YP_DIR)) { system("$MAKE"); warn $@ if $@; chdir $cur_dir or warn "Couldn't go to $cur_dir: $!\n"; } else { warn "Couldn't push yp: $!\n"; } } # print the forms my $status = `$LP $FORMS_FILE`; print "Printing ", scalar @users, " forms: $status\n"; END { unlink($FORMS_FILE,$SHADOW_TMP) unless $DEBUG } sub gen_salt { join '', ('.', '/', 0..9, 'a'..'z', 'A'..'Z')[rand(64),rand(64)] } sub pass_info { my ($user,$pass) = @_; my $date = scalar localtime; return <<INFO; DATE: $date TO: $user You have a new passwd for this system: Login name: $user New Passwd: $pass INFO } sub no_account { my $user = shift; my $date = scalar localtime; return <<NO; DATE: $date You have no account on this system, pick up an Account Creation Form. Login name: $user NO } __END__
In reply to Password Change w/ Forms (Code Review Requested) by jynx
| For: | Use: | ||
| & | & | ||
| < | < | ||
| > | > | ||
| [ | [ | ||
| ] | ] |