]> eyrie.org Git - kerberos/krb5-strength.git/blob - src/rules.c
Import the current krb5-strength code.
[kerberos/krb5-strength.git] / src / rules.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 static char vers_id[] = "rules.c : v5.0p3 Alec Muffett 20 May 1993";
10
11 #ifndef IN_CRACKLIB
12
13 #include "crack.h"
14
15 #else
16
17 #include "packer.h"
18
19 static void
20 Debug(val, a, b, c, d, e, f, g)
21     int val;
22     char *a, *b, *c, *d, *e, *f, *g;
23 {
24     fprintf(stderr, a, b, c, d, e, f);
25 }
26
27 #endif
28
29 #define RULE_NOOP       ':'
30 #define RULE_PREPEND    '^'
31 #define RULE_APPEND     '$'
32 #define RULE_REVERSE    'r'
33 #define RULE_UPPERCASE  'u'
34 #define RULE_LOWERCASE  'l'
35 #define RULE_PLURALISE  'p'
36 #define RULE_CAPITALISE 'c'
37 #define RULE_DUPLICATE  'd'
38 #define RULE_REFLECT    'f'
39 #define RULE_SUBSTITUTE 's'
40 #define RULE_MATCH      '/'
41 #define RULE_NOT        '!'
42 #define RULE_LT         '<'
43 #define RULE_GT         '>'
44 #define RULE_EXTRACT    'x'
45 #define RULE_OVERSTRIKE 'o'
46 #define RULE_INSERT     'i'
47 #define RULE_EQUALS     '='
48 #define RULE_PURGE      '@'
49 #define RULE_CLASS      '?'     /* class rule? socialist ethic in cracker? */
50
51 #define RULE_DFIRST     '['
52 #define RULE_DLAST      ']'
53
54 #define RULE_MFIRST     '('
55 #define RULE_MLAST      ')'
56
57 int
58 Suffix(myword, suffix)
59     char *myword;
60     char *suffix;
61 {
62     register int i;
63     register int j;
64     i = strlen(myword);
65     j = strlen(suffix);
66
67     if (i > j)
68     {
69         return (STRCMP((myword + i - j), suffix));
70     } else
71     {
72         return (-1);
73     }
74 }
75
76 char *
77 Reverse(str)                    /* return a pointer to a reversal */
78     register char *str;
79 {
80     register int i;
81     register int j;
82     static char area[STRINGSIZE];
83     j = i = strlen(str);
84     while (*str)
85     {
86         area[--i] = *str++;
87     }
88     area[j] = '\0';
89     return (area);
90 }
91
92 char *
93 Uppercase(str)                  /* return a pointer to an uppercase */
94     register char *str;
95 {
96     register char *ptr;
97     static char area[STRINGSIZE];
98     ptr = area;
99     while (*str)
100     {
101         *(ptr++) = CRACK_TOUPPER(*str);
102         str++;
103     }
104     *ptr = '\0';
105
106     return (area);
107 }
108
109 char *
110 Lowercase(str)                  /* return a pointer to an lowercase */
111     register char *str;
112 {
113     register char *ptr;
114     static char area[STRINGSIZE];
115     ptr = area;
116     while (*str)
117     {
118         *(ptr++) = CRACK_TOLOWER(*str);
119         str++;
120     }
121     *ptr = '\0';
122
123     return (area);
124 }
125
126 char *
127 Capitalise(str)                 /* return a pointer to an capitalised */
128     register char *str;
129 {
130     register char *ptr;
131     static char area[STRINGSIZE];
132     ptr = area;
133
134     while (*str)
135     {
136         *(ptr++) = CRACK_TOLOWER(*str);
137         str++;
138     }
139
140     *ptr = '\0';
141     area[0] = CRACK_TOUPPER(area[0]);
142     return (area);
143 }
144
145 char *
146 Pluralise(string)               /* returns a pointer to a plural */
147     register char *string;
148 {
149     register int length;
150     static char area[STRINGSIZE];
151     length = strlen(string);
152     strcpy(area, string);
153
154     if (!Suffix(string, "ch") ||
155         !Suffix(string, "ex") ||
156         !Suffix(string, "ix") ||
157         !Suffix(string, "sh") ||
158         !Suffix(string, "ss"))
159     {
160         /* bench -> benches */
161         strcat(area, "es");
162     } else if (length > 2 && string[length - 1] == 'y')
163     {
164         if (strchr("aeiou", string[length - 2]))
165         {
166             /* alloy -> alloys */
167             strcat(area, "s");
168         } else
169         {
170             /* gully -> gullies */
171             strcpy(area + length - 1, "ies");
172         }
173     } else if (string[length - 1] == 's')
174     {
175         /* bias -> biases */
176         strcat(area, "es");
177     } else
178     {
179         /* catchall */
180         strcat(area, "s");
181     }
182
183     return (area);
184 }
185
186 char *
187 Substitute(string, old, new)    /* returns pointer to a swapped about copy */
188     register char *string;
189     register char old;
190     register char new;
191 {
192     register char *ptr;
193     static char area[STRINGSIZE];
194     ptr = area;
195     while (*string)
196     {
197         *(ptr++) = (*string == old ? new : *string);
198         string++;
199     }
200     *ptr = '\0';
201     return (area);
202 }
203
204 char *
205 Purge(string, target)           /* returns pointer to a purged copy */
206     register char *string;
207     register char target;
208 {
209     register char *ptr;
210     static char area[STRINGSIZE];
211     ptr = area;
212     while (*string)
213     {
214         if (*string != target)
215         {
216             *(ptr++) = *string;
217         }
218         string++;
219     }
220     *ptr = '\0';
221     return (area);
222 }
223 /* -------- CHARACTER CLASSES START HERE -------- */
224
225 /*
226  * this function takes two inputs, a class identifier and a character, and
227  * returns non-null if the given character is a member of the class, based
228  * upon restrictions set out below
229  */
230
231 int
232 MatchClass(class, input)
233     register char class;
234     register char input;
235 {
236     register char c;
237     register int retval;
238     retval = 0;
239
240     switch (class)
241     {
242         /* ESCAPE */
243
244     case '?':                   /* ?? -> ? */
245         if (input == '?')
246         {
247             retval = 1;
248         }
249         break;
250
251         /* ILLOGICAL GROUPINGS (ie: not in ctype.h) */
252
253     case 'V':
254     case 'v':                   /* vowels */
255         c = CRACK_TOLOWER(input);
256         if (strchr("aeiou", c))
257         {
258             retval = 1;
259         }
260         break;
261
262     case 'C':
263     case 'c':                   /* consonants */
264         c = CRACK_TOLOWER(input);
265         if (strchr("bcdfghjklmnpqrstvwxyz", c))
266         {
267             retval = 1;
268         }
269         break;
270
271     case 'W':
272     case 'w':                   /* whitespace */
273         if (strchr("\t ", input))
274         {
275             retval = 1;
276         }
277         break;
278
279     case 'P':
280     case 'p':                   /* punctuation */
281         if (strchr(".`,:;'!?\"", input))
282         {
283             retval = 1;
284         }
285         break;
286
287     case 'S':
288     case 's':                   /* symbols */
289         if (strchr("$%%^&*()-_+=|\\[]{}#@/~", input))
290         {
291             retval = 1;
292         }
293         break;
294
295         /* LOGICAL GROUPINGS */
296
297     case 'L':
298     case 'l':                   /* lowercase */
299         if (islower(input))
300         {
301             retval = 1;
302         }
303         break;
304
305     case 'U':
306     case 'u':                   /* uppercase */
307         if (isupper(input))
308         {
309             retval = 1;
310         }
311         break;
312
313     case 'A':
314     case 'a':                   /* alphabetic */
315         if (isalpha(input))
316         {
317             retval = 1;
318         }
319         break;
320
321     case 'X':
322     case 'x':                   /* alphanumeric */
323         if (isalnum(input))
324         {
325             retval = 1;
326         }
327         break;
328
329     case 'D':
330     case 'd':                   /* digits */
331         if (isdigit(input))
332         {
333             retval = 1;
334         }
335         break;
336
337     default:
338         Debug(1, "MatchClass: unknown class %c\n", class);
339         return (0);
340         break;
341     }
342
343     if (isupper(class))
344     {
345         return (!retval);
346     }
347     return (retval);
348 }
349
350 char *
351 PolyStrchr(string, class)
352     register char *string;
353     register char class;
354 {
355     while (*string)
356     {
357         if (MatchClass(class, *string))
358         {
359             return (string);
360         }
361         string++;
362     }
363     return ((char *) 0);
364 }
365
366 char *
367 PolySubst(string, class, new)   /* returns pointer to a swapped about copy */
368     register char *string;
369     register char class;
370     register char new;
371 {
372     register char *ptr;
373     static char area[STRINGSIZE];
374     ptr = area;
375     while (*string)
376     {
377         *(ptr++) = (MatchClass(class, *string) ? new : *string);
378         string++;
379     }
380     *ptr = '\0';
381     return (area);
382 }
383
384 char *
385 PolyPurge(string, class)        /* returns pointer to a purged copy */
386     register char *string;
387     register char class;
388 {
389     register char *ptr;
390     static char area[STRINGSIZE];
391     ptr = area;
392     while (*string)
393     {
394         if (!MatchClass(class, *string))
395         {
396             *(ptr++) = *string;
397         }
398         string++;
399     }
400     *ptr = '\0';
401     return (area);
402 }
403 /* -------- BACK TO NORMALITY -------- */
404
405 int
406 Char2Int(character)
407     char character;
408 {
409     if (isdigit(character))
410     {
411         return (character - '0');
412     } else if (islower(character))
413     {
414         return (character - 'a' + 10);
415     } else if (isupper(character))
416     {
417         return (character - 'A' + 10);
418     }
419     return (-1);
420 }
421
422 char *
423 Mangle(input, control)          /* returns a pointer to a controlled Mangle */
424     char *input;
425     char *control;
426 {
427     int limit,min_to_shift;
428     register j;
429     register char *ptr;
430     static char area[STRINGSIZE];
431     char area2[STRINGSIZE];
432     area[0] = '\0';
433     strcpy(area, input);
434
435     j = strlen(input);
436     if ( j%2 == 0 ) { 
437       min_to_shift = (j+1)/2 ; 
438     } else { 
439       min_to_shift = j/2 ; 
440     }
441     min_to_shift++ ; 
442
443     if ( min_to_shift > 5 )
444       min_to_shift = 5 ; 
445     
446     for (ptr = control; *ptr; ptr++)
447     {
448         switch (*ptr)
449         {
450         case RULE_NOOP:
451             break;
452         case RULE_REVERSE:
453             strcpy(area, Reverse(area));
454             break;
455         case RULE_UPPERCASE:
456             strcpy(area, Uppercase(area));
457             break;
458         case RULE_LOWERCASE:
459             strcpy(area, Lowercase(area));
460             break;
461         case RULE_CAPITALISE:
462             strcpy(area, Capitalise(area));
463             break;
464         case RULE_PLURALISE:
465             strcpy(area, Pluralise(area));
466             break;
467         case RULE_REFLECT:
468             strcat(area, Reverse(area));
469             break;
470         case RULE_DUPLICATE:
471             strcpy(area2, area);
472             strcat(area, area2);
473             break;
474         case RULE_GT:
475             if (!ptr[1])
476             {
477                 Debug(1, "Mangle: '>' missing argument in '%s'\n", control);
478                 return ((char *) 0);
479             } else
480             {
481                 limit = Char2Int(*(++ptr));
482                 if (limit < 0)
483                 {
484                     Debug(1, "Mangle: '>' weird argument in '%s'\n", control);
485                     return ((char *) 0);
486                 }
487                 if (strlen(area) <= limit)
488                 {
489                     return ((char *) 0);
490                 }
491             }
492             break;
493         case RULE_LT:
494             if (!ptr[1])
495             {
496                 Debug(1, "Mangle: '<' missing argument in '%s'\n", control);
497                 return ((char *) 0);
498             } else
499             {
500                 limit = Char2Int(*(++ptr));
501                 if (limit < 0)
502                 {
503                     Debug(1, "Mangle: '<' weird argument in '%s'\n", control);
504                     return ((char *) 0);
505                 }
506                 if (strlen(area) >= limit)
507                 {
508                     return ((char *) 0);
509                 }
510             }
511             break;
512         case RULE_PREPEND:
513             if (!ptr[1])
514             {
515                 Debug(1, "Mangle: prepend missing argument in '%s'\n", control);
516                 return ((char *) 0);
517             } else
518             {
519                 area2[0] = *(++ptr);
520                 strcpy(area2 + 1, area);
521                 strcpy(area, area2);
522             }
523             break;
524         case RULE_APPEND:
525             if (!ptr[1])
526             {
527                 Debug(1, "Mangle: append missing argument in '%s'\n", control);
528                 return ((char *) 0);
529             } else
530             {
531                 register char *string;
532                 string = area;
533                 while (*(string++));
534                 string[-1] = *(++ptr);
535                 *string = '\0';
536             }
537             break;
538         case RULE_EXTRACT:
539             if (!ptr[1] || !ptr[2])
540             {
541                 Debug(1, "Mangle: extract missing argument in '%s'\n", control);
542                 return ((char *) 0);
543             } else
544             {
545                 register int i;
546                 int start;
547                 int length;
548                 start = Char2Int(*(++ptr));
549                 length = Char2Int(*(++ptr));
550                 if (start < 0 || length < 0)
551                 {
552                     Debug(1, "Mangle: extract: weird argument in '%s'\n", control);
553                     return ((char *) 0);
554                 }
555                 strcpy(area2, area);
556                 for (i = 0; length-- && area2[start + i]; i++)
557                 {
558                     area[i] = area2[start + i];
559                 }
560                 /* cant use strncpy() - no trailing NUL */
561                 area[i] = '\0';
562             }
563             break;
564         case RULE_OVERSTRIKE:
565             if (!ptr[1] || !ptr[2])
566             {
567                 Debug(1, "Mangle: overstrike missing argument in '%s'\n", control);
568                 return ((char *) 0);
569             } else
570             {
571                 register int i;
572                 i = Char2Int(*(++ptr));
573                 if (i < 0)
574                 {
575                     Debug(1, "Mangle: overstrike weird argument in '%s'\n",
576                           control);
577                     return ((char *) 0);
578                 } else
579                 {
580                     ++ptr;
581                     if (area[i])
582                     {
583                         area[i] = *ptr;
584                     }
585                 }
586             }
587             break;
588         case RULE_INSERT:
589             if (!ptr[1] || !ptr[2])
590             {
591                 Debug(1, "Mangle: insert missing argument in '%s'\n", control);
592                 return ((char *) 0);
593             } else
594             {
595                 register int i;
596                 register char *p1;
597                 register char *p2;
598                 i = Char2Int(*(++ptr));
599                 if (i < 0)
600                 {
601                     Debug(1, "Mangle: insert weird argument in '%s'\n",
602                           control);
603                     return ((char *) 0);
604                 }
605                 p1 = area;
606                 p2 = area2;
607                 while (i && *p1)
608                 {
609                     i--;
610                     *(p2++) = *(p1++);
611                 }
612                 *(p2++) = *(++ptr);
613                 strcpy(p2, p1);
614                 strcpy(area, area2);
615             }
616             break;
617             /* THE FOLLOWING RULES REQUIRE CLASS MATCHING */
618
619         case RULE_PURGE:        /* @x or @?c */
620             if (!ptr[1] || (ptr[1] == RULE_CLASS && !ptr[2]))
621             {
622                 Debug(1, "Mangle: delete missing arguments in '%s'\n", control);
623                 return ((char *) 0);
624             } else if (ptr[1] != RULE_CLASS)
625             {
626                 strcpy(area, Purge(area, *(++ptr)));
627             } else
628             {
629                 strcpy(area, PolyPurge(area, ptr[2]));
630                 ptr += 2;
631             }
632             break;
633         case RULE_SUBSTITUTE:   /* sxy || s?cy */
634             if (!ptr[1] || !ptr[2] || (ptr[1] == RULE_CLASS && !ptr[3]))
635             {
636                 Debug(1, "Mangle: subst missing argument in '%s'\n", control);
637                 return ((char *) 0);
638             } else if (ptr[1] != RULE_CLASS)
639             {
640                 strcpy(area, Substitute(area, ptr[1], ptr[2]));
641                 ptr += 2;
642             } else
643             {
644                 strcpy(area, PolySubst(area, ptr[2], ptr[3]));
645                 ptr += 3;
646             }
647             break;
648         case RULE_MATCH:        /* /x || /?c */
649             if (!ptr[1] || (ptr[1] == RULE_CLASS && !ptr[2]))
650             {
651                 Debug(1, "Mangle: '/' missing argument in '%s'\n", control);
652                 return ((char *) 0);
653             } else if (ptr[1] != RULE_CLASS)
654             {
655                 if (!strchr(area, *(++ptr)))
656                 {
657                     return ((char *) 0);
658                 }
659             } else
660             {
661                 if (!PolyStrchr(area, ptr[2]))
662                 {
663                     return ((char *) 0);
664                 }
665                 ptr += 2;
666             }
667             break;
668         case RULE_NOT:          /* !x || !?c */
669             if (!ptr[1] || (ptr[1] == RULE_CLASS && !ptr[2]))
670             {
671                 Debug(1, "Mangle: '!' missing argument in '%s'\n", control);
672                 return ((char *) 0);
673             } else if (ptr[1] != RULE_CLASS)
674             {
675                 if (strchr(area, *(++ptr)))
676                 {
677                     return ((char *) 0);
678                 }
679             } else
680             {
681                 if (PolyStrchr(area, ptr[2]))
682                 {
683                     return ((char *) 0);
684                 }
685                 ptr += 2;
686             }
687             break;
688             /*
689              * alternative use for a boomerang, number 1: a standard throwing
690              * boomerang is an ideal thing to use to tuck the sheets under
691              * the mattress when making your bed.  The streamlined shape of
692              * the boomerang allows it to slip easily 'twixt mattress and
693              * bedframe, and it's curve makes it very easy to hook sheets
694              * into the gap.
695              */
696
697         case RULE_EQUALS:       /* =nx || =n?c */
698             if (!ptr[1] || !ptr[2] || (ptr[2] == RULE_CLASS && !ptr[3]))
699             {
700                 Debug(1, "Mangle: '=' missing argument in '%s'\n", control);
701                 return ((char *) 0);
702             } else
703             {
704                 register int i;
705                 if ((i = Char2Int(ptr[1])) < 0)
706                 {
707                     Debug(1, "Mangle: '=' weird argument in '%s'\n", control);
708                     return ((char *) 0);
709                 }
710                 if (ptr[2] != RULE_CLASS)
711                 {
712                     ptr += 2;
713                     if (area[i] != *ptr)
714                     {
715                         return ((char *) 0);
716                     }
717                 } else
718                 {
719                     ptr += 3;
720                     if (!MatchClass(*ptr, area[i]))
721                     {
722                         return ((char *) 0);
723                     }
724                 }
725             }
726             break;
727
728         case RULE_DFIRST:
729             if (area[0])
730             {
731               if (strlen(area) > min_to_shift ) {
732                 register int i;
733                 for (i = 1; area[i] ; i++)
734                 {
735                     area[i - 1] = area[i];
736                 }
737                 area[i - 1] = '\0';
738               }
739             }
740             break;
741
742         case RULE_DLAST:
743             if (area[0])
744             {
745               if ( strlen(area) > min_to_shift ) { 
746                 register int i;
747                 for (i = 1; area[i] ; i++);
748                 area[i - 1] = '\0';
749               }
750             }
751             break;
752
753         case RULE_MFIRST:
754             if (!ptr[1] || (ptr[1] == RULE_CLASS && !ptr[2]))
755             {
756                 Debug(1, "Mangle: '(' missing argument in '%s'\n", control);
757                 return ((char *) 0);
758             } else
759             {
760                 if (ptr[1] != RULE_CLASS)
761                 {
762                     ptr++;
763                     if (area[0] != *ptr)
764                     {
765                         return ((char *) 0);
766                     }
767                 } else
768                 {
769                     ptr += 2;
770                     if (!MatchClass(*ptr, area[0]))
771                     {
772                         return ((char *) 0);
773                     }
774                 }
775             }
776         case RULE_MLAST:
777             if (!ptr[1] || (ptr[1] == RULE_CLASS && !ptr[2]))
778             {
779                 Debug(1, "Mangle: ')' missing argument in '%s'\n", control);
780                 return ((char *) 0);
781             } else
782             {
783                 register int i;
784
785                 for (i = 0; area[i]; i++);
786
787                 if (i > 0)
788                 {
789                     i--;
790                 } else
791                 {
792                     return ((char *) 0);
793                 }
794
795                 if (ptr[1] != RULE_CLASS)
796                 {
797                     ptr++;
798                     if (area[i] != *ptr)
799                     {
800                         return ((char *) 0);
801                     }
802                 } else
803                 {
804                     ptr += 2;
805                     if (!MatchClass(*ptr, area[i]))
806                     {
807                         return ((char *) 0);
808                     }
809                 }
810             }
811
812         default:
813             Debug(1, "Mangle: unknown command %c in %s\n", *ptr, control);
814             return ((char *) 0);
815             break;
816         }
817     }
818     if (!area[0])               /* have we deweted de poor widdle fing away? */
819     {
820         return ((char *) 0);
821     }
822     return (area);
823 }
824
825 int
826 PMatch(control, string)
827 register char *control;
828 register char *string;
829 {
830     while (*string && *control)
831     {
832         if (!MatchClass(*control, *string))
833         {
834             return(0);
835         }
836
837         string++;
838         control++;
839     }
840
841     if (*string || *control)
842     {
843         return(0);
844     }
845
846     return(1);
847 }