1 /*
2 **	find file types by using a modified "magic" file
3 **
4 **	based on file v3.22 by Ian F. Darwin (see below)
5 **
6 **	Modified for mkhybrid James Pearson 19/5/98
7 */
8 
9 /*
10  * softmagic - interpret variable magic from /etc/magic
11  *
12  * Copyright (c) Ian F. Darwin, 1987.
13  * Written by Ian F. Darwin.
14  *
15  * This software is not subject to any license of the American Telephone
16  * and Telegraph Company or of the Regents of the University of California.
17  *
18  * Permission is granted to anyone to use this software for any purpose on
19  * any computer system, and to alter it and redistribute it freely, subject
20  * to the following restrictions:
21  *
22  * 1. The author is not responsible for the consequences of use of this
23  *    software, no matter how awful, even if they arise from flaws in it.
24  *
25  * 2. The origin of this software must not be misrepresented, either by
26  *    explicit claim or by omission.  Since few users ever read sources,
27  *    credits must appear in the documentation.
28  *
29  * 3. Altered versions must be plainly marked as such, and must not be
30  *    misrepresented as being the original software.  Since few users
31  *    ever read sources, credits must appear in the documentation.
32  *
33  * 4. This notice may not be removed or altered.
34  */
35 
36 #include <stdio.h>
37 #include <string.h>
38 #include <stdlib.h>
39 #include <time.h>
40 #include <sys/types.h>
41 
42 #include "file.h"
43 
44 /* static int match	__P((unsigned char *, int)); */
45 static char *match	__P((unsigned char *, int));
46 static int mget		__P((union VALUETYPE *,
47 			     unsigned char *, struct magic *, int));
48 static int mcheck	__P((union VALUETYPE *, struct magic *));
49 static int mconvert	__P((union VALUETYPE *, struct magic *));
50 
51 /*
52  * softmagic - lookup one file in database
53  * (already read from /etc/magic by apprentice.c).
54  * Passed the name and FILE * of one file to be typed.
55  */
56 /*ARGSUSED1*/		/* nbytes passed for regularity, maybe need later */
57 char *
58 softmagic(buf, nbytes)
59 unsigned char *buf;
60 int nbytes;
61 {
62 	return (match(buf, nbytes));
63 }
64 
65 /*
66  * Go through the whole list, stopping if you find a match.  Process all
67  * the continuations of that match before returning.
68  *
69  * We support multi-level continuations:
70  *
71  *	At any time when processing a successful top-level match, there is a
72  *	current continuation level; it represents the level of the last
73  *	successfully matched continuation.
74  *
75  *	Continuations above that level are skipped as, if we see one, it
76  *	means that the continuation that controls them - i.e, the
77  *	lower-level continuation preceding them - failed to match.
78  *
79  *	Continuations below that level are processed as, if we see one,
80  *	it means we've finished processing or skipping higher-level
81  *	continuations under the control of a successful or unsuccessful
82  *	lower-level continuation, and are now seeing the next lower-level
83  *	continuation and should process it.  The current continuation
84  *	level reverts to the level of the one we're seeing.
85  *
86  *	Continuations at the current level are processed as, if we see
87  *	one, there's no lower-level continuation that may have failed.
88  *
89  *	If a continuation matches, we bump the current continuation level
90  *	so that higher-level continuations are processed.
91  */
92 static char *
93 match(s, nbytes)
94 unsigned char	*s;
95 int nbytes;
96 {
97 	int magindex = 0;
98 	union VALUETYPE p;
99 
100 	for (magindex = 0; magindex < nmagic; magindex++) {
101 		/* if main entry matches, print it... */
102 		if (!mget(&p, s, &magic[magindex], nbytes) ||
103 		    !mcheck(&p, &magic[magindex])) {
104 			    /*
105 			     * main entry didn't match,
106 			     * flush its continuations
107 			     */
108 			    while (magindex < nmagic &&
109 			    	   magic[magindex + 1].cont_level != 0)
110 			    	   magindex++;
111 			    continue;
112 		}
113 
114 		return (magic[magindex].desc);
115 	}
116 	return 0;			/* no match at all */
117 }
118 
119 
120 /*
121  * Convert the byte order of the data we are looking at
122  */
123 static int
124 mconvert(p, m)
125 union VALUETYPE *p;
126 struct magic *m;
127 {
128 	switch (m->type) {
129 	case BYTE:
130 	case SHORT:
131 	case LONG:
132 	case DATE:
133 		return 1;
134 	case STRING:
135 		{
136 			char *ptr;
137 
138 			/* Null terminate and eat the return */
139 			p->s[sizeof(p->s) - 1] = '\0';
140 			if ((ptr = strchr(p->s, '\n')) != NULL)
141 				*ptr = '\0';
142 			return 1;
143 		}
144 	case BESHORT:
145 		p->h = (short)((p->hs[0]<<8)|(p->hs[1]));
146 		return 1;
147 	case BELONG:
148 	case BEDATE:
149 		p->l = (int32)
150 		    ((p->hl[0]<<24)|(p->hl[1]<<16)|(p->hl[2]<<8)|(p->hl[3]));
151 		return 1;
152 	case LESHORT:
153 		p->h = (short)((p->hs[1]<<8)|(p->hs[0]));
154 		return 1;
155 	case LELONG:
156 	case LEDATE:
157 		p->l = (int32)
158 		    ((p->hl[3]<<24)|(p->hl[2]<<16)|(p->hl[1]<<8)|(p->hl[0]));
159 		return 1;
160 	default:
161 		return 0;
162 	}
163 }
164 
165 
166 static int
167 mget(p, s, m, nbytes)
168 union VALUETYPE* p;
169 unsigned char	*s;
170 struct magic *m;
171 int nbytes;
172 {
173 	int32 offset = m->offset;
174 
175 	if (offset + sizeof(union VALUETYPE) <= nbytes)
176 		memcpy(p, s + offset, sizeof(union VALUETYPE));
177 	else {
178 		/*
179 		 * the usefulness of padding with zeroes eludes me, it
180 		 * might even cause problems
181 		 */
182 		int32 have = nbytes - offset;
183 		memset(p, 0, sizeof(union VALUETYPE));
184 		if (have > 0)
185 			memcpy(p, s + offset, have);
186 	}
187 
188 	if (!mconvert(p, m))
189 		return 0;
190 
191 	if (m->flag & INDIR) {
192 
193 		switch (m->in.type) {
194 		case BYTE:
195 			offset = p->b + m->in.offset;
196 			break;
197 		case SHORT:
198 			offset = p->h + m->in.offset;
199 			break;
200 		case LONG:
201 			offset = p->l + m->in.offset;
202 			break;
203 		}
204 
205 		if (offset + sizeof(union VALUETYPE) > nbytes)
206 			return 0;
207 
208 		memcpy(p, s + offset, sizeof(union VALUETYPE));
209 
210 		if (!mconvert(p, m))
211 			return 0;
212 	}
213 	return 1;
214 }
215 
216 static int
217 mcheck(p, m)
218 union VALUETYPE* p;
219 struct magic *m;
220 {
221 	register uint32 l = m->value.l;
222 	register uint32 v;
223 	int matched;
224 
225 	if ( (m->value.s[0] == 'x') && (m->value.s[1] == '\0') ) {
226 		fprintf(stderr, "BOINK");
227 		return 1;
228 	}
229 
230 
231 	switch (m->type) {
232 	case BYTE:
233 		v = p->b;
234 		break;
235 
236 	case SHORT:
237 	case BESHORT:
238 	case LESHORT:
239 		v = p->h;
240 		break;
241 
242 	case LONG:
243 	case BELONG:
244 	case LELONG:
245 	case DATE:
246 	case BEDATE:
247 	case LEDATE:
248 		v = p->l;
249 		break;
250 
251 	case STRING:
252 		l = 0;
253 		/* What we want here is:
254 		 * v = strncmp(m->value.s, p->s, m->vallen);
255 		 * but ignoring any nulls.  bcmp doesn't give -/+/0
256 		 * and isn't universally available anyway.
257 		 */
258 		v = 0;
259 		{
260 			register unsigned char *a = (unsigned char*)m->value.s;
261 			register unsigned char *b = (unsigned char*)p->s;
262 			register int len = m->vallen;
263 
264 			while (--len >= 0)
265 				if ((v = *b++ - *a++) != '\0')
266 					break;
267 		}
268 		break;
269 	default:
270 		return 0;/*NOTREACHED*/
271 	}
272 
273 	v = signextend(m, v) & m->mask;
274 
275 	switch (m->reln) {
276 	case 'x':
277 		if (debug)
278 			(void) fprintf(stderr, "%u == *any* = 1\n", v);
279 		matched = 1;
280 		break;
281 
282 	case '!':
283 		matched = v != l;
284 		if (debug)
285 			(void) fprintf(stderr, "%u != %u = %d\n",
286 				       v, l, matched);
287 		break;
288 
289 	case '=':
290 		matched = v == l;
291 		if (debug)
292 			(void) fprintf(stderr, "%u == %u = %d\n",
293 				       v, l, matched);
294 		break;
295 
296 	case '>':
297 		if (m->flag & UNSIGNED) {
298 			matched = v > l;
299 			if (debug)
300 				(void) fprintf(stderr, "%u > %u = %d\n",
301 					       v, l, matched);
302 		}
303 		else {
304 			matched = (int32) v > (int32) l;
305 			if (debug)
306 				(void) fprintf(stderr, "%d > %d = %d\n",
307 					       v, l, matched);
308 		}
309 		break;
310 
311 	case '<':
312 		if (m->flag & UNSIGNED) {
313 			matched = v < l;
314 			if (debug)
315 				(void) fprintf(stderr, "%u < %u = %d\n",
316 					       v, l, matched);
317 		}
318 		else {
319 			matched = (int32) v < (int32) l;
320 			if (debug)
321 				(void) fprintf(stderr, "%d < %d = %d\n",
322 					       v, l, matched);
323 		}
324 		break;
325 
326 	case '&':
327 		matched = (v & l) == l;
328 		if (debug)
329 			(void) fprintf(stderr, "((%x & %x) == %x) = %d\n",
330 				       v, l, l, matched);
331 		break;
332 
333 	case '^':
334 		matched = (v & l) != l;
335 		if (debug)
336 			(void) fprintf(stderr, "((%x & %x) != %x) = %d\n",
337 				       v, l, l, matched);
338 		break;
339 
340 	default:
341 		matched = 0;
342 		break;/*NOTREACHED*/
343 	}
344 
345 	return matched;
346 }
347