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-23 Russ Allbery <eagle@eyrie.org>
13 * - Apply Debian patch to improve the search logic.
14 * - Don't crash if the dictionary is corrupt.
15 * - Additional system includes for other functions.
16 * 2009-10-14 Russ Allbery <eagle@eyrie.org>
17 * - Add ANSI C protototypes for all functions.
18 * - Tweaks for const cleanliness.
19 * - Add parentheses around assignment used for its truth value.
20 * - Make internal functions static.
21 * - Remove unused variables.
22 * 2009-11-18 Russ Allbery <eagle@eyrie.org>
23 * - Fixed the data format output by packer to properly pad the end.
24 * 2013-09-24 Russ Allbery <eagle@eyrie.org>
25 * - Add a missing ANSI C prototype.
26 * - Remove last block optimization in GetPW and start fresh each time.
27 * 2013-12-13 Russ Allbery <eagle@eyrie.org>
28 * - Close the wfp file handle on PWClose if it's open.
29 * 2016-11-06 Russ Allbery <eagle@eyrie.org>
30 * - Remove unused vers_id to silence GCC warnings.
31 * 2020-05-16 Russ Allbery <eagle@eyrie.org>
32 * - Fix types of printf formatting directives in DEBUG conditionals.
41 PWOpen(const char *prefix, const char *mode)
44 char iname[STRINGSIZE];
45 char dname[STRINGSIZE];
46 char wname[STRINGSIZE];
51 if (pdesc.header.pih_magic == PIH_MAGIC)
53 fprintf(stderr, "%s: another dictionary already open\n", prefix);
54 return ((PWDICT *) 0);
57 memset(&pdesc, '\0', sizeof(pdesc));
59 sprintf(iname, "%s.pwi", prefix);
60 sprintf(dname, "%s.pwd", prefix);
61 sprintf(wname, "%s.hwm", prefix);
63 if (!(pdesc.dfp = fopen(dname, mode)))
66 return ((PWDICT *) 0);
69 if (!(pdesc.ifp = fopen(iname, mode)))
73 return ((PWDICT *) 0);
76 if ((pdesc.wfp = fopen(wname, mode)) != NULL)
78 pdesc.flags |= PFOR_USEHWMS;
87 pdesc.flags |= PFOR_WRITE;
88 pdesc.header.pih_magic = PIH_MAGIC;
89 pdesc.header.pih_blocklen = NUMWORDS;
90 pdesc.header.pih_numwords = 0;
92 fwrite((char *) &pdesc.header, sizeof(pdesc.header), 1, ifp);
95 pdesc.flags &= ~PFOR_WRITE;
97 if (!fread((char *) &pdesc.header, sizeof(pdesc.header), 1, ifp))
99 fprintf(stderr, "%s: error reading header\n", prefix);
101 pdesc.header.pih_magic = 0;
108 return ((PWDICT *) 0);
111 if (pdesc.header.pih_magic != PIH_MAGIC)
113 fprintf(stderr, "%s: magic mismatch\n", prefix);
115 pdesc.header.pih_magic = 0;
122 return ((PWDICT *) 0);
125 if (pdesc.header.pih_blocklen != NUMWORDS)
127 fprintf(stderr, "%s: size mismatch\n", prefix);
129 pdesc.header.pih_magic = 0;
136 return ((PWDICT *) 0);
139 if (pdesc.flags & PFOR_USEHWMS)
141 if (fread(pdesc.hwms, 1, sizeof(pdesc.hwms), wfp) != sizeof(pdesc.hwms))
143 pdesc.flags &= ~PFOR_USEHWMS;
154 if (pwp->header.pih_magic != PIH_MAGIC)
156 fprintf(stderr, "PWClose: close magic mismatch\n");
160 if (pwp->flags & PFOR_WRITE)
162 pwp->flags |= PFOR_FLUSH;
163 PutPW(pwp, (char *) 0); /* flush last index if necess */
165 if (fseek(pwp->ifp, 0L, 0))
167 fprintf(stderr, "index magic fseek failed\n");
171 if (!fwrite((char *) &pwp->header, sizeof(pwp->header), 1, pwp->ifp))
173 fprintf(stderr, "index magic fwrite failed\n");
177 if (pwp->flags & PFOR_USEHWMS)
180 for (i=1; i<=0xff; i++)
184 pwp->hwms[i] = pwp->hwms[i-1];
187 printf("hwm[%02x] = %u\n", i, pwp->hwms[i]);
190 fwrite(pwp->hwms, 1, sizeof(pwp->hwms), pwp->wfp);
196 if (pwp->wfp != NULL)
201 pwp->header.pih_magic = 0;
207 PutPW(PWDICT *pwp, const char *string)
209 if (!(pwp->flags & PFOR_WRITE))
216 strncpy(pwp->data[pwp->count], string, MAXWORDLEN);
217 pwp->data[pwp->count][MAXWORDLEN - 1] = '\0';
219 pwp->hwms[string[0] & 0xff]= pwp->header.pih_numwords;
222 ++(pwp->header.pih_numwords);
224 } else if (!(pwp->flags & PFOR_FLUSH))
229 if ((pwp->flags & PFOR_FLUSH) || !(pwp->count % NUMWORDS))
235 datum = (int32) ftell(pwp->dfp);
237 fwrite((char *) &datum, sizeof(datum), 1, pwp->ifp);
239 fputs(pwp->data[0], pwp->dfp);
244 for (i = 1; i < NUMWORDS; i++)
252 for (j = 0; ostr[j] && nstr[j] && (ostr[j] == nstr[j]); j++);
253 putc(j & 0xff, pwp->dfp);
254 fputs(nstr + j, pwp->dfp);
264 memset(pwp->data, '\0', sizeof(pwp->data));
271 GetPW(PWDICT *pwp, int32 number)
278 char buffer[NUMWORDS * MAXWORDLEN];
279 static char data[NUMWORDS][MAXWORDLEN];
282 thisblock = number / NUMWORDS;
284 if (fseek(pwp->ifp, sizeof(struct pi_header) + (thisblock * sizeof(int32)), 0))
286 perror("(index fseek failed)");
290 if (!fread((char *) &datum, sizeof(datum), 1, pwp->ifp))
292 perror("(index fread failed)");
296 if (fseek(pwp->dfp, datum, 0))
298 perror("(data fseek failed)");
302 if (!fread(buffer, 1, sizeof(buffer), pwp->dfp))
304 perror("(data fread failed)");
310 for (ostr = data[0]; (*(ostr++) = *(bptr++)) != '\0'; /* nothing */ );
314 for (i = 1; i < NUMWORDS; i++)
319 ostr = nstr + *(bptr++);
320 while ((*(ostr++) = *(bptr++)) != '\0');
325 return (data[number % NUMWORDS]);
329 FindPW(PWDICT *pwp, const char *string)
333 register int32 middle;
337 if (pwp->flags & PFOR_USEHWMS)
339 idx = string[0] & 0xff;
340 lwm = idx ? pwp->hwms[idx - 1] : 0;
341 hwm = pwp->hwms[idx];
345 hwm = PW_WORDS(pwp) - 1;
349 printf("---- %u, %u ----\n", lwm, hwm);
357 printf("%u, %u\n", lwm, hwm);
360 middle = lwm + ((hwm - lwm + 1) / 2);
363 * If GetPW returns NULL, we have a corrupt dictionary. It's hard to
364 * figure out the best thing to do here. Returning true for every
365 * password seems better than just crashing the program.
367 this = GetPW(pwp, middle);
372 cmp = strcmp(string, this); /* INLINE ? */
376 /* The following may be a little non-obvious... it's
383 * which is much clearer, but it unfortunately doesn't work
384 * because hwm is unsigned and middle may legitimately be
385 * zero, which would lead to hwm being set to a very high
386 * number. So instead we have...
402 return (PW_WORDS(pwp));