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