]> eyrie.org Git - kerberos/krb5-strength.git/blob - cracklib/packlib.c
Update hash iterations in heimdal-history
[kerberos/krb5-strength.git] / cracklib / packlib.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-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.
33  */
34
35 #include <stdio.h>
36 #include <string.h>
37
38 #include "packer.h"
39
40 PWDICT *
41 PWOpen(const char *prefix, const char *mode)
42 {
43     static PWDICT pdesc;
44     char iname[STRINGSIZE];
45     char dname[STRINGSIZE];
46     char wname[STRINGSIZE];
47     FILE *dfp;
48     FILE *ifp;
49     FILE *wfp;
50
51     if (pdesc.header.pih_magic == PIH_MAGIC)
52     {
53         fprintf(stderr, "%s: another dictionary already open\n", prefix);
54         return ((PWDICT *) 0);
55     }
56
57     memset(&pdesc, '\0', sizeof(pdesc));
58
59     sprintf(iname, "%s.pwi", prefix);
60     sprintf(dname, "%s.pwd", prefix);
61     sprintf(wname, "%s.hwm", prefix);
62
63     if (!(pdesc.dfp = fopen(dname, mode)))
64     {
65         perror(dname);
66         return ((PWDICT *) 0);
67     }
68
69     if (!(pdesc.ifp = fopen(iname, mode)))
70     {
71         fclose(pdesc.dfp);
72         perror(iname);
73         return ((PWDICT *) 0);
74     }
75
76     if ((pdesc.wfp = fopen(wname, mode)) != NULL)
77     {
78         pdesc.flags |= PFOR_USEHWMS;
79     }
80
81     ifp = pdesc.ifp;
82     dfp = pdesc.dfp;
83     wfp = pdesc.wfp;
84
85     if (mode[0] == 'w')
86     {
87         pdesc.flags |= PFOR_WRITE;
88         pdesc.header.pih_magic = PIH_MAGIC;
89         pdesc.header.pih_blocklen = NUMWORDS;
90         pdesc.header.pih_numwords = 0;
91
92         fwrite((char *) &pdesc.header, sizeof(pdesc.header), 1, ifp);
93     } else
94     {
95         pdesc.flags &= ~PFOR_WRITE;
96
97         if (!fread((char *) &pdesc.header, sizeof(pdesc.header), 1, ifp))
98         {
99             fprintf(stderr, "%s: error reading header\n", prefix);
100
101             pdesc.header.pih_magic = 0;
102             fclose(ifp);
103             fclose(dfp);
104             if (wfp != NULL)
105             {
106                 fclose(wfp);
107             }
108             return ((PWDICT *) 0);
109         }
110
111         if (pdesc.header.pih_magic != PIH_MAGIC)
112         {
113             fprintf(stderr, "%s: magic mismatch\n", prefix);
114
115             pdesc.header.pih_magic = 0;
116             fclose(ifp);
117             fclose(dfp);
118             if (wfp != NULL)
119             {
120                 fclose(wfp);
121             }
122             return ((PWDICT *) 0);
123         }
124
125         if (pdesc.header.pih_blocklen != NUMWORDS)
126         {
127             fprintf(stderr, "%s: size mismatch\n", prefix);
128
129             pdesc.header.pih_magic = 0;
130             fclose(ifp);
131             fclose(dfp);
132             if (wfp != NULL)
133             {
134                 fclose(wfp);
135             }
136             return ((PWDICT *) 0);
137         }
138
139         if (pdesc.flags & PFOR_USEHWMS)
140         {
141             if (fread(pdesc.hwms, 1, sizeof(pdesc.hwms), wfp) != sizeof(pdesc.hwms))
142             {
143                 pdesc.flags &= ~PFOR_USEHWMS;
144             }
145         }
146     }
147
148     return (&pdesc);
149 }
150
151 int
152 PWClose(PWDICT *pwp)
153 {
154     if (pwp->header.pih_magic != PIH_MAGIC)
155     {
156         fprintf(stderr, "PWClose: close magic mismatch\n");
157         return (-1);
158     }
159
160     if (pwp->flags & PFOR_WRITE)
161     {
162         pwp->flags |= PFOR_FLUSH;
163         PutPW(pwp, (char *) 0); /* flush last index if necess */
164
165         if (fseek(pwp->ifp, 0L, 0))
166         {
167             fprintf(stderr, "index magic fseek failed\n");
168             return (-1);
169         }
170
171         if (!fwrite((char *) &pwp->header, sizeof(pwp->header), 1, pwp->ifp))
172         {
173             fprintf(stderr, "index magic fwrite failed\n");
174             return (-1);
175         }
176
177         if (pwp->flags & PFOR_USEHWMS)
178         {
179             int i;
180             for (i=1; i<=0xff; i++)
181             {
182                 if (!pwp->hwms[i])
183                 {
184                     pwp->hwms[i] = pwp->hwms[i-1];
185                 }
186 #ifdef DEBUG
187                 printf("hwm[%02x] = %u\n", i, pwp->hwms[i]);
188 #endif
189             }
190             fwrite(pwp->hwms, 1, sizeof(pwp->hwms), pwp->wfp);
191         }
192     }
193
194     fclose(pwp->ifp);
195     fclose(pwp->dfp);
196     if (pwp->wfp != NULL)
197     {
198         fclose(pwp->wfp);
199     }
200
201     pwp->header.pih_magic = 0;
202
203     return (0);
204 }
205
206 int
207 PutPW(PWDICT *pwp, const char *string)
208 {
209     if (!(pwp->flags & PFOR_WRITE))
210     {
211         return (-1);
212     }
213
214     if (string)
215     {
216         strncpy(pwp->data[pwp->count], string, MAXWORDLEN);
217         pwp->data[pwp->count][MAXWORDLEN - 1] = '\0';
218
219         pwp->hwms[string[0] & 0xff]= pwp->header.pih_numwords;
220
221         ++(pwp->count);
222         ++(pwp->header.pih_numwords);
223
224     } else if (!(pwp->flags & PFOR_FLUSH))
225     {
226         return (-1);
227     }
228
229     if ((pwp->flags & PFOR_FLUSH) || !(pwp->count % NUMWORDS))
230     {
231         int i;
232         int32 datum;
233         register char *ostr;
234
235         datum = (int32) ftell(pwp->dfp);
236
237         fwrite((char *) &datum, sizeof(datum), 1, pwp->ifp);
238
239         fputs(pwp->data[0], pwp->dfp);
240         putc(0, pwp->dfp);
241
242         ostr = pwp->data[0];
243
244         for (i = 1; i < NUMWORDS; i++)
245         {
246             register int j;
247             register char *nstr;
248             nstr = pwp->data[i];
249
250             if (nstr[0])
251             {
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);
255             } else
256             {
257                 putc(0, pwp->dfp);
258             }
259             putc(0, pwp->dfp);
260
261             ostr = nstr;
262         }
263
264         memset(pwp->data, '\0', sizeof(pwp->data));
265         pwp->count = 0;
266     }
267     return (0);
268 }
269
270 static char *
271 GetPW(PWDICT *pwp, int32 number)
272 {
273     int32 datum;
274     register int i;
275     register char *ostr;
276     register char *nstr;
277     register char *bptr;
278     char buffer[NUMWORDS * MAXWORDLEN];
279     static char data[NUMWORDS][MAXWORDLEN];
280     int32 thisblock;
281
282     thisblock = number / NUMWORDS;
283
284     if (fseek(pwp->ifp, sizeof(struct pi_header) + (thisblock * sizeof(int32)), 0))
285     {
286         perror("(index fseek failed)");
287         return ((char *) 0);
288     }
289
290     if (!fread((char *) &datum, sizeof(datum), 1, pwp->ifp))
291     {
292         perror("(index fread failed)");
293         return ((char *) 0);
294     }
295
296     if (fseek(pwp->dfp, datum, 0))
297     {
298         perror("(data fseek failed)");
299         return ((char *) 0);
300     }
301
302     if (!fread(buffer, 1, sizeof(buffer), pwp->dfp))
303     {
304         perror("(data fread failed)");
305         return ((char *) 0);
306     }
307
308     bptr = buffer;
309
310     for (ostr = data[0]; (*(ostr++) = *(bptr++)) != '\0'; /* nothing */ );
311
312     ostr = data[0];
313
314     for (i = 1; i < NUMWORDS; i++)
315     {
316         nstr = data[i];
317         strcpy(nstr, ostr);
318
319         ostr = nstr + *(bptr++);
320         while ((*(ostr++) = *(bptr++)) != '\0');
321
322         ostr = nstr;
323     }
324
325     return (data[number % NUMWORDS]);
326 }
327
328 int32
329 FindPW(PWDICT *pwp, const char *string)
330 {
331     register int32 lwm;
332     register int32 hwm;
333     register int32 middle;
334     register char *this;
335     int idx;
336
337     if (pwp->flags & PFOR_USEHWMS)
338     {
339         idx = string[0] & 0xff;
340         lwm = idx ? pwp->hwms[idx - 1] : 0;
341         hwm = pwp->hwms[idx];
342     } else
343     {
344         lwm = 0;
345         hwm = PW_WORDS(pwp) - 1;
346     }
347
348 #ifdef DEBUG
349     printf("---- %u, %u ----\n", lwm, hwm);
350 #endif
351
352     for (;;)
353     {
354         int cmp;
355
356 #ifdef DEBUG
357         printf("%u, %u\n", lwm, hwm);
358 #endif
359
360         middle = lwm + ((hwm - lwm + 1) / 2);
361
362         /*
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.
366          */
367         this = GetPW(pwp, middle);
368         if (this == NULL)
369         {
370             return (middle);
371         }
372         cmp = strcmp(string, this);             /* INLINE ? */
373
374         if (cmp < 0)
375         {
376            /* The following may be a little non-obvious... it's
377             * basically doing:
378             *
379             *   hwm = middle - 1;
380             *   if (hwm < lwm)
381             *       break;
382             *
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...
387             */
388            if (middle == lwm)
389                break;
390            hwm = middle - 1;
391         } else if (cmp > 0)
392         {
393            if (middle == hwm)
394                break;
395            lwm = middle + 1;
396         } else
397         {
398             return (middle);
399         }
400     }
401
402     return (PW_WORDS(pwp));
403 }