CGI para cambiar claves con Net::LDAP

Ernesto Hernandez-Novich emhn at telcel.net.ve
Tue Mar 18 15:42:35 CST 2003


On Tue, 18 Mar 2003, Luis M. Gallardo D. wrote:
> Ahora que esta funcionando para lo que lo pensi
> (administracisn de cuentas Linux/Samba) me voy a poner
> a estudiar la forma de usar el msdulo de perl-LDAP, y
> luego publicarlo bajo GPL ;-)

Escribí esto ésta tarde. Por lo menos funciona y es estricto con la
selección de claves para que el usuario no ponga sandeces.

#!/usr/bin/perl -w
#
# Requisitos:
#
# NET::LDAP
# Crypt::Cracklib
# Digest::SHA1
#
# apt-get install libnet-ldap-perl libcrypt-cracklib-perl libdigest-sha1-perl

use constant;
use CGI;
use Net::LDAP;
use Crypt::Cracklib;
use Digest::SHA1;

$|++;
my $ldapserver = "ldap.nuevomundo.seg";
my $basedn     = "dc=nuevomundo,dc=com,dc=ve";

my %translation = (
     "it is based on your username" =>
     "esta basada en su nombre de usuario",
     "it is based upon your password entry" =>
     "esta basada en su nombre completo",
     "it is derived from your password entry" =>
     "es derivada de su nombre completo",
     "it's derived from your password entry" =>
     "es derivada de su descripcion de usuario",
     "it is derivable from your password entry" =>
     "puede deducirse de su descripcion de usuario",
     "it's derivable from your password entry" =>
     "puede deducirse de su descripcion de usuario",
     "it's WAY too short" =>
     "es demasiado corta",
     "it is too short" =>
     "es muy corta",
     "it does not contain enough DIFFERENT characters" =>
     "no contiene suficientes caracteres diferentes",
     "it is all whitespace" =>
     "esta compuesta por espacios en blanco",
     "it is too simplistic/systematic" =>
     "es demasiado simple o sistematica",
     "it looks like a National Insurance number" =>
     "parece un numero de cedula",
     "it is based on a dictionary word" =>
     "esta basada en una palabra del diccionario",
     "it is based on a (reversed) dictionary word" =>
     "esta basada en invertir una palabra del diccionario",
     "ok" => "ok",
);

sub checkquality {
  my $p = shift;

  return("no tiene letras y numeros al mismo tiempo")
     unless $p =~ m/\w/ && $p =~ m/\d/;
  my $reason = fascist_check($p,"/var/cache/cracklib/cracklib_dict");
  return($translation{$reason});
}

sub showpage {
  my $q     = shift;
  my $login = shift;
  my $error = shift;

  print $q->header,
        $q->start_html( -title  => 'Cambiar clave',
	                -author => 'Ernesto Hernandez-Novich' ), "\n",
	$q->h1('Cambiar clave'), "\n",
	"Bla bla - password dificil - consejos...\n",
	$q->startform(), "\n",
	$q->start_table, "\n",
	$q->Tr, "\n",
	$q->td( { -align => 'right' },
	        "Usuario:"
	      ), "\n",
	$q->td( { -align => 'left'  },
	        $q->textfield( -name      => 'login',
		               -default   => $login,
			       -size      => 8,
			       -maxlength => 8)
	      ), "\n",
	$q->end_Tr, "\n",
	$q->Tr, "\n",
	$q->td( { -align => 'right' },
	        "Clave actual:"
	      ), "\n",
	$q->td( { -align => 'left' },
	        $q->password_field( -name      => 'oldpass',
		                    -size      => 20,
				    -maxlength => 20)
	      ), "\n",
	$q->end_Tr, "\n",
	$q->Tr, "\n",
	$q->td( { -align => 'right' },
	        "Nueva Clave:"
	      ), "\n",
	$q->td( { -align => 'left' },
	        $q->password_field( -name      => 'newpass1',
		                    -size      => 20,
				    -maxlength => 20)
	      ), "\n",
	$q->end_Tr, "\n",
	$q->Tr, "\n",
	$q->td( { -align => 'right' },
	        "Repita la Nueva Clave"
	      ), "\n",
	$q->td( { -align => 'left' },
	        $q->password_field( -name      => 'newpass2',
		                    -size      => 20,
				    -maxlength => 20)
	      ), "\n",
	$q->end_Tr, "\n",
	$q->Tr, "\n",
	$q->td( { -colspan => '2',
	          -align   => 'center' },
		$q->submit( -value => 'Cambiar')
	      ), "\n",
	$q->end_Tr, "\n",
	$q->end_table, "\n",
	$q->endform, "\n",
	$q->end_table, "\n",
	$q->p;
  if (defined($error)) {
    print $error, $q->p;
  }
  print $q->end_html;
}

