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