1 /* @(#)softmagic.c	1.12 09/07/11 joerg */
2 #include <schily/mconfig.h>
3 #ifndef lint
4 static	UConst char sccsid[] =
5 	"@(#)softmagic.c	1.12 09/07/11 joerg";
6 #endif
7 /*
8 **	find file types by using a modified "magic" file
9 **
10 **	based on file v3.22 by Ian F. Darwin (see below)
11 **
12 **	Modified for mkhybrid James Pearson 19/5/98
13 */
14 
15 /*
16  * softmagic - interpret variable magic from /etc/magic
17  *
18  * Copyright (c) Ian F. Darwin, 1987.
19  * Written by Ian F. Darwin.
20  *
21  * This software is not subject to any export provision of the United States
22  * Department of Commerce, and may be exported to any country or planet.
23  *
24  * Redistribution and use in source and binary forms, with or without
25  * modification, are permitted provided that the following conditions
26  * are met:
27  * 1. Redistributions of source code must retain the above copyright
28  *    notice immediately at the beginning of the file, without modification,
29  *    this list of conditions, and the following disclaimer.
30  * 2. Redistributions in binary form must reproduce the above copyright
31  *    notice, this list of conditions and the following disclaimer in the
32  *    documentation and/or other materials provided with the distribution.
33  *
34  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
35  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
36  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
37  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
38  * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
39  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
40  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
41  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
42  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
43  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
44  * SUCH DAMAGE.
45  */
46 
47 #include <schily/stdio.h>
48 #include <schily/string.h>
49 #include <schily/stdlib.h>
50 #include <schily/schily.h>
51 
52 #include "file.h"
53 
54 #ifndef	lint
55 static UConst char moduleid[] =
56 	"@(#)$Id: softmagic.c,v 1.34 1997/01/15 19:28:35 christos Exp $";
57 #endif	/* lint */
58 
59 #ifdef DEBUG
60 int	debug = 1; 	/* debugging 				*/
61 #else
62 #define	debug	0 	/* debugging 				*/
63 #endif /* DEBUG */
64 
65 /* static int match	__PR((unsigned char *, int)); */
66 static char *match	__PR((unsigned char *, int));
67 static int mget		__PR((union VALUETYPE *,
68 			     unsigned char *, struct magic *, int));
69 /* QNX has a mcheck() prototyp in a public include file */
70 static int magcheck	__PR((union VALUETYPE *, struct magic *));
71 #ifdef	__used__
72 static void mdebug	__PR((Int32_t, char *, int));
73 #endif
74 static int mconvert	__PR((union VALUETYPE *, struct magic *));
75 
76 /*
77  * softmagic - lookup one file in database
78  * (already read from /etc/magic by apprentice.c).
79  * Passed the name and FILE * of one file to be typed.
80  */
81 /*ARGSUSED1*/		/* nbytes passed for regularity, maybe need later */
82 char *
softmagic(buf,nbytes)83 softmagic(buf, nbytes)
84 unsigned char *buf;
85 int nbytes;
86 {
87 	return (match(buf, nbytes));
88 }
89 
90 /*
91  * Go through the whole list, stopping if you find a match.  Process all
92  * the continuations of that match before returning.
93  *
94  * We support multi-level continuations:
95  *
96  *	At any time when processing a successful top-level match, there is a
97  *	current continuation level; it represents the level of the last
98  *	successfully matched continuation.
99  *
100  *	Continuations above that level are skipped as, if we see one, it
101  *	means that the continuation that controls them - i.e, the
102  *	lower-level continuation preceding them - failed to match.
103  *
104  *	Continuations below that level are processed as, if we see one,
105  *	it means we've finished processing or skipping higher-level
106  *	continuations under the control of a successful or unsuccessful
107  *	lower-level continuation, and are now seeing the next lower-level
108  *	continuation and should process it.  The current continuation
109  *	level reverts to the level of the one we're seeing.
110  *
111  *	Continuations at the current level are processed as, if we see
112  *	one, there's no lower-level continuation that may have failed.
113  *
114  *	If a continuation matches, we bump the current continuation level
115  *	so that higher-level continuations are processed.
116  */
117 static char *
match(s,nbytes)118 match(s, nbytes)
119 unsigned char	*s;
120 int nbytes;
121 {
122 	int magindex = 0;
123 	union VALUETYPE p;
124 
125 	for (magindex = 0; magindex < __f_nmagic; magindex++) {
126 		/* if main entry matches, print it... */
127 		if (!mget(&p, s, &__f_magic[magindex], nbytes) ||
128 		    !magcheck(&p, &__f_magic[magindex])) {
129 			    /*
130 			     * main entry didn't match,
131 			     * flush its continuations
132 			     */
133 			    while (magindex < __f_nmagic &&
134 			    	   __f_magic[magindex + 1].cont_level != 0)
135 			    	   magindex++;
136 			    continue;
137 		}
138 
139 		return (__f_magic[magindex].desc);
140 	}
141 	return 0;			/* no match at all */
142 }
143 
144 
145 /*
146  * Convert the byte order of the data we are looking at
147  */
148 static int
mconvert(p,m)149 mconvert(p, m)
150 union VALUETYPE *p;
151 struct magic *m;
152 {
153 	switch (m->type) {
154 	case BYTE:
155 	case SHORT:
156 	case LONG:
157 	case DATE:
158 		return 1;
159 	case STRING:
160 		{
161 			char *ptr;
162 
163 			/* Null terminate and eat the return */
164 			p->s[sizeof(p->s) - 1] = '\0';
165 			if ((ptr = strchr(p->s, '\n')) != NULL)
166 				*ptr = '\0';
167 			return 1;
168 		}
169 	case BESHORT:
170 		p->h = (short)((p->hs[0]<<8)|(p->hs[1]));
171 		return 1;
172 	case BELONG:
173 	case BEDATE:
174 		p->l = (Int32_t)
175 		    ((p->hl[0]<<24)|(p->hl[1]<<16)|(p->hl[2]<<8)|(p->hl[3]));
176 		return 1;
177 	case LESHORT:
178 		p->h = (short)((p->hs[1]<<8)|(p->hs[0]));
179 		return 1;
180 	case LELONG:
181 	case LEDATE:
182 		p->l = (Int32_t)
183 		    ((p->hl[3]<<24)|(p->hl[2]<<16)|(p->hl[1]<<8)|(p->hl[0]));
184 		return 1;
185 	default:
186 		return 0;
187 	}
188 }
189 
190 #ifdef	__used__
191 static void
mdebug(offset,str,len)192 mdebug(offset, str, len)
193 Int32_t offset;
194 char *str;
195 int len;
196 {
197 	(void) fprintf(stderr, "mget @%d: ", offset);
198 	showstr(stderr, (char *) str, len);
199 	(void) fputc('\n', stderr);
200 	(void) fputc('\n', stderr);
201 }
202 #endif
203 
204 static int
mget(p,s,m,nbytes)205 mget(p, s, m, nbytes)
206 union VALUETYPE* p;
207 unsigned char	*s;
208 struct magic *m;
209 int nbytes;
210 {
211 	Int32_t offset = m->offset;
212 
213 	if (offset + sizeof(union VALUETYPE) <= nbytes)
214 		memcpy(p, s + offset, sizeof(union VALUETYPE));
215 	else {
216 		/*
217 		 * the usefulness of padding with zeroes eludes me, it
218 		 * might even cause problems
219 		 */
220 		Int32_t have = nbytes - offset;
221 		memset(p, 0, sizeof(union VALUETYPE));
222 		if (have > 0)
223 			memcpy(p, s + offset, have);
224 	}
225 
226 	if (!mconvert(p, m))
227 		return 0;
228 
229 	if (m->flag & INDIR) {
230 
231 		switch (m->in.type) {
232 		case BYTE:
233 			offset = p->b + m->in.offset;
234 			break;
235 		case SHORT:
236 			offset = p->h + m->in.offset;
237 			break;
238 		case LONG:
239 			offset = p->l + m->in.offset;
240 			break;
241 		}
242 
243 		if (offset + sizeof(union VALUETYPE) > nbytes)
244 			return 0;
245 
246 		memcpy(p, s + offset, sizeof(union VALUETYPE));
247 
248 		if (!mconvert(p, m))
249 			return 0;
250 	}
251 	return 1;
252 }
253 
254 static int
magcheck(p,m)255 magcheck(p, m)
256 union VALUETYPE* p;
257 struct magic *m;
258 {
259 	register UInt32_t l = m->value.l;
260 	register UInt32_t v;
261 	int matched;
262 
263 	if ( (m->value.s[0] == 'x') && (m->value.s[1] == '\0') ) {
264 		fprintf(stderr, "BOINK");
265 		return 1;
266 	}
267 
268 
269 	switch (m->type) {
270 	case BYTE:
271 		v = p->b;
272 		break;
273 
274 	case SHORT:
275 	case BESHORT:
276 	case LESHORT:
277 		v = p->h;
278 		break;
279 
280 	case LONG:
281 	case BELONG:
282 	case LELONG:
283 	case DATE:
284 	case BEDATE:
285 	case LEDATE:
286 		v = p->l;
287 		break;
288 
289 	case STRING:
290 		l = 0;
291 		/* What we want here is:
292 		 * v = strncmp(m->value.s, p->s, m->vallen);
293 		 * but ignoring any nulls.  bcmp doesn't give -/+/0
294 		 * and isn't universally available anyway.
295 		 */
296 		v = 0;
297 		{
298 			register unsigned char *a = (unsigned char*)m->value.s;
299 			register unsigned char *b = (unsigned char*)p->s;
300 			register int len = m->vallen;
301 
302 			while (--len >= 0)
303 				if ((v = *b++ - *a++) != '\0')
304 					break;
305 		}
306 		break;
307 	default:
308 		return 0;/*NOTREACHED*/
309 	}
310 
311 	v = signextend(m, v) & m->mask;
312 
313 	switch (m->reln) {
314 	case 'x':
315 		if (debug)
316 			(void) fprintf(stderr, "%u == *any* = 1\n", v);
317 		matched = 1;
318 		break;
319 
320 	case '!':
321 		matched = v != l;
322 		if (debug)
323 			(void) fprintf(stderr, "%u != %u = %d\n",
324 				       v, l, matched);
325 		break;
326 
327 	case '=':
328 		matched = v == l;
329 		if (debug)
330 			(void) fprintf(stderr, "%u == %u = %d\n",
331 				       v, l, matched);
332 		break;
333 
334 	case '>':
335 		if (m->flag & UNSIGNED) {
336 			matched = v > l;
337 			if (debug)
338 				(void) fprintf(stderr, "%u > %u = %d\n",
339 					       v, l, matched);
340 		}
341 		else {
342 			matched = (Int32_t) v > (Int32_t) l;
343 			if (debug)
344 				(void) fprintf(stderr, "%d > %d = %d\n",
345 					    (Int32_t)v, (Int32_t)l, matched);
346 		}
347 		break;
348 
349 	case '<':
350 		if (m->flag & UNSIGNED) {
351 			matched = v < l;
352 			if (debug)
353 				(void) fprintf(stderr, "%u < %u = %d\n",
354 					       v, l, matched);
355 		}
356 		else {
357 			matched = (Int32_t) v < (Int32_t) l;
358 			if (debug)
359 				(void) fprintf(stderr, "%d < %d = %d\n",
360 					    (Int32_t)v, (Int32_t)l, matched);
361 		}
362 		break;
363 
364 	case '&':
365 		matched = (v & l) == l;
366 		if (debug)
367 			(void) fprintf(stderr, "((%x & %x) == %x) = %d\n",
368 				       v, l, l, matched);
369 		break;
370 
371 	case '^':
372 		matched = (v & l) != l;
373 		if (debug)
374 			(void) fprintf(stderr, "((%x & %x) != %x) = %d\n",
375 				       v, l, l, matched);
376 		break;
377 
378 	default:
379 		matched = 0;
380 		break;/*NOTREACHED*/
381 	}
382 
383 	return matched;
384 }
385