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