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
10 * Modified as part of the krb5-strength project as follows:
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.
26 static const char vers_id[] = "fascist.c : v2.3p3 Alec Muffett 14 dec 1997";
29 #include <sys/types.h>
35 #define ISSKIP(x) (isspace(x) || ispunct(x))
45 static const char *r_destructors[] = {
46 ":", /* noop - must do this to test raw word. */
52 "[", /* trimming leading/trailing junk */
57 "]]]", /* 5 for 8 char passwords */
58 /* This is for longer passwords, it should be based on length */
59 "]]]]", /* 6 for 10 char passwords */
61 "]]]]]", /* 7 for 12 char passwords */
63 "]]]]]]", /* 8 for 14 char passwords */
66 "/?p@?p", /* purging out punctuation/symbols/junk */
70 /* attempt reverse engineering of password strings */
75 "/$s$s/0s0o/2s2a/3s3e",
76 "/$s$s/0s0o/2s2a/3s3e/5s5s",
77 "/$s$s/0s0o/2s2a/3s3e/5s5s/1s1i",
78 "/$s$s/0s0o/2s2a/3s3e/5s5s/1s1l",
79 "/$s$s/0s0o/2s2a/3s3e/5s5s/1s1i/4s4a",
80 "/$s$s/0s0o/2s2a/3s3e/5s5s/1s1i/4s4h",
81 "/$s$s/0s0o/2s2a/3s3e/5s5s/1s1l/4s4a",
82 "/$s$s/0s0o/2s2a/3s3e/5s5s/1s1l/4s4h",
83 "/$s$s/0s0o/2s2a/3s3e/5s5s/4s4a",
84 "/$s$s/0s0o/2s2a/3s3e/5s5s/4s4h",
85 "/$s$s/0s0o/2s2a/3s3e/5s5s/4s4a",
86 "/$s$s/0s0o/2s2a/3s3e/5s5s/4s4h",
87 "/$s$s/0s0o/2s2a/3s3e/1s1i",
88 "/$s$s/0s0o/2s2a/3s3e/1s1l",
89 "/$s$s/0s0o/2s2a/3s3e/1s1i/4s4a",
90 "/$s$s/0s0o/2s2a/3s3e/1s1i/4s4h",
91 "/$s$s/0s0o/2s2a/3s3e/1s1l/4s4a",
92 "/$s$s/0s0o/2s2a/3s3e/1s1l/4s4h",
93 "/$s$s/0s0o/2s2a/3s3e/4s4a",
94 "/$s$s/0s0o/2s2a/3s3e/4s4h",
95 "/$s$s/0s0o/2s2a/3s3e/4s4a",
96 "/$s$s/0s0o/2s2a/3s3e/4s4h",
97 "/$s$s/0s0o/2s2a/5s5s",
98 "/$s$s/0s0o/2s2a/5s5s/1s1i",
99 "/$s$s/0s0o/2s2a/5s5s/1s1l",
100 "/$s$s/0s0o/2s2a/5s5s/1s1i/4s4a",
101 "/$s$s/0s0o/2s2a/5s5s/1s1i/4s4h",
102 "/$s$s/0s0o/2s2a/5s5s/1s1l/4s4a",
103 "/$s$s/0s0o/2s2a/5s5s/1s1l/4s4h",
104 "/$s$s/0s0o/2s2a/5s5s/4s4a",
105 "/$s$s/0s0o/2s2a/5s5s/4s4h",
106 "/$s$s/0s0o/2s2a/5s5s/4s4a",
107 "/$s$s/0s0o/2s2a/5s5s/4s4h",
108 "/$s$s/0s0o/2s2a/1s1i",
109 "/$s$s/0s0o/2s2a/1s1l",
110 "/$s$s/0s0o/2s2a/1s1i/4s4a",
111 "/$s$s/0s0o/2s2a/1s1i/4s4h",
112 "/$s$s/0s0o/2s2a/1s1l/4s4a",
113 "/$s$s/0s0o/2s2a/1s1l/4s4h",
114 "/$s$s/0s0o/2s2a/4s4a",
115 "/$s$s/0s0o/2s2a/4s4h",
116 "/$s$s/0s0o/2s2a/4s4a",
117 "/$s$s/0s0o/2s2a/4s4h",
119 "/$s$s/0s0o/3s3e/5s5s",
120 "/$s$s/0s0o/3s3e/5s5s/1s1i",
121 "/$s$s/0s0o/3s3e/5s5s/1s1l",
122 "/$s$s/0s0o/3s3e/5s5s/1s1i/4s4a",
123 "/$s$s/0s0o/3s3e/5s5s/1s1i/4s4h",
124 "/$s$s/0s0o/3s3e/5s5s/1s1l/4s4a",
125 "/$s$s/0s0o/3s3e/5s5s/1s1l/4s4h",
126 "/$s$s/0s0o/3s3e/5s5s/4s4a",
127 "/$s$s/0s0o/3s3e/5s5s/4s4h",
128 "/$s$s/0s0o/3s3e/5s5s/4s4a",
129 "/$s$s/0s0o/3s3e/5s5s/4s4h",
130 "/$s$s/0s0o/3s3e/1s1i",
131 "/$s$s/0s0o/3s3e/1s1l",
132 "/$s$s/0s0o/3s3e/1s1i/4s4a",
133 "/$s$s/0s0o/3s3e/1s1i/4s4h",
134 "/$s$s/0s0o/3s3e/1s1l/4s4a",
135 "/$s$s/0s0o/3s3e/1s1l/4s4h",
136 "/$s$s/0s0o/3s3e/4s4a",
137 "/$s$s/0s0o/3s3e/4s4h",
138 "/$s$s/0s0o/3s3e/4s4a",
139 "/$s$s/0s0o/3s3e/4s4h",
141 "/$s$s/0s0o/5s5s/1s1i",
142 "/$s$s/0s0o/5s5s/1s1l",
143 "/$s$s/0s0o/5s5s/1s1i/4s4a",
144 "/$s$s/0s0o/5s5s/1s1i/4s4h",
145 "/$s$s/0s0o/5s5s/1s1l/4s4a",
146 "/$s$s/0s0o/5s5s/1s1l/4s4h",
147 "/$s$s/0s0o/5s5s/4s4a",
148 "/$s$s/0s0o/5s5s/4s4h",
149 "/$s$s/0s0o/5s5s/4s4a",
150 "/$s$s/0s0o/5s5s/4s4h",
153 "/$s$s/0s0o/1s1i/4s4a",
154 "/$s$s/0s0o/1s1i/4s4h",
155 "/$s$s/0s0o/1s1l/4s4a",
156 "/$s$s/0s0o/1s1l/4s4h",
163 "/$s$s/2s2a/3s3e/5s5s",
164 "/$s$s/2s2a/3s3e/5s5s/1s1i",
165 "/$s$s/2s2a/3s3e/5s5s/1s1l",
166 "/$s$s/2s2a/3s3e/5s5s/1s1i/4s4a",
167 "/$s$s/2s2a/3s3e/5s5s/1s1i/4s4h",
168 "/$s$s/2s2a/3s3e/5s5s/1s1l/4s4a",
169 "/$s$s/2s2a/3s3e/5s5s/1s1l/4s4h",
170 "/$s$s/2s2a/3s3e/5s5s/4s4a",
171 "/$s$s/2s2a/3s3e/5s5s/4s4h",
172 "/$s$s/2s2a/3s3e/5s5s/4s4a",
173 "/$s$s/2s2a/3s3e/5s5s/4s4h",
174 "/$s$s/2s2a/3s3e/1s1i",
175 "/$s$s/2s2a/3s3e/1s1l",
176 "/$s$s/2s2a/3s3e/1s1i/4s4a",
177 "/$s$s/2s2a/3s3e/1s1i/4s4h",
178 "/$s$s/2s2a/3s3e/1s1l/4s4a",
179 "/$s$s/2s2a/3s3e/1s1l/4s4h",
180 "/$s$s/2s2a/3s3e/4s4a",
181 "/$s$s/2s2a/3s3e/4s4h",
182 "/$s$s/2s2a/3s3e/4s4a",
183 "/$s$s/2s2a/3s3e/4s4h",
185 "/$s$s/2s2a/5s5s/1s1i",
186 "/$s$s/2s2a/5s5s/1s1l",
187 "/$s$s/2s2a/5s5s/1s1i/4s4a",
188 "/$s$s/2s2a/5s5s/1s1i/4s4h",
189 "/$s$s/2s2a/5s5s/1s1l/4s4a",
190 "/$s$s/2s2a/5s5s/1s1l/4s4h",
191 "/$s$s/2s2a/5s5s/4s4a",
192 "/$s$s/2s2a/5s5s/4s4h",
193 "/$s$s/2s2a/5s5s/4s4a",
194 "/$s$s/2s2a/5s5s/4s4h",
197 "/$s$s/2s2a/1s1i/4s4a",
198 "/$s$s/2s2a/1s1i/4s4h",
199 "/$s$s/2s2a/1s1l/4s4a",
200 "/$s$s/2s2a/1s1l/4s4h",
207 "/$s$s/3s3e/5s5s/1s1i",
208 "/$s$s/3s3e/5s5s/1s1l",
209 "/$s$s/3s3e/5s5s/1s1i/4s4a",
210 "/$s$s/3s3e/5s5s/1s1i/4s4h",
211 "/$s$s/3s3e/5s5s/1s1l/4s4a",
212 "/$s$s/3s3e/5s5s/1s1l/4s4h",
213 "/$s$s/3s3e/5s5s/4s4a",
214 "/$s$s/3s3e/5s5s/4s4h",
215 "/$s$s/3s3e/5s5s/4s4a",
216 "/$s$s/3s3e/5s5s/4s4h",
219 "/$s$s/3s3e/1s1i/4s4a",
220 "/$s$s/3s3e/1s1i/4s4h",
221 "/$s$s/3s3e/1s1l/4s4a",
222 "/$s$s/3s3e/1s1l/4s4h",
230 "/$s$s/5s5s/1s1i/4s4a",
231 "/$s$s/5s5s/1s1i/4s4h",
232 "/$s$s/5s5s/1s1l/4s4a",
233 "/$s$s/5s5s/1s1l/4s4h",
251 "/0s0o/2s2a/3s3e/5s5s",
252 "/0s0o/2s2a/3s3e/5s5s/1s1i",
253 "/0s0o/2s2a/3s3e/5s5s/1s1l",
254 "/0s0o/2s2a/3s3e/5s5s/1s1i/4s4a",
255 "/0s0o/2s2a/3s3e/5s5s/1s1i/4s4h",
256 "/0s0o/2s2a/3s3e/5s5s/1s1l/4s4a",
257 "/0s0o/2s2a/3s3e/5s5s/1s1l/4s4h",
258 "/0s0o/2s2a/3s3e/5s5s/4s4a",
259 "/0s0o/2s2a/3s3e/5s5s/4s4h",
260 "/0s0o/2s2a/3s3e/5s5s/4s4a",
261 "/0s0o/2s2a/3s3e/5s5s/4s4h",
262 "/0s0o/2s2a/3s3e/1s1i",
263 "/0s0o/2s2a/3s3e/1s1l",
264 "/0s0o/2s2a/3s3e/1s1i/4s4a",
265 "/0s0o/2s2a/3s3e/1s1i/4s4h",
266 "/0s0o/2s2a/3s3e/1s1l/4s4a",
267 "/0s0o/2s2a/3s3e/1s1l/4s4h",
268 "/0s0o/2s2a/3s3e/4s4a",
269 "/0s0o/2s2a/3s3e/4s4h",
270 "/0s0o/2s2a/3s3e/4s4a",
271 "/0s0o/2s2a/3s3e/4s4h",
273 "/0s0o/2s2a/5s5s/1s1i",
274 "/0s0o/2s2a/5s5s/1s1l",
275 "/0s0o/2s2a/5s5s/1s1i/4s4a",
276 "/0s0o/2s2a/5s5s/1s1i/4s4h",
277 "/0s0o/2s2a/5s5s/1s1l/4s4a",
278 "/0s0o/2s2a/5s5s/1s1l/4s4h",
279 "/0s0o/2s2a/5s5s/4s4a",
280 "/0s0o/2s2a/5s5s/4s4h",
281 "/0s0o/2s2a/5s5s/4s4a",
282 "/0s0o/2s2a/5s5s/4s4h",
285 "/0s0o/2s2a/1s1i/4s4a",
286 "/0s0o/2s2a/1s1i/4s4h",
287 "/0s0o/2s2a/1s1l/4s4a",
288 "/0s0o/2s2a/1s1l/4s4h",
295 "/0s0o/3s3e/5s5s/1s1i",
296 "/0s0o/3s3e/5s5s/1s1l",
297 "/0s0o/3s3e/5s5s/1s1i/4s4a",
298 "/0s0o/3s3e/5s5s/1s1i/4s4h",
299 "/0s0o/3s3e/5s5s/1s1l/4s4a",
300 "/0s0o/3s3e/5s5s/1s1l/4s4h",
301 "/0s0o/3s3e/5s5s/4s4a",
302 "/0s0o/3s3e/5s5s/4s4h",
303 "/0s0o/3s3e/5s5s/4s4a",
304 "/0s0o/3s3e/5s5s/4s4h",
307 "/0s0o/3s3e/1s1i/4s4a",
308 "/0s0o/3s3e/1s1i/4s4h",
309 "/0s0o/3s3e/1s1l/4s4a",
310 "/0s0o/3s3e/1s1l/4s4h",
318 "/0s0o/5s5s/1s1i/4s4a",
319 "/0s0o/5s5s/1s1i/4s4h",
320 "/0s0o/5s5s/1s1l/4s4a",
321 "/0s0o/5s5s/1s1l/4s4h",
339 "/2s2a/3s3e/5s5s/1s1i",
340 "/2s2a/3s3e/5s5s/1s1l",
341 "/2s2a/3s3e/5s5s/1s1i/4s4a",
342 "/2s2a/3s3e/5s5s/1s1i/4s4h",
343 "/2s2a/3s3e/5s5s/1s1l/4s4a",
344 "/2s2a/3s3e/5s5s/1s1l/4s4h",
345 "/2s2a/3s3e/5s5s/4s4a",
346 "/2s2a/3s3e/5s5s/4s4h",
347 "/2s2a/3s3e/5s5s/4s4a",
348 "/2s2a/3s3e/5s5s/4s4h",
351 "/2s2a/3s3e/1s1i/4s4a",
352 "/2s2a/3s3e/1s1i/4s4h",
353 "/2s2a/3s3e/1s1l/4s4a",
354 "/2s2a/3s3e/1s1l/4s4h",
362 "/2s2a/5s5s/1s1i/4s4a",
363 "/2s2a/5s5s/1s1i/4s4h",
364 "/2s2a/5s5s/1s1l/4s4a",
365 "/2s2a/5s5s/1s1l/4s4h",
384 "/3s3e/5s5s/1s1i/4s4a",
385 "/3s3e/5s5s/1s1i/4s4h",
386 "/3s3e/5s5s/1s1l/4s4a",
387 "/3s3e/5s5s/1s1l/4s4h",
429 FascistLook(PWDICT *pwp, const char *instring)
432 unsigned int mindiff;
435 char junk[STRINGSIZE];
437 char rpassword[STRINGSIZE];
440 notfound = PW_WORDS(pwp);
441 /* already truncated if from FascistCheck() */
442 /* but pretend it wasn't ... */
443 strncpy(rpassword, instring, TRUNCSTRINGSIZE);
444 rpassword[TRUNCSTRINGSIZE - 1] = '\0';
445 password = rpassword;
447 pw_len = strlen(password);
450 return ("it's WAY too short");
455 return ("it is too short");
461 for (i = 0; i < STRINGSIZE && password[i]; i++)
463 if (!strchr(junk, password[i]))
465 *(jptr++) = password[i];
471 * mindiff is the number of different characters the password has to
472 * contain. The original CrackLib always requires five different
473 * characters. This increases that number up to 8 for passwords longer
474 * than nine characters.
476 if (pw_len < 2 * MINDIFF)
481 if ((pw_len % 2) == 0)
483 mindiff = (pw_len + 1) / 2;
486 mindiff = pw_len / 2;
489 if (mindiff > MAXMINDIFF)
491 mindiff = MAXMINDIFF;
495 if (strlen(junk) < mindiff)
497 return ("it does not contain enough DIFFERENT characters");
500 strcpy(password, Lowercase(password));
504 while (*password && isspace(*password))
511 return ("it is all whitespace");
516 while (ptr[0] && ptr[1])
518 if ((ptr[1] == (ptr[0] + 1)) || (ptr[1] == (ptr[0] - 1)))
527 return ("it is too simplistic/systematic");
530 if (PMatch("aadddddda", password)) /* smirk */
532 return ("it looks like a National Insurance number.");
535 /* This is pretty useless for a server. */
536 #ifdef HAVE_GECOS_AVAILABLE
537 if (ptr = FascistGecos(password, getuid()))
543 /* it should be safe to use Mangle with its reliance on STRINGSIZE
544 since password cannot be longer than TRUNCSTRINGSIZE;
545 nonetheless this is not an elegant solution */
547 for (i = 0; r_destructors[i]; i++)
551 if (!(a = Mangle(password, r_destructors[i])))
557 printf("%-16s (dict)\n", a);
560 if (FindPW(pwp, a) != notfound)
562 return ("it is based on a dictionary word");
566 strcpy(password, Reverse(password));
568 for (i = 0; r_destructors[i]; i++)
572 if (!(a = Mangle(password, r_destructors[i])))
577 printf("%-16s (reversed dict)\n", a);
579 if (FindPW(pwp, a) != notfound)
581 return ("it is based on a (reversed) dictionary word");
589 FascistCheck(const char *password, const char *path)
591 static char lastpath[STRINGSIZE];
593 char pwtrunced[STRINGSIZE];
595 /* security problem: assume we may have been given a really long
596 password (buffer attack) and so truncate it to a workable size;
597 try to define workable size as something from which we cannot
598 extend a buffer beyond its limits in the rest of the code */
600 strncpy(pwtrunced, password, TRUNCSTRINGSIZE);
601 pwtrunced[TRUNCSTRINGSIZE - 1] = '\0'; /* enforce */
603 /* perhaps someone should put something here to check if password
604 is really long and syslog() a message denoting buffer attacks? */
606 if (pwp && strncmp(lastpath, path, STRINGSIZE))
614 if (!(pwp = PWOpen(path, "r")))
617 return "Cannot check password: dictionary unavailable";
619 strncpy(lastpath, path, STRINGSIZE);
622 return (FascistLook(pwp, pwtrunced));