1 #!/usr/pkg/bin/perl 2 # 3 # Sample password verifier for Heimdals external password 4 # verifier, see the chapter "Password changing" in the the info 5 # documentation for more information about the protocol used. 6 # 7 # Three checks 8 # 1. Check that password is not the principal name 9 # 2. Check that the password passes cracklib 10 # 3. Check that password isn't repeated for this principal 11 # 12 # The repeat check must be last because some clients ask 13 # twice when getting "no" back and thus the error message 14 # would be wrong. 15 # 16 # Prereqs (example versions): 17 # 18 # * perl (5.8.5) http://www.perl.org/ 19 # * cracklib (2.8.5) http://sourceforge.net/projects/cracklib 20 # * Crypt-Cracklib perlmodule (0.01) http://search.cpan.org/~daniel/ 21 # 22 # Sample dictionaries: 23 # cracklib-words (1.1) http://sourceforge.net/projects/cracklib 24 # miscfiles (1.4.2) http://directory.fsf.org/miscfiles.html 25 # 26 # Configuration for krb5.conf or kdc.conf 27 # 28 # [password_quality] 29 # policies = builtin:external-check 30 # external_program = <your-path>/check-cracklib.pl 31 # 32 # Id 33 34 use strict; 35 use Crypt::Cracklib; 36 use Digest::MD5; 37 38 # NEED TO CHANGE THESE TO MATCH YOUR SYSTEM 39 my $database = '/usr/lib/cracklib_dict'; 40 my $historydb = '/var/heimdal/historydb'; 41 # NEED TO CHANGE THESE TO MATCH YOUR SYSTEM 42 43 # seconds password reuse allowed (to catch retries from clients) 44 my $reusetime = 60; 45 46 my %params; 47 48 sub check_basic 49 { 50 my $principal = shift; 51 my $passwd = shift; 52 53 if ($principal eq $passwd) { 54 return "Principal name as password is not allowed"; 55 } 56 return "ok"; 57 } 58 59 sub check_repeat 60 { 61 my $principal = shift; 62 my $passwd = shift; 63 my $result = 'Do not reuse passwords'; 64 my %DB; 65 my $md5context = new Digest::MD5; 66 my $timenow = scalar(time()); 67 68 $md5context->reset(); 69 $md5context->add($principal, ":", $passwd); 70 71 my $key=$md5context->hexdigest(); 72 73 dbmopen(%DB,$historydb,0600) or die "Internal: Could not open $historydb"; 74 if (!$DB{$key} || ($timenow - $DB{$key} < $reusetime)) { 75 $result = "ok"; 76 $DB{$key}=$timenow; 77 } 78 dbmclose(%DB) or die "Internal: Could not close $historydb"; 79 return $result; 80 } 81 82 sub badpassword 83 { 84 my $reason = shift; 85 print "$reason\n"; 86 exit 0 87 } 88 89 while (<STDIN>) { 90 last if /^end$/; 91 if (!/^([^:]+): (.+)$/) { 92 die "key value pair not correct: $_"; 93 } 94 $params{$1} = $2; 95 } 96 97 die "missing principal" if (!defined $params{'principal'}); 98 die "missing password" if (!defined $params{'new-password'}); 99 100 my $reason; 101 102 $reason = check_basic($params{'principal'}, $params{'new-password'}); 103 badpassword($reason) if ($reason ne "ok"); 104 105 $reason = fascist_check($params{'new-password'}, $database); 106 badpassword($reason) if ($reason ne "ok"); 107 108 $reason = check_repeat($params{'principal'}, $params{'new-password'}); 109 badpassword($reason) if ($reason ne "ok"); 110 111 print "APPROVED\n"; 112 exit 0 113