#!/usr/local/bin/perl
## $Id: mpasswd,v 1.7 1994/10/21 02:58:44 mikew Exp $
## ========================================================================
## mpasswd -- /bin/passwd wrapper
## Author          : Mike Williams <mikew@gopher.dosli.govt.nz>
## ========================================================================

require 'chat2.pl';
require 'open2.pl';

#--- Initialisation -------------------------------------------------------

$checkpw = "/usr/local/lib/ckpasswd/ckpasswd";
$greeting = undef;

#--- Inhibit core dumps ---------------------------------------------------

# Leaving a core dump around could be a security problem (as it will
# probably contain the user's password).  So, we catch the signals which
# normally produce core dumps, and exit gracefully.

for $sig ('QUIT', 'ILL', 'TRAP', 'IOT', 'EMT',
	  'FPE', 'BUS', 'SEGV', 'SYS') {
    $SIG{$sig} = 'sigexit';
}

sub sigexit {
    warn "\ncaught fatal signal - no core dump\n";
    exit 99;
}

#--- Talk to /bin/passwd --------------------------------------------------

print $greeting if $greeting;

$passwd = &chat'open_proc("/bin/passwd", @ARGV);

system ('stty', '-echo');

expect:
for (;;) {
    $val = &chat'expect
	($passwd, 10,
	 'ew password: ', q[	# "New password" prompt
	     $prompt = $`.$&;
	     while ($_ = &getpw($prompt)) {  
		 last unless ($reason = &checkpw($_));
		 print "\n\n  Sorry, that's not a good password:\n";
		 $* = 1; $reason =~ s/^/    /g; $* = 0;
		 print "$reason\n";
	     }
	     &chat'print ($passwd, "$_\n");
	 ],
	 '.*\n' , q{		# messages
	     $_ = $&; 
	     print;
	 },    
	 ': ', q{		# other prompts ("Old password", "Verify")
	     $prompt = $`.$&;
	     $_ = &getpw($prompt);
	     &chat'print ($passwd, "$_\n");
	 },
	 EOF, q{		# End of file
	     last expect;
	 },
	 TIMEOUT, q{		# timeout (shouldn't happen)
	     die "timed out\n";
	 },
	 );
}

system ('stty', 'echo');

#--- Prompt for password --------------------------------------------------

sub getpw {
    local ($prompt) = @_;
    local ($_);
    print $prompt;
    chop ($_ = <STDIN>);
    $_;
}

#--- Check safety of passwd -----------------------------------------------

sub checkpw {
    local ($password) = @_;
    local (*IN, *OUT);
    local ($pid, $reply, $_);
    eval {
	$pid = &open2 (OUT, IN, $checkpw);
    };
    die "\nerror invoking password checker\n$@" if ($@);
    print IN "$password\n";
    close (IN);
    while (<OUT>) {
	$reply .= $_;
    }
    close (OUT);
    waitpid ($pid, 0);
    $reply;
}

##=== END of mpasswd ======================================================