# Rutinas para interactuar con LDAP

sub checkandchange {
  my $uid     = shift;
  my $oldpass = shift;
  my $newpass = shift;
  my $ldap    = Net::LDAP->new($ldapserver);
  my $binddn  = "uid=$uid,ou=People,$basedn";

  if ($ldap) {
    if ($ldap->bind) {
      if ($ldap->search(base => $basedn, filter => "(uid=$uid)")->count) {
        $ldap->unbind;
        $ldap = Net::LDAP->new($ldapserver);
        if ($ldap->bind($binddn, password => $oldpass)->code) {
          $ldap->unbind;
          return 2;
        } else {
	  my $h = Digest::SHA1->new;
	  my $p = "{SHA}";
	  $h->add($newpass);
	  $p .= $h->b64digest . "=";
	  if ($ldap->modify($binddn,
	                    replace => { 'userPassword' => $p }
			   )->code) {
	    $ldap->unbind;
	    return 3;
	  } else {;
            $ldap->unbind;
            return 0;
	  }
        }
        return (1,undef);
      } else {
        $ldap->unbind;
        return 1;
      }
    } else {
      return 5;
    }
  } else {
    return 4;
  }
}

# Rutinas para reaccionar ante los posibles errores.

sub nologin {
  my $q = shift;

  showpage($q,undef,'¡No indicó su nombre de usuario!');
  exit(0);
}

sub nooldpass {
  my $q = shift;

  showpage($q,undef,'¡No indicó su clave actual!');
  exit(0);
}

sub nonewpass {
  my $q = shift;

  showpage($q,undef,'¡No indicó la clave nueva dos veces!');
  exit(0);
}

sub newnomatch {
  my $q = shift;

  showpage($q,undef,'¡Las claves nuevas no coinciden!');
  exit(0);
}

sub weakpass {
  my $q = shift;
  my $r = shift;

  showpage($q,undef,"La nueva clave ha sido rechazada porque $r.");
  exit(0);
}

my $q = new CGI;
if ($q->param) {
  my ($login,$oldpass,$newpass1,$newpass2)
     = map { $q->param($_) } ( 'login', 'oldpass', 'newpass1', 'newpass2' );

  # Verificamos que no falte nada

  nologin($q)     unless $login;
  nooldpass($q)   unless $oldpass;
  nonewpass($q)   unless ($newpass1 && $newpass2);
  newnomatch($q)  unless ($newpass1 eq $newpass2);

  # Verificamos que la nueva clave cumpla con los standards de calidad
  # de organismos pluricelulares.

  my $reason = checkquality($newpass1);
  weakpass($q,$reason) unless $reason eq 'ok';

  # Verificamos que el usuario exista, su clave actual sea correcta
  # y procedemos con el cambio.

  my $result = "";
  for (checkandchange($login,$oldpass,$newpass1)) {
    /^0$/ and do { $result = "La clave de $login fue cambiada exitosamente.";
                   last;
		 };
    /^1$/ and do { $result = "El usuario $login no existe";
                   last;
		 };
    /^2$/ and do { $result = "La clave actual es incorrecta";
                   last;
		 };
    /^3$/ and do { $result = "No se pudo cambiar la clave";
                   last;
		 };
    /^4$/ and do { $result = "No puedo conectarme a $ldapserver";
                   last;
		 };
    /^5$/ and do { $result = "No puedo conectarme anonimamente a $ldapserver";
                   last;
		 };
  }
  showpage($q,$login,$result);
} else {
  showpage($q,undef,"Por favor complete los datos");
}
-- 
Ernesto Hernández-Novich - Running Linux 2.4.19 i686 - Unix: Live free or die!
Geek by nature, Linux by choice, Debian of course.
If you can't apt-get it, it isn't useful or doesn't exist.
GPG Key Fingerprint = 438C 49A2 A8C7 E7D7 1500 C507 96D6 A3D6 2F4C 85E3

------------------------------------------------------------------------
Enviar e-mail a <majordomo at pm.org> colocando en el cuerpo:
"UNSUBSCRIBE caracas-pm-list" para desuscribirse.
"INFO caracas-pm-list" para conocer las reglas de etiqueta.
------------------------------------------------------------------------



More information about the caracas-pm mailing list