]> eyrie.org Git - kerberos/krb5-strength.git/blob - cracklib/fascist.c
Merge branch 'debian' into squeeze
[kerberos/krb5-strength.git] / cracklib / fascist.c
1 /*
2  * This program is copyright Alec Muffett 1993. The author disclaims all
3  * responsibility or liability with respect to it's usage or its effect
4  * upon hardware or computer systems, and maintains copyright as set out
5  * in the "LICENCE" document which accompanies distributions of Crack v4.0
6  * and upwards.
7  */
8
9 /*
10  * Modified as part of the krb5-strength project as follows:
11  *
12  * 2007-03-22  Russ Allbery <eagle@eyrie.org>
13  *   - Add four-, five-, and six-character prefix and suffix rules.
14  *   - Longer passwords must contain more different characters, up to 8.
15  *   - Disable GECOS checking (useless for a server).
16  *   - Replace exit(-1) with return when dictionary doesn't exist.
17  *   - Additional system includes for other functions.
18  * 2009-10-14  Russ Allbery <eagle@eyrie.org>
19  *   - Add ANSI C protototypes for all functions.
20  *   - Tweaks for const cleanliness.
21  *   - Add parentheses around assignment used for its truth value.
22  *   - Change a variable to unsigned int to avoid gcc warnings.
23  *   - Remove the unused FascistGecos function.
24  * 2012-05-11  Russ Allbery <eagle@eyrie.org>
25  *   - Change MINLENGTH to 8.
26  *   - Use a separate buffer to hold the reversed password.
27  *   - Also check whether a password is a duplicated dictionary word.
28  * 2013-09-24  Russ Allbery <eagle@eyrie.org>
29  *   - Replaced MAXSTEP with allowing one increment per four characters.
30  *   - Changed error for very short passwords to match current CrackLib.
31  *   - Close the dictionary after each password lookup.
32  */
33
34 static const char vers_id[] = "fascist.c : v2.3p3 Alec Muffett 14 dec 1997";
35
36 #include "packer.h"
37 #include <sys/types.h>
38 #include <pwd.h>
39 #include <string.h>
40 #include <stdlib.h>
41 #include <unistd.h>
42
43 #define ISSKIP(x) (isspace(x) || ispunct(x))
44
45 #define MINDIFF 5
46 #define MINLEN 8
47 #define MAXMINDIFF 8
48
49 #undef DEBUG
50 #undef DEBUG2
51
52 static const char *r_destructors[] = {
53     ":",                        /* noop - must do this to test raw word. */
54
55 #ifdef DEBUG2
56     (char *) 0,
57 #endif
58
59     "[",                        /* trimming leading/trailing junk */
60     "]",
61     "[[",
62     "]]",
63     "[[[",
64     "]]]", /* 5 for 8 char passwords */ 
65     /* This is for longer passwords, it should be based on length */ 
66     "]]]]", /* 6 for 10 char passwords */ 
67     "[[[[",
68     "]]]]]", /* 7 for 12 char passwords */ 
69     "[[[[[",
70     "]]]]]]", /* 8 for 14 char passwords */ 
71     "[[[[[[",
72
73     "/?p@?p",                   /* purging out punctuation/symbols/junk */
74     "/?s@?s",
75     "/?X@?X",
76
77     /* attempt reverse engineering of password strings */
78
79     "/$s$s",
80     "/$s$s/0s0o",
81     "/$s$s/0s0o/2s2a",
82     "/$s$s/0s0o/2s2a/3s3e",
83     "/$s$s/0s0o/2s2a/3s3e/5s5s",
84     "/$s$s/0s0o/2s2a/3s3e/5s5s/1s1i",
85     "/$s$s/0s0o/2s2a/3s3e/5s5s/1s1l",
86     "/$s$s/0s0o/2s2a/3s3e/5s5s/1s1i/4s4a",
87     "/$s$s/0s0o/2s2a/3s3e/5s5s/1s1i/4s4h",
88     "/$s$s/0s0o/2s2a/3s3e/5s5s/1s1l/4s4a",
89     "/$s$s/0s0o/2s2a/3s3e/5s5s/1s1l/4s4h",
90     "/$s$s/0s0o/2s2a/3s3e/5s5s/4s4a",
91     "/$s$s/0s0o/2s2a/3s3e/5s5s/4s4h",
92     "/$s$s/0s0o/2s2a/3s3e/5s5s/4s4a",
93     "/$s$s/0s0o/2s2a/3s3e/5s5s/4s4h",
94     "/$s$s/0s0o/2s2a/3s3e/1s1i",
95     "/$s$s/0s0o/2s2a/3s3e/1s1l",
96     "/$s$s/0s0o/2s2a/3s3e/1s1i/4s4a",
97     "/$s$s/0s0o/2s2a/3s3e/1s1i/4s4h",
98     "/$s$s/0s0o/2s2a/3s3e/1s1l/4s4a",
99     "/$s$s/0s0o/2s2a/3s3e/1s1l/4s4h",
100     "/$s$s/0s0o/2s2a/3s3e/4s4a",
101     "/$s$s/0s0o/2s2a/3s3e/4s4h",
102     "/$s$s/0s0o/2s2a/3s3e/4s4a",
103     "/$s$s/0s0o/2s2a/3s3e/4s4h",
104     "/$s$s/0s0o/2s2a/5s5s",
105     "/$s$s/0s0o/2s2a/5s5s/1s1i",
106     "/$s$s/0s0o/2s2a/5s5s/1s1l",
107     "/$s$s/0s0o/2s2a/5s5s/1s1i/4s4a",
108     "/$s$s/0s0o/2s2a/5s5s/1s1i/4s4h",
109     "/$s$s/0s0o/2s2a/5s5s/1s1l/4s4a",
110     "/$s$s/0s0o/2s2a/5s5s/1s1l/4s4h",
111     "/$s$s/0s0o/2s2a/5s5s/4s4a",
112     "/$s$s/0s0o/2s2a/5s5s/4s4h",
113     "/$s$s/0s0o/2s2a/5s5s/4s4a",
114     "/$s$s/0s0o/2s2a/5s5s/4s4h",
115     "/$s$s/0s0o/2s2a/1s1i",
116     "/$s$s/0s0o/2s2a/1s1l",
117     "/$s$s/0s0o/2s2a/1s1i/4s4a",
118     "/$s$s/0s0o/2s2a/1s1i/4s4h",
119     "/$s$s/0s0o/2s2a/1s1l/4s4a",
120     "/$s$s/0s0o/2s2a/1s1l/4s4h",
121     "/$s$s/0s0o/2s2a/4s4a",
122     "/$s$s/0s0o/2s2a/4s4h",
123     "/$s$s/0s0o/2s2a/4s4a",
124     "/$s$s/0s0o/2s2a/4s4h",
125     "/$s$s/0s0o/3s3e",
126     "/$s$s/0s0o/3s3e/5s5s",
127     "/$s$s/0s0o/3s3e/5s5s/1s1i",
128     "/$s$s/0s0o/3s3e/5s5s/1s1l",
129     "/$s$s/0s0o/3s3e/5s5s/1s1i/4s4a",
130     "/$s$s/0s0o/3s3e/5s5s/1s1i/4s4h",
131     "/$s$s/0s0o/3s3e/5s5s/1s1l/4s4a",
132     "/$s$s/0s0o/3s3e/5s5s/1s1l/4s4h",
133     "/$s$s/0s0o/3s3e/5s5s/4s4a",
134     "/$s$s/0s0o/3s3e/5s5s/4s4h",
135     "/$s$s/0s0o/3s3e/5s5s/4s4a",
136     "/$s$s/0s0o/3s3e/5s5s/4s4h",
137     "/$s$s/0s0o/3s3e/1s1i",
138     "/$s$s/0s0o/3s3e/1s1l",
139     "/$s$s/0s0o/3s3e/1s1i/4s4a",
140     "/$s$s/0s0o/3s3e/1s1i/4s4h",
141     "/$s$s/0s0o/3s3e/1s1l/4s4a",
142     "/$s$s/0s0o/3s3e/1s1l/4s4h",
143     "/$s$s/0s0o/3s3e/4s4a",
144     "/$s$s/0s0o/3s3e/4s4h",
145     "/$s$s/0s0o/3s3e/4s4a",
146     "/$s$s/0s0o/3s3e/4s4h",
147     "/$s$s/0s0o/5s5s",
148     "/$s$s/0s0o/5s5s/1s1i",
149     "/$s$s/0s0o/5s5s/1s1l",
150     "/$s$s/0s0o/5s5s/1s1i/4s4a",
151     "/$s$s/0s0o/5s5s/1s1i/4s4h",
152     "/$s$s/0s0o/5s5s/1s1l/4s4a",
153     "/$s$s/0s0o/5s5s/1s1l/4s4h",
154     "/$s$s/0s0o/5s5s/4s4a",
155     "/$s$s/0s0o/5s5s/4s4h",
156     "/$s$s/0s0o/5s5s/4s4a",
157     "/$s$s/0s0o/5s5s/4s4h",
158     "/$s$s/0s0o/1s1i",
159     "/$s$s/0s0o/1s1l",
160     "/$s$s/0s0o/1s1i/4s4a",
161     "/$s$s/0s0o/1s1i/4s4h",
162     "/$s$s/0s0o/1s1l/4s4a",
163     "/$s$s/0s0o/1s1l/4s4h",
164     "/$s$s/0s0o/4s4a",
165     "/$s$s/0s0o/4s4h",
166     "/$s$s/0s0o/4s4a",
167     "/$s$s/0s0o/4s4h",
168     "/$s$s/2s2a",
169     "/$s$s/2s2a/3s3e",
170     "/$s$s/2s2a/3s3e/5s5s",
171     "/$s$s/2s2a/3s3e/5s5s/1s1i",
172     "/$s$s/2s2a/3s3e/5s5s/1s1l",
173     "/$s$s/2s2a/3s3e/5s5s/1s1i/4s4a",
174     "/$s$s/2s2a/3s3e/5s5s/1s1i/4s4h",
175     "/$s$s/2s2a/3s3e/5s5s/1s1l/4s4a",
176     "/$s$s/2s2a/3s3e/5s5s/1s1l/4s4h",
177     "/$s$s/2s2a/3s3e/5s5s/4s4a",
178     "/$s$s/2s2a/3s3e/5s5s/4s4h",
179     "/$s$s/2s2a/3s3e/5s5s/4s4a",
180     "/$s$s/2s2a/3s3e/5s5s/4s4h",
181     "/$s$s/2s2a/3s3e/1s1i",
182     "/$s$s/2s2a/3s3e/1s1l",
183     "/$s$s/2s2a/3s3e/1s1i/4s4a",
184     "/$s$s/2s2a/3s3e/1s1i/4s4h",
185     "/$s$s/2s2a/3s3e/1s1l/4s4a",
186     "/$s$s/2s2a/3s3e/1s1l/4s4h",
187     "/$s$s/2s2a/3s3e/4s4a",
188     "/$s$s/2s2a/3s3e/4s4h",
189     "/$s$s/2s2a/3s3e/4s4a",
190     "/$s$s/2s2a/3s3e/4s4h",
191     "/$s$s/2s2a/5s5s",
192     "/$s$s/2s2a/5s5s/1s1i",
193     "/$s$s/2s2a/5s5s/1s1l",
194     "/$s$s/2s2a/5s5s/1s1i/4s4a",
195     "/$s$s/2s2a/5s5s/1s1i/4s4h",
196     "/$s$s/2s2a/5s5s/1s1l/4s4a",
197     "/$s$s/2s2a/5s5s/1s1l/4s4h",
198     "/$s$s/2s2a/5s5s/4s4a",
199     "/$s$s/2s2a/5s5s/4s4h",
200     "/$s$s/2s2a/5s5s/4s4a",
201     "/$s$s/2s2a/5s5s/4s4h",
202     "/$s$s/2s2a/1s1i",
203     "/$s$s/2s2a/1s1l",
204     "/$s$s/2s2a/1s1i/4s4a",
205     "/$s$s/2s2a/1s1i/4s4h",
206     "/$s$s/2s2a/1s1l/4s4a",
207     "/$s$s/2s2a/1s1l/4s4h",
208     "/$s$s/2s2a/4s4a",
209     "/$s$s/2s2a/4s4h",
210     "/$s$s/2s2a/4s4a",
211     "/$s$s/2s2a/4s4h",
212     "/$s$s/3s3e",
213     "/$s$s/3s3e/5s5s",
214     "/$s$s/3s3e/5s5s/1s1i",
215     "/$s$s/3s3e/5s5s/1s1l",
216     "/$s$s/3s3e/5s5s/1s1i/4s4a",
217     "/$s$s/3s3e/5s5s/1s1i/4s4h",
218     "/$s$s/3s3e/5s5s/1s1l/4s4a",
219     "/$s$s/3s3e/5s5s/1s1l/4s4h",
220     "/$s$s/3s3e/5s5s/4s4a",
221     "/$s$s/3s3e/5s5s/4s4h",
222     "/$s$s/3s3e/5s5s/4s4a",
223     "/$s$s/3s3e/5s5s/4s4h",
224     "/$s$s/3s3e/1s1i",
225     "/$s$s/3s3e/1s1l",
226     "/$s$s/3s3e/1s1i/4s4a",
227     "/$s$s/3s3e/1s1i/4s4h",
228     "/$s$s/3s3e/1s1l/4s4a",
229     "/$s$s/3s3e/1s1l/4s4h",
230     "/$s$s/3s3e/4s4a",
231     "/$s$s/3s3e/4s4h",
232     "/$s$s/3s3e/4s4a",
233     "/$s$s/3s3e/4s4h",
234     "/$s$s/5s5s",
235     "/$s$s/5s5s/1s1i",
236     "/$s$s/5s5s/1s1l",
237     "/$s$s/5s5s/1s1i/4s4a",
238     "/$s$s/5s5s/1s1i/4s4h",
239     "/$s$s/5s5s/1s1l/4s4a",
240     "/$s$s/5s5s/1s1l/4s4h",
241     "/$s$s/5s5s/4s4a",
242     "/$s$s/5s5s/4s4h",
243     "/$s$s/5s5s/4s4a",
244     "/$s$s/5s5s/4s4h",
245     "/$s$s/1s1i",
246     "/$s$s/1s1l",
247     "/$s$s/1s1i/4s4a",
248     "/$s$s/1s1i/4s4h",
249     "/$s$s/1s1l/4s4a",
250     "/$s$s/1s1l/4s4h",
251     "/$s$s/4s4a",
252     "/$s$s/4s4h",
253     "/$s$s/4s4a",
254     "/$s$s/4s4h",
255     "/0s0o",
256     "/0s0o/2s2a",
257     "/0s0o/2s2a/3s3e",
258     "/0s0o/2s2a/3s3e/5s5s",
259     "/0s0o/2s2a/3s3e/5s5s/1s1i",
260     "/0s0o/2s2a/3s3e/5s5s/1s1l",
261     "/0s0o/2s2a/3s3e/5s5s/1s1i/4s4a",
262     "/0s0o/2s2a/3s3e/5s5s/1s1i/4s4h",
263     "/0s0o/2s2a/3s3e/5s5s/1s1l/4s4a",
264     "/0s0o/2s2a/3s3e/5s5s/1s1l/4s4h",
265     "/0s0o/2s2a/3s3e/5s5s/4s4a",
266     "/0s0o/2s2a/3s3e/5s5s/4s4h",
267     "/0s0o/2s2a/3s3e/5s5s/4s4a",
268     "/0s0o/2s2a/3s3e/5s5s/4s4h",
269     "/0s0o/2s2a/3s3e/1s1i",
270     "/0s0o/2s2a/3s3e/1s1l",
271     "/0s0o/2s2a/3s3e/1s1i/4s4a",
272     "/0s0o/2s2a/3s3e/1s1i/4s4h",
273     "/0s0o/2s2a/3s3e/1s1l/4s4a",
274     "/0s0o/2s2a/3s3e/1s1l/4s4h",
275     "/0s0o/2s2a/3s3e/4s4a",
276     "/0s0o/2s2a/3s3e/4s4h",
277     "/0s0o/2s2a/3s3e/4s4a",
278     "/0s0o/2s2a/3s3e/4s4h",
279     "/0s0o/2s2a/5s5s",
280     "/0s0o/2s2a/5s5s/1s1i",
281     "/0s0o/2s2a/5s5s/1s1l",
282     "/0s0o/2s2a/5s5s/1s1i/4s4a",
283     "/0s0o/2s2a/5s5s/1s1i/4s4h",
284     "/0s0o/2s2a/5s5s/1s1l/4s4a",
285     "/0s0o/2s2a/5s5s/1s1l/4s4h",
286     "/0s0o/2s2a/5s5s/4s4a",
287     "/0s0o/2s2a/5s5s/4s4h",
288     "/0s0o/2s2a/5s5s/4s4a",
289     "/0s0o/2s2a/5s5s/4s4h",
290     "/0s0o/2s2a/1s1i",
291     "/0s0o/2s2a/1s1l",
292     "/0s0o/2s2a/1s1i/4s4a",
293     "/0s0o/2s2a/1s1i/4s4h",
294     "/0s0o/2s2a/1s1l/4s4a",
295     "/0s0o/2s2a/1s1l/4s4h",
296     "/0s0o/2s2a/4s4a",
297     "/0s0o/2s2a/4s4h",
298     "/0s0o/2s2a/4s4a",
299     "/0s0o/2s2a/4s4h",
300     "/0s0o/3s3e",
301     "/0s0o/3s3e/5s5s",
302     "/0s0o/3s3e/5s5s/1s1i",
303     "/0s0o/3s3e/5s5s/1s1l",
304     "/0s0o/3s3e/5s5s/1s1i/4s4a",
305     "/0s0o/3s3e/5s5s/1s1i/4s4h",
306     "/0s0o/3s3e/5s5s/1s1l/4s4a",
307     "/0s0o/3s3e/5s5s/1s1l/4s4h",
308     "/0s0o/3s3e/5s5s/4s4a",
309     "/0s0o/3s3e/5s5s/4s4h",
310     "/0s0o/3s3e/5s5s/4s4a",
311     "/0s0o/3s3e/5s5s/4s4h",
312     "/0s0o/3s3e/1s1i",
313     "/0s0o/3s3e/1s1l",
314     "/0s0o/3s3e/1s1i/4s4a",
315     "/0s0o/3s3e/1s1i/4s4h",
316     "/0s0o/3s3e/1s1l/4s4a",
317     "/0s0o/3s3e/1s1l/4s4h",
318     "/0s0o/3s3e/4s4a",
319     "/0s0o/3s3e/4s4h",
320     "/0s0o/3s3e/4s4a",
321     "/0s0o/3s3e/4s4h",
322     "/0s0o/5s5s",
323     "/0s0o/5s5s/1s1i",
324     "/0s0o/5s5s/1s1l",
325     "/0s0o/5s5s/1s1i/4s4a",
326     "/0s0o/5s5s/1s1i/4s4h",
327     "/0s0o/5s5s/1s1l/4s4a",
328     "/0s0o/5s5s/1s1l/4s4h",
329     "/0s0o/5s5s/4s4a",
330     "/0s0o/5s5s/4s4h",
331     "/0s0o/5s5s/4s4a",
332     "/0s0o/5s5s/4s4h",
333     "/0s0o/1s1i",
334     "/0s0o/1s1l",
335     "/0s0o/1s1i/4s4a",
336     "/0s0o/1s1i/4s4h",
337     "/0s0o/1s1l/4s4a",
338     "/0s0o/1s1l/4s4h",
339     "/0s0o/4s4a",
340     "/0s0o/4s4h",
341     "/0s0o/4s4a",
342     "/0s0o/4s4h",
343     "/2s2a",
344     "/2s2a/3s3e",
345     "/2s2a/3s3e/5s5s",
346     "/2s2a/3s3e/5s5s/1s1i",
347     "/2s2a/3s3e/5s5s/1s1l",
348     "/2s2a/3s3e/5s5s/1s1i/4s4a",
349     "/2s2a/3s3e/5s5s/1s1i/4s4h",
350     "/2s2a/3s3e/5s5s/1s1l/4s4a",
351     "/2s2a/3s3e/5s5s/1s1l/4s4h",
352     "/2s2a/3s3e/5s5s/4s4a",
353     "/2s2a/3s3e/5s5s/4s4h",
354     "/2s2a/3s3e/5s5s/4s4a",
355     "/2s2a/3s3e/5s5s/4s4h",
356     "/2s2a/3s3e/1s1i",
357     "/2s2a/3s3e/1s1l",
358     "/2s2a/3s3e/1s1i/4s4a",
359     "/2s2a/3s3e/1s1i/4s4h",
360     "/2s2a/3s3e/1s1l/4s4a",
361     "/2s2a/3s3e/1s1l/4s4h",
362     "/2s2a/3s3e/4s4a",
363     "/2s2a/3s3e/4s4h",
364     "/2s2a/3s3e/4s4a",
365     "/2s2a/3s3e/4s4h",
366     "/2s2a/5s5s",
367     "/2s2a/5s5s/1s1i",
368     "/2s2a/5s5s/1s1l",
369     "/2s2a/5s5s/1s1i/4s4a",
370     "/2s2a/5s5s/1s1i/4s4h",
371     "/2s2a/5s5s/1s1l/4s4a",
372     "/2s2a/5s5s/1s1l/4s4h",
373     "/2s2a/5s5s/4s4a",
374     "/2s2a/5s5s/4s4h",
375     "/2s2a/5s5s/4s4a",
376     "/2s2a/5s5s/4s4h",
377     "/2s2a/1s1i",
378     "/2s2a/1s1l",
379     "/2s2a/1s1i/4s4a",
380     "/2s2a/1s1i/4s4h",
381     "/2s2a/1s1l/4s4a",
382     "/2s2a/1s1l/4s4h",
383     "/2s2a/4s4a",
384     "/2s2a/4s4h",
385     "/2s2a/4s4a",
386     "/2s2a/4s4h",
387     "/3s3e",
388     "/3s3e/5s5s",
389     "/3s3e/5s5s/1s1i",
390     "/3s3e/5s5s/1s1l",
391     "/3s3e/5s5s/1s1i/4s4a",
392     "/3s3e/5s5s/1s1i/4s4h",
393     "/3s3e/5s5s/1s1l/4s4a",
394     "/3s3e/5s5s/1s1l/4s4h",
395     "/3s3e/5s5s/4s4a",
396     "/3s3e/5s5s/4s4h",
397     "/3s3e/5s5s/4s4a",
398     "/3s3e/5s5s/4s4h",
399     "/3s3e/1s1i",
400     "/3s3e/1s1l",
401     "/3s3e/1s1i/4s4a",
402     "/3s3e/1s1i/4s4h",
403     "/3s3e/1s1l/4s4a",
404     "/3s3e/1s1l/4s4h",
405     "/3s3e/4s4a",
406     "/3s3e/4s4h",
407     "/3s3e/4s4a",
408     "/3s3e/4s4h",
409     "/5s5s",
410     "/5s5s/1s1i",
411     "/5s5s/1s1l",
412     "/5s5s/1s1i/4s4a",
413     "/5s5s/1s1i/4s4h",
414     "/5s5s/1s1l/4s4a",
415     "/5s5s/1s1l/4s4h",
416     "/5s5s/4s4a",
417     "/5s5s/4s4h",
418     "/5s5s/4s4a",
419     "/5s5s/4s4h",
420     "/1s1i",
421     "/1s1l",
422     "/1s1i/4s4a",
423     "/1s1i/4s4h",
424     "/1s1l/4s4a",
425     "/1s1l/4s4h",
426     "/4s4a",
427     "/4s4h",
428     "/4s4a",
429     "/4s4h",
430
431     /* done */
432     (char *) 0
433 };
434
435 static const char *
436 FascistLook(PWDICT *pwp, const char *instring)
437 {
438     int i, pw_len;
439     unsigned int mindiff;
440     char *ptr;
441     char *jptr;
442     char junk[STRINGSIZE];
443     char *password;
444     char rpassword[STRINGSIZE];
445     char reverse[STRINGSIZE];
446     int32 notfound;
447
448     notfound = PW_WORDS(pwp);
449     /* already truncated if from FascistCheck() */
450     /* but pretend it wasn't ... */
451     strncpy(rpassword, instring, TRUNCSTRINGSIZE);
452     rpassword[TRUNCSTRINGSIZE - 1] = '\0';
453     password = rpassword;
454
455     pw_len = strlen(password); 
456     if (pw_len < 4)
457     {
458         return ("it is WAY too short");
459     }
460
461     if (pw_len < MINLEN)
462     {
463         return ("it is too short");
464     }
465
466     jptr = junk;
467     *jptr = '\0';
468
469     for (i = 0; i < STRINGSIZE && password[i]; i++)
470     {
471         if (!strchr(junk, password[i]))
472         {
473             *(jptr++) = password[i];
474             *jptr = '\0';
475         }
476     }
477
478     /*
479      * mindiff is the number of different characters the password has to
480      * contain.  The original CrackLib always requires five different
481      * characters.  This increases that number up to 8 for passwords longer
482      * than nine characters.
483      */
484     if (pw_len < 2 * MINDIFF)
485     { 
486         mindiff = MINDIFF;
487     } else
488     {
489         if ((pw_len % 2) == 0)
490         {
491             mindiff = (pw_len + 1) / 2;
492         } else
493         {
494             mindiff = pw_len / 2;
495         }
496         mindiff++;
497         if (mindiff > MAXMINDIFF)
498         {
499             mindiff = MAXMINDIFF;
500         }
501     }
502
503     if (strlen(junk) < mindiff)
504     {
505         return ("it does not contain enough DIFFERENT characters");
506     }
507
508     strcpy(password, Lowercase(password));
509
510     Trim(password);
511
512     while (*password && isspace(*password))
513     {
514         password++;
515     }
516
517     if (!*password)
518     {
519         return ("it is all whitespace");
520     }
521
522     i = 0;
523     ptr = password;
524     while (ptr[0] && ptr[1])
525     {
526         if ((ptr[1] == (ptr[0] + 1)) || (ptr[1] == (ptr[0] - 1)))
527         {
528             i++;
529         }
530         ptr++;
531     }
532
533     /* Allow one simple letter increment per three characters. */
534     if (i > (int) strlen(password) / 3)
535     {
536         return ("it is too simplistic/systematic");
537     }
538
539     if (PMatch("aadddddda", password))  /* smirk */
540     {
541         return ("it looks like a National Insurance number.");
542     }
543
544     /* This is pretty useless for a server. */
545 #ifdef HAVE_GECOS_AVAILABLE
546     if (ptr = FascistGecos(password, getuid()))
547     {
548         return (ptr);
549     }
550 #endif 
551
552     /* it should be safe to use Mangle with its reliance on STRINGSIZE
553        since password cannot be longer than TRUNCSTRINGSIZE;
554        nonetheless this is not an elegant solution */
555
556     for (i = 0; r_destructors[i]; i++)
557     {
558         char *a;
559
560         if (!(a = Mangle(password, r_destructors[i])))
561         {
562             continue;
563         }
564
565 #ifdef DEBUG
566         printf("%-16s (dict)\n", a);
567 #endif
568
569         if (FindPW(pwp, a) != notfound)
570         {
571             return ("it is based on a dictionary word");
572         }
573     }
574
575     strcpy(reverse, Reverse(password));
576
577     for (i = 0; r_destructors[i]; i++)
578     {
579         char *a;
580
581         if (!(a = Mangle(reverse, r_destructors[i])))
582         {
583             continue;
584         }
585 #ifdef DEBUG
586         printf("%-16s (reversed dict)\n", a);
587 #endif
588         if (FindPW(pwp, a) != notfound)
589         {
590             return ("it is based on a (reversed) dictionary word");
591         }
592     }
593
594     /* Check for a duplicated word. */
595
596     if ((pw_len % 2) == 0)
597     {
598         if (strncmp(password, password + (pw_len / 2), pw_len / 2) == 0)
599         {
600             password[pw_len / 2] = '\0';
601             for (i = 0; r_destructors[i]; i++)
602             {
603                 char *a;
604
605                 if (!(a = Mangle(password, r_destructors[i])))
606                 {
607                     continue;
608                 }
609 #ifdef DEBUG
610                 printf("%-16s (duplicated dict)\n", a);
611 #endif
612                 if (FindPW(pwp, a) != notfound)
613                 {
614                     return ("it is based on a (duplicated) dictionary word");
615                 }
616             }
617         }
618     }
619
620     return ((char *) 0);
621 }
622
623 const char *
624 FascistCheck(const char *password, const char *path)
625 {
626     PWDICT *pwp;
627     char pwtrunced[STRINGSIZE];
628     const char *result;
629
630     /* security problem: assume we may have been given a really long
631        password (buffer attack) and so truncate it to a workable size;
632        try to define workable size as something from which we cannot
633        extend a buffer beyond its limits in the rest of the code */
634
635     strncpy(pwtrunced, password, TRUNCSTRINGSIZE);
636     pwtrunced[TRUNCSTRINGSIZE - 1] = '\0'; /* enforce */
637
638     /* perhaps someone should put something here to check if password
639        is really long and syslog() a message denoting buffer attacks?  */
640
641     if (!(pwp = PWOpen(path, "r")))
642     {
643         perror("PWOpen");
644         return "Cannot check password: dictionary unavailable";
645     }
646
647     result = FascistLook(pwp, pwtrunced);
648     PWClose(pwp);
649     return result;
650 }