/*
* Copyright 2005 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
/*
* This program is copyright Alec Muffett 1993. The author disclaims all
* responsibility or liability with respect to it's usage or its effect
* upon hardware or computer systems, and maintains copyright as set out
* in the "LICENCE" document which accompanies distributions of Crack v4.0
* and upwards.
*/
#include "packer.h"
#define RULE_NOOP ':'
#define RULE_PREPEND '^'
#define RULE_APPEND '$'
#define RULE_REVERSE 'r'
#define RULE_UPPERCASE 'u'
#define RULE_LOWERCASE 'l'
#define RULE_PLURALISE 'p'
#define RULE_CAPITALISE 'c'
#define RULE_DUPLICATE 'd'
#define RULE_REFLECT 'f'
#define RULE_SUBSTITUTE 's'
#define RULE_MATCH '/'
#define RULE_NOT '!'
#define RULE_LT '<'
#define RULE_GT '>'
#define RULE_EXTRACT 'x'
#define RULE_OVERSTRIKE 'o'
#define RULE_INSERT 'i'
#define RULE_EQUALS '='
#define RULE_PURGE '@'
#define RULE_CLASS '?' /* class rule? socialist ethic in cracker? */
#define RULE_DFIRST '['
#define RULE_DLAST ']'
#define RULE_MFIRST '('
#define RULE_MLAST ')'
int
Suffix(char *myword, char *suffix)
{
register int i;
register int j;
i = strlen(myword);
j = strlen(suffix);
if (i > j) {
return (STRCMP((myword + i - j), suffix));
} else {
return (-1);
}
}
char *
Reverse(register char *str) /* return a pointer to a reversal */
{
register int i;
register int j;
static char area[PATH_MAX];
j = i = strlen(str);
while (*str) {
area[--i] = *str++;
}
area[j] = '\0';
return (area);
}
char *
Uppercase(register char *str) /* return a pointer to an uppercase */
{
register char *ptr;
static char area[PATH_MAX];
ptr = area;
while (*str) {
*(ptr++) = CRACK_TOUPPER(*str);
str++;
}
*ptr = '\0';
return (area);
}
char *
Lowercase(register char *str) /* return a pointer to an lowercase */
{
register char *ptr;
static char area[PATH_MAX];
ptr = area;
while (*str) {
*(ptr++) = CRACK_TOLOWER(*str);
str++;
}
*ptr = '\0';
return (area);
}
char *
Capitalise(register char *str) /* return a pointer to an capitalised */
{
register char *ptr;
static char area[PATH_MAX];
ptr = area;
while (*str) {
*(ptr++) = CRACK_TOLOWER(*str);
str++;
}
*ptr = '\0';
area[0] = CRACK_TOUPPER(area[0]);
return (area);
}
char *
Pluralise(register char *string) /* returns a pointer to a plural */
{
register int length;
static char area[PATH_MAX];
length = strlen(string);
(void) strlcpy(area, string, PATH_MAX);
if (!Suffix(string, "ch") ||
!Suffix(string, "ex") ||
!Suffix(string, "ix") ||
!Suffix(string, "sh") ||
!Suffix(string, "ss")) {
/* bench -> benches */
(void) strcat(area, "es");
} else if (length > 2 && string[length - 1] == 'y') {
if (strchr("aeiou", string[length - 2])) {
/* alloy -> alloys */
(void) strcat(area, "s");
} else {
/* gully -> gullies */
(void) strcpy(area + length - 1, "ies");
}
} else if (string[length - 1] == 's') {
/* bias -> biases */
(void) strcat(area, "es");
} else {
/* catchall */
(void) strcat(area, "s");
}
return (area);
}
char *
Substitute(register char *string, register char old,
register char new) /* returns pointer to a swapped about copy */
{
register char *ptr;
static char area[PATH_MAX];
ptr = area;
while (*string) {
*(ptr++) = (*string == old ? new : *string);
string++;
}
*ptr = '\0';
return (area);
}
/* returns pointer to a purged copy */
char *
Purge(register char *string, register char target)
{
register char *ptr;
static char area[PATH_MAX];
ptr = area;
while (*string) {
if (*string != target) {
*(ptr++) = *string;
}
string++;
}
*ptr = '\0';
return (area);
}
/* -------- CHARACTER CLASSES START HERE -------- */
/*
* this function takes two inputs, a class identifier and a character, and
* returns non-null if the given character is a member of the class, based
* upon restrictions set out below
*/
int
MatchClass(register char class, register char input)
{
register char c;
register int retval;
retval = 0;
switch (class) {
/* ESCAPE */
case '?': /* ?? -> ? */
if (input == '?') {
retval = 1;
}
break;
/* ILLOGICAL GROUPINGS (ie: not in ctype.h) */
case 'V':
case 'v': /* vowels */
c = CRACK_TOLOWER(input);
if (strchr("aeiou", c)) {
retval = 1;
}
break;
case 'C':
case 'c': /* consonants */
c = CRACK_TOLOWER(input);
if (strchr("bcdfghjklmnpqrstvwxyz", c)) {
retval = 1;
}
break;
case 'W':
case 'w': /* whitespace */
if (strchr("\t ", input)) {
retval = 1;
}
break;
case 'P':
case 'p': /* punctuation */
if (strchr(".`,:;'!?\"", input)) {
retval = 1;
}
break;
case 'S':
case 's': /* symbols */
if (strchr("$%%^&*()-_+=|\\[]{}#@/~", input)) {
retval = 1;
}
break;
/* LOGICAL GROUPINGS */
case 'L':
case 'l': /* lowercase */
if (islower(input)) {
retval = 1;
}
break;
case 'U':
case 'u': /* uppercase */
if (isupper(input)) {
retval = 1;
}
break;
case 'A':
case 'a': /* alphabetic */
if (isalpha(input)) {
retval = 1;
}
break;
case 'X':
case 'x': /* alphanumeric */
if (isalnum(input)) {
retval = 1;
}
break;
case 'D':
case 'd': /* digits */
if (isdigit(input)) {
retval = 1;
}
break;
}
if (isupper(class)) {
return (!retval);
}
return (retval);
}
char *
PolyStrchr(register char *string, register char class)
{
while (*string) {
if (MatchClass(class, *string)) {
return (string);
}
string++;
}
return ((char *)0);
}
/* returns pointer to a swapped about copy */
char *
PolySubst(register char *string, register char class, register char new)
{
register char *ptr;
static char area[PATH_MAX];
ptr = area;
while (*string) {
*(ptr++) = (MatchClass(class, *string) ? new : *string);
string++;
}
*ptr = '\0';
return (area);
}
/* returns pointer to a purged copy */
char *
PolyPurge(register char *string, register char class)
{
register char *ptr;
static char area[PATH_MAX];
ptr = area;
while (*string) {
if (!MatchClass(class, *string)) {
*(ptr++) = *string;
}
string++;
}
*ptr = '\0';
return (area);
}
/* -------- BACK TO NORMALITY -------- */
int
Char2Int(char character)
{
if (isdigit(character)) {
return (character - '0');
} else if (islower(character)) {
return (character - 'a' + 10);
} else if (isupper(character)) {
return (character - 'A' + 10);
}
return (-1);
}
/* returns a pointer to a controlled Mangle */
char *
Mangle(char *input, char *control)
{
int limit;
register char *ptr;
static char area[PATH_MAX];
char area2[PATH_MAX];
area[0] = '\0';
(void) strlcpy(area, input, PATH_MAX);
for (ptr = control; *ptr; ptr++) {
switch (*ptr) {
case RULE_NOOP:
break;
case RULE_REVERSE:
(void) strlcpy(area, Reverse(area), PATH_MAX);
break;
case RULE_UPPERCASE:
(void) strlcpy(area, Uppercase(area), PATH_MAX);
break;
case RULE_LOWERCASE:
(void) strlcpy(area, Lowercase(area), PATH_MAX);
break;
case RULE_CAPITALISE:
(void) strlcpy(area, Capitalise(area),
PATH_MAX);
break;
case RULE_PLURALISE:
(void) strlcpy(area, Pluralise(area), PATH_MAX);
break;
case RULE_REFLECT:
(void) strlcat(area, Reverse(area), PATH_MAX);
break;
case RULE_DUPLICATE:
(void) strlcpy(area2, area, PATH_MAX);
(void) strlcat(area, area2, PATH_MAX);
break;
case RULE_GT:
if (!ptr[1]) {
return ((char *)0);
} else {
limit = Char2Int(*(++ptr));
if (limit < 0) {
return ((char *)0);
}
if (strlen(area) <= limit) {
return ((char *)0);
}
}
break;
case RULE_LT:
if (!ptr[1]) {
return ((char *)0);
} else {
limit = Char2Int(*(++ptr));
if (limit < 0) {
return ((char *)0);
}
if (strlen(area) >= limit) {
return ((char *)0);
}
}
break;
case RULE_PREPEND:
if (!ptr[1]) {
return ((char *)0);
} else {
area2[0] = *(++ptr);
(void) strlcpy(area2 + 1, area,
PATH_MAX);
(void) strlcpy(area, area2, PATH_MAX);
}
break;
case RULE_APPEND:
if (!ptr[1]) {
return ((char *)0);
} else {
register char *string;
string = area;
while (*(string++));
string[-1] = *(++ptr);
*string = '\0';
}
break;
case RULE_EXTRACT:
if (!ptr[1] || !ptr[2]) {
return ((char *)0);
} else {
register int i;
int start;
int length;
start = Char2Int(*(++ptr));
length = Char2Int(*(++ptr));
if (start < 0 || length < 0) {
return ((char *)0);
}
(void) strlcpy(area2, area, PATH_MAX);
for (i = 0; length-- &&
area2[start + i]; i++) {
area[i] = area2[start + i];
}
/* cant use strncpy()-no trailing NUL */
area[i] = '\0';
}
break;
case RULE_OVERSTRIKE:
if (!ptr[1] || !ptr[2]) {
return ((char *)0);
} else {
register int i;
i = Char2Int(*(++ptr));
if (i < 0) {
return ((char *)0);
} else {
++ptr;
if (area[i]) {
area[i] = *ptr;
}
}
}
break;
case RULE_INSERT:
if (!ptr[1] || !ptr[2]) {
return ((char *)0);
} else {
register int i;
register char *p1;
register char *p2;
i = Char2Int(*(++ptr));
if (i < 0) {
return ((char *)0);
}
p1 = area;
p2 = area2;
while (i && *p1) {
i--;
*(p2++) = *(p1++);
}
*(p2++) = *(++ptr);
(void) strlcpy(p2, p1, PATH_MAX);
(void) strlcpy(area, area2, PATH_MAX);
}
break;
/* THE FOLLOWING RULES REQUIRE CLASS MATCHING */
case RULE_PURGE: /* @x or @?c */
if (!ptr[1] || (ptr[1] ==
RULE_CLASS && !ptr[2])) {
return ((char *)0);
} else if (ptr[1] != RULE_CLASS) {
(void) strlcpy(area, Purge(area,
*(++ptr)), PATH_MAX);
} else {
(void) strlcpy(area, PolyPurge(area,
ptr[2]), PATH_MAX);
ptr += 2;
}
break;
case RULE_SUBSTITUTE: /* sxy || s?cy */
if (!ptr[1] || !ptr[2] ||
(ptr[1] == RULE_CLASS && !ptr[3])) {
return ((char *)0);
} else if (ptr[1] != RULE_CLASS) {
ptr += 2;
} else {
(void) strlcpy(area, PolySubst(area,
ptr[2], ptr[3]), PATH_MAX);
ptr += 3;
}
break;
case RULE_MATCH: /* /x || /?c */
if (!ptr[1] ||
(ptr[1] == RULE_CLASS && !ptr[2])) {
return ((char *)0);
} else if (ptr[1] != RULE_CLASS) {
if (!strchr(area, *(++ptr))) {
return ((char *)0);
}
} else {
if (!PolyStrchr(area, ptr[2])) {
return ((char *)0);
}
ptr += 2;
}
break;
case RULE_NOT: /* !x || !?c */
if (!ptr[1] ||
(ptr[1] == RULE_CLASS && !ptr[2])) {
return ((char *)0);
} else if (ptr[1] != RULE_CLASS) {
if (strchr(area, *(++ptr))) {
return ((char *)0);
}
} else {
if (PolyStrchr(area, ptr[2])) {
return ((char *)0);
}
ptr += 2;
}
break;
/*
* alternative use for a boomerang, number 1: a standard throwing
* boomerang is an ideal thing to use to tuck the sheets under
* the mattress when making your bed. The streamlined shape of
* the boomerang allows it to slip easily 'twixt mattress and
* bedframe, and it's curve makes it very easy to hook sheets
* into the gap.
*/
case RULE_EQUALS: /* =nx || =n?c */
if (!ptr[1] || !ptr[2] ||
(ptr[2] == RULE_CLASS && !ptr[3])) {
return ((char *)0);
} else {
register int i;
if ((i = Char2Int(ptr[1])) < 0) {
return ((char *)0);
}
if (ptr[2] != RULE_CLASS) {
ptr += 2;
if (area[i] != *ptr) {
return ((char *)0);
}
} else {
ptr += 3;
if (!MatchClass(*ptr,
area[i])) {
return ((char *)0);
}
}
}
break;
case RULE_DFIRST:
if (area[0]) {
register int i;
for (i = 1; area[i]; i++) {
area[i - 1] = area[i];
}
area[i - 1] = '\0';
}
break;
case RULE_DLAST:
if (area[0]) {
register int i;
for (i = 1; area[i]; i++);
area[i - 1] = '\0';
}
break;
case RULE_MFIRST:
if (!ptr[1] ||
(ptr[1] == RULE_CLASS && !ptr[2])) {
return ((char *)0);
} else {
if (ptr[1] != RULE_CLASS) {
ptr++;
if (area[0] != *ptr) {
return ((char *)0);
}
} else {
ptr += 2;
if (!MatchClass(*ptr,
area[0])) {
return ((char *)0);
}
}
}
break;
case RULE_MLAST:
if (!ptr[1] ||
(ptr[1] == RULE_CLASS && !ptr[2])) {
return ((char *)0);
} else {
register int i;
for (i = 0; area[i]; i++);
if (i > 0) {
i--;
} else {
return ((char *)0);
}
if (ptr[1] != RULE_CLASS) {
ptr++;
if (area[i] != *ptr) {
return ((char *)0);
}
} else {
ptr += 2;
if (!MatchClass(*ptr,
area[i])) {
return ((char *)0);
}
}
}
break;
}
}
if (!area[0]) { /* have we deweted de poor widdle fing away? */
return ((char *)0);
}
return (area);
}
/*
* int
* PMatch(register char *control, register char *string)
* {
* while (*string && *control) {
* if (!MatchClass(*control, *string)) {
* return (0);
* }
*
* string++;
* control++;
* }
*
* if (*string || *control) {
* return (0);
* }
*
* return (1);
* }
*/