Revert "drop overrids - LDAP has it on its own"
[mirror/userdir-ldap-cgi.git] / Util.pm
diff --git a/Util.pm b/Util.pm
index 2b5b266..27060d7 100644 (file)
--- a/Util.pm
+++ b/Util.pm
@@ -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 Net::LDAP qw(LDAP_SUCCESS LDAP_PROTOCOL_ERROR);
+use English;
 
 my $blocksize = 8; # A blowfish block is 8 bytes
 my $configfile = "/etc/userdir-ldap/userdir-ldap.conf";
@@ -28,21 +33,26 @@ sub CreateKey {
 }
 
 sub CreateCryptSalt {
+  # CreateCryptSalt(type = 0, skip_header = 0)
   # this can create either a DES type salt or a MD5 salt
+  # 0 for DES, 1 for MD5 salt
+  # if skip_header is 0, does not add $1$ for md5 salts.
   my $md5 = shift; # do we want a MD5 salt?
+  my $no_crypttype_header = shift;
   my $validstr = './0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
   my @valid = split(//,$validstr);
   my ($in, $out);
-  
+
   my $cryptsaltlen = ($md5 ? 8 : 2);
-  
+
   open (F, "</dev/urandom") || die &HTMLError("No /dev/urandom found!");
   foreach (1..$cryptsaltlen) {
     read(F, $in, 1);
     $out .= $valid[ord($in) % ($#valid + 1)];
   }
   close F;
-  return ($md5 ? "\$1\$$out\$" : $out);
+  if ($md5 == 1 && !$no_crypttype_header) { $out = "\$1\$$out\$"; }
+  return $out
 }
 
 sub Encrypt { 
@@ -223,16 +233,21 @@ sub FormatLastSeen {
   my ($d1, $d2, $lastseen);
 
   return "<b>No activity detected</b>" if (!$lastseenpgp && !$lastseenfrom);
+  $lastseen = $lastseenpgp;
   $lastseen = $lastseenfrom if (!$lastseenpgp);
 
   if ($lastseenfrom && $lastseenpgp) {
-    ($d1) = ($lastseenpgp =~ /^\[(.+?)\]/); $d1 = ParseDate($d1);  
+    ($d1) = ($lastseenpgp =~ /^\[(.+?)\]/); $d1 = ParseDate($d1);
     ($d2) = ($lastseenfrom =~ /^\[(.+?)\]/); $d2 = ParseDate($d2);
     $lastseen = (($d1 gt $d2) ? $lastseenpgp : $lastseenfrom);
   }
 
-  my ($date,$user,$list,$msgid) = ($lastseen =~ /^\[(.+?)\]\s+"(.+?)"\s+"(?:<(.+?)>.*?|\-)"\s+"<(.+?)>"/);
+  my ($date,$user,$list,$msgid) = ($lastseen =~ /^\[(.+?)\]\s+"(.+?)"\s+"(?:<(.+?)>.*?|\-)"\s+"(<.+?>)"/);
   $list = "on $list" if ($list);
+  $date = CGI::escapeHTML($date);
+  $user = CGI::escapeHTML($user);
+  $list = CGI::escapeHTML($list);
+  $msgid = CGI::escapeHTML($msgid);
   return "$date $list<br>&nbsp;Message ID: $msgid";
 }
 
@@ -344,13 +359,131 @@ sub UpgradeConnection($) {
   my ($ldap) = @_;
   my $mesg = $ldap->start_tls(
                           verify => 'require',
-                          capath => '/etc/ssl/certs/'
+                          cafile => '/etc/ssl/certs/spi-cacert-2008.pem'
                           );
   $mesg->sync;
   if ($mesg->code != LDAP_SUCCESS) {
     print "Content-type: text/html; charset=utf-8\n\n";
-    print "<html><body><h1>STARTTLS failed: "..$mesg->error."</h1></body></html>\n";
+    print "<html><body><h1>STARTTLS failed: ".$mesg->error."</h1></body></html>\n";
+    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;