[Da-tools-commits] ./debian/userdir-ldap-cgi r109: Implement password quality checking in update
Peter Palfrader
peter at palfrader.org
Mon Sep 15 13:26:52 UTC 2008
------------------------------------------------------------
revno: 109
committer: Peter Palfrader <peter at palfrader.org>
branch nick: userdir-ldap-cgi
timestamp: Mon 2008-09-15 15:26:52 +0200
message:
Implement password quality checking in update
modified:
Util.pm
update.cgi
-------------- next part --------------
=== modified file 'Util.pm'
--- a/Util.pm 2008-05-25 16:27:04 +0000
+++ b/Util.pm 2008-09-15 13:26:52 +0000
@@ -1,9 +1,14 @@
# -*- perl -*-x
+
+# Copyright (c) 1999-2006 Debian Admin Team Members and Developers (taken from debian/copyright in 2008 by weasel)
+# Copyright (c) 2002, 2003, 2004, 2008 Peter Palfrader
+
package Util;
use strict;
use Date::Manip qw(ParseDate);
use Net::LDAP qw(:all);
+use English;
my $blocksize = 8; # A blowfish block is 8 bytes
my $configfile = "/etc/userdir-ldap/userdir-ldap.conf";
@@ -353,4 +358,122 @@
exit(1);
};
};
+
+sub readwrite3($$$$) {
+ my ($in, $inputfd, $stdoutfd, $stderrfd) = @_;
+
+ #Echolot::Log::trace("Entering readwrite_gpg.");
+
+ local $INPUT_RECORD_SEPARATOR = undef;
+ my $sout = IO::Select->new();
+ my $sin = IO::Select->new();
+ my $offset = 0;
+
+ #Echolot::Log::trace("input is $inputfd; output is $stdoutfd; err is $stderrfd; status is ".(defined $statusfd ? $statusfd : 'undef').".");
+
+ $inputfd->blocking(0);
+ $stdoutfd->blocking(0);
+ $stderrfd->blocking(0);
+ $sout->add($stdoutfd);
+ $sout->add($stderrfd);
+ $sin->add($inputfd);
+
+ my ($stdout, $stderr) = ("", "", "");
+
+ my ($readyr, $readyw);
+ while ($sout->count() > 0 || (defined($sin) && ($sin->count() > 0))) {
+ #Echolot::Log::trace("select waiting for ".($sout->count())." fds.");
+ ($readyr, $readyw, undef) = IO::Select::select($sout, $sin, undef, 42);
+ #Echolot::Log::trace("ready: write: ".(defined $readyw ? scalar @$readyw : 'none')."; read: ".(defined $readyr ? scalar @$readyr : 'none'));
+ for my $wfd (@$readyw) {
+ #Echolot::Log::trace("writing to $wfd.");
+ my $written = 0;
+ if ($offset != length($in)) {
+ $written = $wfd->syswrite($in, length($in) - $offset, $offset);
+ }
+ unless (defined ($written)) {
+ #Echolot::Log::warn("Error while writing to GnuPG: $!");
+ close $wfd;
+ $sin->remove($wfd);
+ $sin = undef;
+ } else {
+ $offset += $written;
+ if ($offset == length($in)) {
+ #Echolot::Log::trace("writing to $wfd done.");
+ close $wfd;
+ $sin->remove($wfd);
+ $sin = undef;
+ }
+ }
+ }
+
+ next unless (defined(@$readyr)); # Wait some more.
+
+ for my $rfd (@$readyr) {
+ if ($rfd->eof) {
+ #Echolot::Log::trace("reading from $rfd done.");
+ $sout->remove($rfd);
+ close($rfd);
+ next;
+ }
+ #Echolot::Log::trace("reading from $rfd.");
+ if ($rfd == $stdoutfd) {
+ $stdout .= <$rfd>;
+ next;
+ }
+ if ($rfd == $stderrfd) {
+ $stderr .= <$rfd>;
+ next;
+ }
+ }
+ }
+ #Echolot::Log::trace("readwrite_gpg done.");
+ return ($stdout, $stderr);
+};
+
+sub checkPasswordQuality($$$) {
+ my ($pw, $oldpw, $ldapelements) = @_;
+ my ($stdinR, $stdinW) = (IO::Handle->new(), IO::Handle->new());
+ my ($stdoutR, $stdoutW) = (IO::Handle->new(), IO::Handle->new());
+ my ($stderrR, $stderrW) = (IO::Handle->new(), IO::Handle->new());
+ pipe $stdinR, $stdinW;
+ pipe $stdoutR, $stdoutW;
+ pipe $stderrR, $stderrW;
+
+ my $pid = fork();
+ unless (defined $pid) {
+ return (2, "Could not fork: $!");
+ };
+ unless ($pid) { # child
+ $stdinW->close;
+ $stdoutR->close;
+ $stderrR->close;
+ close STDIN;
+ close STDOUT;
+ close STDERR;
+ open (STDIN, "<&".$stdinR->fileno) or warn ("Cannot dup stdinR (fd ".$stdinR->fileno.") as STDIN: $!");
+ open (STDOUT, ">&".$stdoutW->fileno) or warn ("Cannot dup stdoutW (fd ".$stdoutW->fileno.") as STDOUT: $!");
+ open (STDERR, ">&".$stderrW->fileno) or warn ("Cannot dup stderrW (fd ".$stderrW->fileno.") as STDERR: $!");
+ { exec('/usr/lib/userdir-ldap-cgi/password-qualify-check'); }
+ $stderrW->print("Could not exec password-qualify-check: $!\n");
+ exit(1);
+ };
+ $stdinR->close;
+ $stdoutW->close;
+ $stderrW->close;
+
+ $oldpw = '' unless defined $oldpw;
+ my $out = join("\n", $pw, $oldpw, @$ldapelements)."\n";
+ my ($stdout, $stderr) = readwrite3($out, $stdinW, $stdoutR, $stderrR);
+ waitpid $pid, 0;
+
+ my $exitcode = $? >> 8;
+ if ($exitcode == 0 && $stdout eq '' && $stderr eq '') {
+ return (0, "ok");
+ } elsif ($exitcode == 1 && $stderr eq '') {
+ return (1, $stdout);
+ } else {
+ return (2, "check exited with exit code $exitcode, said '$stdout' on stdout, and '$stderr' on stderr.");
+ };
+};
1;
=== modified file 'update.cgi'
--- a/update.cgi 2008-09-14 22:48:37 +0000
+++ b/update.cgi 2008-09-15 13:26:52 +0000
@@ -119,8 +119,8 @@
. '>female</select>';
my $confirmstring = '';
my $sudopassword = '';
- for my $entry (@{$entry->{'sudopassword'}}) {
- my ($uuid, $status, $hosts, $crypted) = ($entry =~ /^([0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}) (confirmed:[0-9a-f]{40}|unconfirmed) ([a-z0-9.,*]+) ([^ ]+)$/);
+ for my $e(@{$entry->{'sudopassword'}}) {
+ my ($uuid, $status, $hosts, $crypted) = ($e =~ /^([0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}) (confirmed:[0-9a-f]{40}|unconfirmed) ([a-z0-9.,*]+) ([^ ]+)$/);
unless (defined $uuid) {
$sudopassword .= "<tr><td>Unparseable line!</td></tr>\n";
next;
@@ -165,6 +165,14 @@
}
close F;
} else {
+ my @ldapinfo_for_pwcheck;
+ for my $a (qw{cn sn md gecos uid}) {
+ for my $e (@{$entry->{$a}}) {
+ push @ldapinfo_for_pwcheck, $e;
+ }
+ }
+
+
# Actually update stuff...
my ($newpassword, $newstaddress);
@@ -179,7 +187,13 @@
if ($query->param('newpass') ne $query->param('newpassvrfy')) {
# passwords don't match...
&Util::HTMLError("The passwords you specified do not match. Please go back and try again.");
- }
+ }
+
+ my ($r, $msg) = &Util::checkPasswordQuality($query->param('newpass'), undef, [@ldapinfo_for_pwcheck]);
+ if ($r) {
+ &Util::HTMLError("Password check failed: $msg. Please go back and try again.");
+ }
+
# create a md5 crypted password
$newpassword = '{crypt}'.crypt($query->param('newpass'), &Util::CreateCryptSalt(1));
@@ -237,13 +251,23 @@
my $newsudo;
my $newsudo_hosts;
if ($query->param('newsudopass') && $query->param('newsudopassvrfy')) {
- if ($query->param('newsudopass') ne $query->param('newsudopassvrfy')) {
- &Util::HTMLError("The sudo passwords you specified do not match. Please go back and try again.");
- }
my $host = $query->param('newsudopass-host');
if ($host =~ /[^a-z0-9.-]/ and $host ne '*') {
&Util::HTMLError("The sudo host has weird characters '$host'.");
}
+
+ if ($query->param('newsudopass') ne $query->param('newsudopassvrfy')) {
+ &Util::HTMLError("The sudo passwords you specified do not match. Please go back and try again.");
+ }
+
+ my $ldappass = $password;
+ $ldappass = $query->param('newpass') if $query->param('newpass');
+ push @ldapinfo_for_pwcheck, $host, split(/\./, $host);
+ my ($r, $msg) = &Util::checkPasswordQuality($query->param('newsudopass'), $ldappass, [@ldapinfo_for_pwcheck]);
+ if ($r) {
+ &Util::HTMLError("Password check failed for new sudo pass: $msg. Please go back and try again.");
+ }
+
# create a md5 crypted password
my $newsudopassword = crypt($query->param('newsudopass'), &Util::CreateCryptSalt(1));
my $ug = new Data::UUID;
More information about the Da-tools-commits
mailing list