On Fri, Jan 23, 2004 at 12:17:00AM -0700, Will Aoki wrote: > I've attached a slightly cleaned-up version of the password changer that
Perhaps this time I'll remember to attach the file *and* the mailing list won't reject it... -- William Aoki KD7YAF [EMAIL PROTECTED] /"\ ASCII Ribbon Campaign \ / No HTML in mail or news! X / \
#!/usr/bin/perl -w -T # # Password changer # # written by Will Aoki <waoki AT umnh.utah.edu> # # $Id: passwdchanger.cgi,v 1.2 2004/01/23 06:53:26 waoki Exp $ use strict; use CGI qw/:standard -nodebug/; use CGI::Carp; use FileHandle; use IO::Select; use IPC::Open2; use IPC::Open3; use Sys::Syslog; ### Config goes here: my $config_ldapserver = "ldap.umnh.utah.edu"; my $config_basedn = ",ou=People,dc=umnh,dc=utah,dc=edu"; my $config_title = "UMNH Password Changer"; ### End of config #carp "Starting!\n"; # Setup my $pwchars = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ./'; my @pwchars = split //, $pwchars; undef $pwchars; #print $#pwchars, "\n"; # Returns Windows passwds sub mkntpwd ($) { my $p = open2(*Reader, *Writer, '/usr/local/sbin/mkntpwd', '-f', '-'); print Writer $_[0], "\n"; #close Writer; my $pass = <Reader>; chomp $pass; my @passes = split /:/, $pass; return @passes; } #print mkntpwd("HI"), "\n"; #print mkntpwd("IH"), "\n"; sub changepass ($$$$) { my $user = $_[0]; my $oldpass = $_[1]; my $newpass = $_[2]; my $newpassconfirm = $_[3]; if ($user !~ /^[a-zA-Z][a-zA-Z0-9]*$/) { sleep 4; return "user name contains illegal symbols"; } if ($oldpass eq '') { sleep 4; return "null password for user $user", "authentication failed"; } if ($newpass ne $newpassconfirm) { return "new passwords don't match for user $user", "new passwords don't match"; } my $salt = '$1$'; for my $i (1..8) { $salt .= $pwchars[rand($#pwchars + 1)]; } #print "salt is $salt\n"; my $cryptedpass = crypt($newpass, $salt); my $lmpasswd; my $ntpasswd; ($lmpasswd,$ntpasswd) = mkntpwd ($newpass); my $Reader; my $Writer; my $Error; my $p = open3($Writer, $Reader, $Error, '/usr/bin/ldapmodify', '-ZZ', '-h', $config_ldapserver, '-D', "uid=$user" . $config_basedn, '-x', '-W'); my $select = IO::Select->new($Reader, $Error); my $line; my $sock; my $timeout = time() + 1; do { my @ready = $select->can_read(5); foreach my $s (@ready) { # foreach is implicity local! $sock = $s; if ($sock == $Reader) { last; } else { # something on wrong stream $line = ''; my $l; my $read = 0; do { $read = sysread($sock, $l, 1024); $line .= $l; } while (defined $read && ($read != 0 ^ $read != 1024)); syslog('err', "Error: ldapmodify said \"%s\" on stderr while we expected a password prompt", $line); } } } while ((!defined $sock || $Reader != $sock) && time() < $timeout); if ($sock != $Reader) { return "Timed out waiting for ldapmodify for user $user", "internal error 3: timed out"; } sysread($Reader, $line, 30); if ($line !~ /^Enter LDAP Password:/) { return "internal error 1"; } else { print $Writer "$oldpass\n"; } $timeout = time() + 2; do { my @ready = $select->can_read(2); foreach my $s (@ready) { $sock = $s; #if ($sock == $Error) { $line = ''; my $l; while (sysread($sock, $l, 1024)) { $line .= $l; } sleep 4; return "bad password for user $user: $line", "authentication failed"; #} } } while (time() < $timeout); syslog("notice", "authenticated user $user"); print $Writer "dn: uid=$user,ou=People,dc=umnh,dc=utah,dc=edu\n"; print $Writer "userPassword: {CRYPT}$cryptedpass\n"; print $Writer "lmPassword: $lmpasswd\n"; print $Writer "ntPassword: $ntpasswd\n"; print $Writer "\n"; close $Writer; $timeout = time() + 5; do { my @ready = $select->can_read(5); foreach my $s (@ready) { $sock = $s; #if ($sock == $Reader) { $line = ''; my $l; while (sysread($sock, $l, 1024)) { $line .= $l; } if ($line =~ /^\s*modifying entry/) { syslog("notice", "Set new password for user $user"); return 1; } else { return "Modify failed for user $user: $line", "internal error 2"; } #} } } while (time() < $timeout); return "Timed out modifying for user $user", "internal error 4: timed out"; #return 1; } #changepass ('a', 'b', 'c'); sub printmenu { my $c = $_[0]; shift @_; print $c->header(); print $c->start_html(-title=>$config_title, -color=>"black", -bgcolor=>"white"); print $c->h1($config_title); if ($#_ >= 0) { foreach my $e (@_) { print $c->p("<font color=\"red\">Error: $e</font>"); } } print $c->start_form(-method=>"POST"); print $c->table({-border=>'none'}, $c->Tr([ $c->td(["Username: ", $c->textfield(-name=>"username")]), $c->td(["Old password: ", $c->password_field(-name=>"oldpass", -override=>1)]), $c->td(["New password: ", $c->password_field(-name=>"newpass1", -override=>1)]), $c->td(["Confirm new password: ", $c->password_field(-name=>"newpass2", -override=>1)]), ]) ); print $c->submit(-name=>"submitbutton", -value=>"Change password", -content=>"Change password"); print $c->end_form(); print $c->end_html(); print "\n"; } #printmenu($q); sub printsuccess ($) { my $c = $_[0]; print $c->header(); print $c->start_html(-title=>$config_title, -color=>"black", -bgcolor=>"white"); print $c->h1($config_title); print $c->p("Your password has been changed."); print $c->p($c->a({-href=>"/"}, "Return")); print $c->end_html(); print "\n"; } sub doaction($) { my $q = $_[0]; my $user = $q->param("username"); my $oldpass = $q->param("oldpass"); my $newpass1 = $q->param("newpass1"); my $newpass2 = $q->param("newpass2"); my @r = changepass($user, $oldpass, $newpass1, $newpass2); if ($r[0] eq 1) { printsuccess($q); } else { syslog('warning', '%s failed to change password: %s', $q->remote_host(), $r[0]); if (defined $r[1]) { printmenu($q, $r[1]); } else { printmenu($q, $r[0]); } } } #my $q = new CGI; #printsuccess($q) my $q = new CGI; openlog("webpwchanger", "pid", "LOG_AUTH"); if (defined $q->param('submitbutton')) { doaction($q); } else { printmenu($q); }