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
|
---|