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