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