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