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-22 Russ Allbery <rra@stanford.edu>
13 * - Cap deletion of leading or trailing characters at one more than half
14 * the length of the password string and no more than five characters.
15 * This goes with a change to fascist.c that adds rules to delete more
16 * leading and trailing characters for longer passwords.
17 * - Additional system includes for other functions.
18 * 2009-10-14 Russ Allbery <rra@stanford.edu>
19 * - Simplify Debug() function for how it's actually called.
20 * - Add ANSI C protototypes for all functions.
21 * - Tweaks for const cleanliness.
22 * - Make internal functions static.
23 * - Remove unused variables.
24 * - Changed a variable to unsigned to avoid gcc warnings.
27 static const char vers_id[] = "rules.c : v5.0p3 Alec Muffett 20 May 1993";
40 Debug(int val, const char *fmt, ...)
46 vfprintf(stderr, fmt, args);
56 #define RULE_PREPEND '^'
57 #define RULE_APPEND '$'
58 #define RULE_REVERSE 'r'
59 #define RULE_UPPERCASE 'u'
60 #define RULE_LOWERCASE 'l'
61 #define RULE_PLURALISE 'p'
62 #define RULE_CAPITALISE 'c'
63 #define RULE_DUPLICATE 'd'
64 #define RULE_REFLECT 'f'
65 #define RULE_SUBSTITUTE 's'
66 #define RULE_MATCH '/'
70 #define RULE_EXTRACT 'x'
71 #define RULE_OVERSTRIKE 'o'
72 #define RULE_INSERT 'i'
73 #define RULE_EQUALS '='
74 #define RULE_PURGE '@'
75 #define RULE_CLASS '?' /* class rule? socialist ethic in cracker? */
77 #define RULE_DFIRST '['
78 #define RULE_DLAST ']'
79 #define RULE_MFIRST '('
80 #define RULE_MLAST ')'
83 Suffix(const char *myword, const char *suffix)
92 return (STRCMP((myword + i - j), suffix));
99 /* return a pointer to a reversal */
101 Reverse(const char *str)
105 static char area[STRINGSIZE];
115 /* return a pointer to an uppercase */
117 Uppercase(const char *str)
120 static char area[STRINGSIZE];
124 *(ptr++) = CRACK_TOUPPER(*str);
132 /* return a pointer to an lowercase */
134 Lowercase(const char *str)
137 static char area[STRINGSIZE];
141 *(ptr++) = CRACK_TOLOWER(*str);
149 /* return a pointer to an capitalised */
151 Capitalise(const char *str)
154 static char area[STRINGSIZE];
159 *(ptr++) = CRACK_TOLOWER(*str);
164 area[0] = CRACK_TOUPPER(area[0]);
168 /* returns a pointer to a plural */
170 Pluralise(const char *string)
173 static char area[STRINGSIZE];
174 length = strlen(string);
175 strcpy(area, string);
177 if (!Suffix(string, "ch") ||
178 !Suffix(string, "ex") ||
179 !Suffix(string, "ix") ||
180 !Suffix(string, "sh") ||
181 !Suffix(string, "ss"))
183 /* bench -> benches */
185 } else if (length > 2 && string[length - 1] == 'y')
187 if (strchr("aeiou", string[length - 2]))
189 /* alloy -> alloys */
193 /* gully -> gullies */
194 strcpy(area + length - 1, "ies");
196 } else if (string[length - 1] == 's')
209 /* returns pointer to a swapped about copy */
211 Substitute(const char *string, char old, char new)
214 static char area[STRINGSIZE];
218 *(ptr++) = (*string == old ? new : *string);
225 /* returns pointer to a purged copy */
227 Purge(const char *string, char target)
230 static char area[STRINGSIZE];
234 if (*string != target)
243 /* -------- CHARACTER CLASSES START HERE -------- */
246 * this function takes two inputs, a class identifier and a character, and
247 * returns non-null if the given character is a member of the class, based
248 * upon restrictions set out below
252 MatchClass(char class, char input)
262 case '?': /* ?? -> ? */
269 /* ILLOGICAL GROUPINGS (ie: not in ctype.h) */
272 case 'v': /* vowels */
273 c = CRACK_TOLOWER(input);
274 if (strchr("aeiou", c))
281 case 'c': /* consonants */
282 c = CRACK_TOLOWER(input);
283 if (strchr("bcdfghjklmnpqrstvwxyz", c))
290 case 'w': /* whitespace */
291 if (strchr("\t ", input))
298 case 'p': /* punctuation */
299 if (strchr(".`,:;'!?\"", input))
306 case 's': /* symbols */
307 if (strchr("$%%^&*()-_+=|\\[]{}#@/~", input))
313 /* LOGICAL GROUPINGS */
316 case 'l': /* lowercase */
324 case 'u': /* uppercase */
332 case 'a': /* alphabetic */
340 case 'x': /* alphanumeric */
348 case 'd': /* digits */
356 Debug(1, "MatchClass: unknown class %c\n", class);
369 PolyStrchr(const char *string, char class)
373 if (MatchClass(class, *string))
382 /* returns pointer to a swapped about copy */
384 PolySubst(const char *string, char class, char new)
387 static char area[STRINGSIZE];
391 *(ptr++) = (MatchClass(class, *string) ? new : *string);
398 /* returns pointer to a purged copy */
400 PolyPurge(const char *string, const char class)
403 static char area[STRINGSIZE];
407 if (!MatchClass(class, *string))
416 /* -------- BACK TO NORMALITY -------- */
419 Char2Int(char character)
421 if (isdigit(character))
423 return (character - '0');
424 } else if (islower(character))
426 return (character - 'a' + 10);
427 } else if (isupper(character))
429 return (character - 'A' + 10);
434 /* returns a pointer to a controlled Mangle */
436 Mangle(const char *input, const char *control)
438 int limit, min_to_shift;
441 static char area[STRINGSIZE];
442 char area2[STRINGSIZE];
449 min_to_shift = (j + 1) / 2;
452 min_to_shift = j / 2;
455 if (min_to_shift > 5)
460 for (ptr = control; *ptr; ptr++)
467 strcpy(area, Reverse(area));
470 strcpy(area, Uppercase(area));
473 strcpy(area, Lowercase(area));
475 case RULE_CAPITALISE:
476 strcpy(area, Capitalise(area));
479 strcpy(area, Pluralise(area));
482 strcat(area, Reverse(area));
491 Debug(1, "Mangle: '>' missing argument in '%s'\n", control);
495 limit = Char2Int(*(++ptr));
498 Debug(1, "Mangle: '>' weird argument in '%s'\n", control);
501 if (strlen(area) <= (size_t) limit)
510 Debug(1, "Mangle: '<' missing argument in '%s'\n", control);
514 limit = Char2Int(*(++ptr));
517 Debug(1, "Mangle: '<' weird argument in '%s'\n", control);
520 if (strlen(area) >= (size_t) limit)
529 Debug(1, "Mangle: prepend missing argument in '%s'\n", control);
534 strcpy(area2 + 1, area);
541 Debug(1, "Mangle: append missing argument in '%s'\n", control);
545 register char *string;
548 string[-1] = *(++ptr);
553 if (!ptr[1] || !ptr[2])
555 Debug(1, "Mangle: extract missing argument in '%s'\n", control);
562 start = Char2Int(*(++ptr));
563 length = Char2Int(*(++ptr));
564 if (start < 0 || length < 0)
566 Debug(1, "Mangle: extract: weird argument in '%s'\n", control);
570 for (i = 0; length-- && area2[start + i]; i++)
572 area[i] = area2[start + i];
574 /* cant use strncpy() - no trailing NUL */
578 case RULE_OVERSTRIKE:
579 if (!ptr[1] || !ptr[2])
581 Debug(1, "Mangle: overstrike missing argument in '%s'\n", control);
586 i = Char2Int(*(++ptr));
589 Debug(1, "Mangle: overstrike weird argument in '%s'\n",
603 if (!ptr[1] || !ptr[2])
605 Debug(1, "Mangle: insert missing argument in '%s'\n", control);
612 i = Char2Int(*(++ptr));
615 Debug(1, "Mangle: insert weird argument in '%s'\n",
631 /* THE FOLLOWING RULES REQUIRE CLASS MATCHING */
633 case RULE_PURGE: /* @x or @?c */
634 if (!ptr[1] || (ptr[1] == RULE_CLASS && !ptr[2]))
636 Debug(1, "Mangle: delete missing arguments in '%s'\n", control);
638 } else if (ptr[1] != RULE_CLASS)
640 strcpy(area, Purge(area, *(++ptr)));
643 strcpy(area, PolyPurge(area, ptr[2]));
647 case RULE_SUBSTITUTE: /* sxy || s?cy */
648 if (!ptr[1] || !ptr[2] || (ptr[1] == RULE_CLASS && !ptr[3]))
650 Debug(1, "Mangle: subst missing argument in '%s'\n", control);
652 } else if (ptr[1] != RULE_CLASS)
654 strcpy(area, Substitute(area, ptr[1], ptr[2]));
658 strcpy(area, PolySubst(area, ptr[2], ptr[3]));
662 case RULE_MATCH: /* /x || /?c */
663 if (!ptr[1] || (ptr[1] == RULE_CLASS && !ptr[2]))
665 Debug(1, "Mangle: '/' missing argument in '%s'\n", control);
667 } else if (ptr[1] != RULE_CLASS)
669 if (!strchr(area, *(++ptr)))
675 if (!PolyStrchr(area, ptr[2]))
682 case RULE_NOT: /* !x || !?c */
683 if (!ptr[1] || (ptr[1] == RULE_CLASS && !ptr[2]))
685 Debug(1, "Mangle: '!' missing argument in '%s'\n", control);
687 } else if (ptr[1] != RULE_CLASS)
689 if (strchr(area, *(++ptr)))
695 if (PolyStrchr(area, ptr[2]))
703 * alternative use for a boomerang, number 1: a standard throwing
704 * boomerang is an ideal thing to use to tuck the sheets under
705 * the mattress when making your bed. The streamlined shape of
706 * the boomerang allows it to slip easily 'twixt mattress and
707 * bedframe, and it's curve makes it very easy to hook sheets
711 case RULE_EQUALS: /* =nx || =n?c */
712 if (!ptr[1] || !ptr[2] || (ptr[2] == RULE_CLASS && !ptr[3]))
714 Debug(1, "Mangle: '=' missing argument in '%s'\n", control);
719 if ((i = Char2Int(ptr[1])) < 0)
721 Debug(1, "Mangle: '=' weird argument in '%s'\n", control);
724 if (ptr[2] != RULE_CLASS)
734 if (!MatchClass(*ptr, area[i]))
743 if (area[0] && strlen(area) > (size_t) min_to_shift)
746 for (i = 1; area[i]; i++)
748 area[i - 1] = area[i];
755 if (area[0] && strlen(area) > (size_t) min_to_shift)
758 for (i = 1; area[i]; i++);
764 if (!ptr[1] || (ptr[1] == RULE_CLASS && !ptr[2]))
766 Debug(1, "Mangle: '(' missing argument in '%s'\n", control);
770 if (ptr[1] != RULE_CLASS)
780 if (!MatchClass(*ptr, area[0]))
787 if (!ptr[1] || (ptr[1] == RULE_CLASS && !ptr[2]))
789 Debug(1, "Mangle: ')' missing argument in '%s'\n", control);
795 for (i = 0; area[i]; i++);
805 if (ptr[1] != RULE_CLASS)
815 if (!MatchClass(*ptr, area[i]))
823 Debug(1, "Mangle: unknown command %c in %s\n", *ptr, control);
828 if (!area[0]) /* have we deweted de poor widdle fing away? */
836 PMatch(const char *control, const char *string)
838 while (*string && *control)
840 if (!MatchClass(*control, *string))
849 if (*string || *control)