xref: /openbsd-src/gnu/usr.sbin/mkhybrid/src/libfile/softmagic.c (revision b2ea75c1b17e1a9a339660e7ed45cd24946b230e)
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 #ifndef	lint
45 static char *moduleid =
46 	"@(#)$Id: softmagic.c,v 1.1 2000/10/10 20:40:37 beck Exp $";
47 #endif	/* lint */
48 
49 /* static int match	__P((unsigned char *, int)); */
50 static char *match	__P((unsigned char *, int));
51 static int mget		__P((union VALUETYPE *,
52 			     unsigned char *, struct magic *, int));
53 static int mcheck	__P((union VALUETYPE *, struct magic *));
54 static int32 mprint	__P((union VALUETYPE *, struct magic *));
55 static void mdebug	__P((int32, char *, int));
56 static int mconvert	__P((union VALUETYPE *, struct magic *));
57 
58 /*
59  * softmagic - lookup one file in database
60  * (already read from /etc/magic by apprentice.c).
61  * Passed the name and FILE * of one file to be typed.
62  */
63 /*ARGSUSED1*/		/* nbytes passed for regularity, maybe need later */
64 char *
65 softmagic(buf, nbytes)
66 unsigned char *buf;
67 int nbytes;
68 {
69 	return (match(buf, nbytes));
70 }
71 
72 /*
73  * Go through the whole list, stopping if you find a match.  Process all
74  * the continuations of that match before returning.
75  *
76  * We support multi-level continuations:
77  *
78  *	At any time when processing a successful top-level match, there is a
79  *	current continuation level; it represents the level of the last
80  *	successfully matched continuation.
81  *
82  *	Continuations above that level are skipped as, if we see one, it
83  *	means that the continuation that controls them - i.e, the
84  *	lower-level continuation preceding them - failed to match.
85  *
86  *	Continuations below that level are processed as, if we see one,
87  *	it means we've finished processing or skipping higher-level
88  *	continuations under the control of a successful or unsuccessful
89  *	lower-level continuation, and are now seeing the next lower-level
90  *	continuation and should process it.  The current continuation
91  *	level reverts to the level of the one we're seeing.
92  *
93  *	Continuations at the current level are processed as, if we see
94  *	one, there's no lower-level continuation that may have failed.
95  *
96  *	If a continuation matches, we bump the current continuation level
97  *	so that higher-level continuations are processed.
98  */
99 static char *
100 match(s, nbytes)
101 unsigned char	*s;
102 int nbytes;
103 {
104 	int magindex = 0;
105 	int cont_level = 0;
106 	union VALUETYPE p;
107 
108 	for (magindex = 0; magindex < nmagic; magindex++) {
109 		/* if main entry matches, print it... */
110 		if (!mget(&p, s, &magic[magindex], nbytes) ||
111 		    !mcheck(&p, &magic[magindex])) {
112 			    /*
113 			     * main entry didn't match,
114 			     * flush its continuations
115 			     */
116 			    while (magindex < nmagic &&
117 			    	   magic[magindex + 1].cont_level != 0)
118 			    	   magindex++;
119 			    continue;
120 		}
121 
122 		return (magic[magindex].desc);
123 	}
124 	return 0;			/* no match at all */
125 }
126 
127 
128 /*
129  * Convert the byte order of the data we are looking at
130  */
131 static int
132 mconvert(p, m)
133 union VALUETYPE *p;
134 struct magic *m;
135 {
136 	switch (m->type) {
137 	case BYTE:
138 	case SHORT:
139 	case LONG:
140 	case DATE:
141 		return 1;
142 	case STRING:
143 		{
144 			char *ptr;
145 
146 			/* Null terminate and eat the return */
147 			p->s[sizeof(p->s) - 1] = '\0';
148 			if ((ptr = strchr(p->s, '\n')) != NULL)
149 				*ptr = '\0';
150 			return 1;
151 		}
152 	case BESHORT:
153 		p->h = (short)((p->hs[0]<<8)|(p->hs[1]));
154 		return 1;
155 	case BELONG:
156 	case BEDATE:
157 		p->l = (int32)
158 		    ((p->hl[0]<<24)|(p->hl[1]<<16)|(p->hl[2]<<8)|(p->hl[3]));
159 		return 1;
160 	case LESHORT:
161 		p->h = (short)((p->hs[1]<<8)|(p->hs[0]));
162 		return 1;
163 	case LELONG:
164 	case LEDATE:
165 		p->l = (int32)
166 		    ((p->hl[3]<<24)|(p->hl[2]<<16)|(p->hl[1]<<8)|(p->hl[0]));
167 		return 1;
168 	default:
169 		return 0;
170 	}
171 }
172 
173 
174 static void
175 mdebug(offset, str, len)
176 int32 offset;
177 char *str;
178 int len;
179 {
180 	(void) fprintf(stderr, "mget @%d: ", offset);
181 	showstr(stderr, (char *) str, len);
182 	(void) fputc('\n', stderr);
183 	(void) fputc('\n', stderr);
184 }
185 
186 static int
187 mget(p, s, m, nbytes)
188 union VALUETYPE* p;
189 unsigned char	*s;
190 struct magic *m;
191 int nbytes;
192 {
193 	int32 offset = m->offset;
194 
195 	if (offset + sizeof(union VALUETYPE) <= nbytes)
196 		memcpy(p, s + offset, sizeof(union VALUETYPE));
197 	else {
198 		/*
199 		 * the usefulness of padding with zeroes eludes me, it
200 		 * might even cause problems
201 		 */
202 		int32 have = nbytes - offset;
203 		memset(p, 0, sizeof(union VALUETYPE));
204 		if (have > 0)
205 			memcpy(p, s + offset, have);
206 	}
207 
208 	if (!mconvert(p, m))
209 		return 0;
210 
211 	if (m->flag & INDIR) {
212 
213 		switch (m->in.type) {
214 		case BYTE:
215 			offset = p->b + m->in.offset;
216 			break;
217 		case SHORT:
218 			offset = p->h + m->in.offset;
219 			break;
220 		case LONG:
221 			offset = p->l + m->in.offset;
222 			break;
223 		}
224 
225 		if (offset + sizeof(union VALUETYPE) > nbytes)
226 			return 0;
227 
228 		memcpy(p, s + offset, sizeof(union VALUETYPE));
229 
230 		if (!mconvert(p, m))
231 			return 0;
232 	}
233 	return 1;
234 }
235 
236 static int
237 mcheck(p, m)
238 union VALUETYPE* p;
239 struct magic *m;
240 {
241 	register uint32 l = m->value.l;
242 	register uint32 v;
243 	int matched;
244 
245 	if ( (m->value.s[0] == 'x') && (m->value.s[1] == '\0') ) {
246 		fprintf(stderr, "BOINK");
247 		return 1;
248 	}
249 
250 
251 	switch (m->type) {
252 	case BYTE:
253 		v = p->b;
254 		break;
255 
256 	case SHORT:
257 	case BESHORT:
258 	case LESHORT:
259 		v = p->h;
260 		break;
261 
262 	case LONG:
263 	case BELONG:
264 	case LELONG:
265 	case DATE:
266 	case BEDATE:
267 	case LEDATE:
268 		v = p->l;
269 		break;
270 
271 	case STRING:
272 		l = 0;
273 		/* What we want here is:
274 		 * v = strncmp(m->value.s, p->s, m->vallen);
275 		 * but ignoring any nulls.  bcmp doesn't give -/+/0
276 		 * and isn't universally available anyway.
277 		 */
278 		v = 0;
279 		{
280 			register unsigned char *a = (unsigned char*)m->value.s;
281 			register unsigned char *b = (unsigned char*)p->s;
282 			register int len = m->vallen;
283 
284 			while (--len >= 0)
285 				if ((v = *b++ - *a++) != '\0')
286 					break;
287 		}
288 		break;
289 	default:
290 		return 0;/*NOTREACHED*/
291 	}
292 
293 	v = signextend(m, v) & m->mask;
294 
295 	switch (m->reln) {
296 	case 'x':
297 		if (debug)
298 			(void) fprintf(stderr, "%u == *any* = 1\n", v);
299 		matched = 1;
300 		break;
301 
302 	case '!':
303 		matched = v != l;
304 		if (debug)
305 			(void) fprintf(stderr, "%u != %u = %d\n",
306 				       v, l, matched);
307 		break;
308 
309 	case '=':
310 		matched = v == l;
311 		if (debug)
312 			(void) fprintf(stderr, "%u == %u = %d\n",
313 				       v, l, matched);
314 		break;
315 
316 	case '>':
317 		if (m->flag & UNSIGNED) {
318 			matched = v > l;
319 			if (debug)
320 				(void) fprintf(stderr, "%u > %u = %d\n",
321 					       v, l, matched);
322 		}
323 		else {
324 			matched = (int32) v > (int32) l;
325 			if (debug)
326 				(void) fprintf(stderr, "%d > %d = %d\n",
327 					       v, l, matched);
328 		}
329 		break;
330 
331 	case '<':
332 		if (m->flag & UNSIGNED) {
333 			matched = v < l;
334 			if (debug)
335 				(void) fprintf(stderr, "%u < %u = %d\n",
336 					       v, l, matched);
337 		}
338 		else {
339 			matched = (int32) v < (int32) l;
340 			if (debug)
341 				(void) fprintf(stderr, "%d < %d = %d\n",
342 					       v, l, matched);
343 		}
344 		break;
345 
346 	case '&':
347 		matched = (v & l) == l;
348 		if (debug)
349 			(void) fprintf(stderr, "((%x & %x) == %x) = %d\n",
350 				       v, l, l, matched);
351 		break;
352 
353 	case '^':
354 		matched = (v & l) != l;
355 		if (debug)
356 			(void) fprintf(stderr, "((%x & %x) != %x) = %d\n",
357 				       v, l, l, matched);
358 		break;
359 
360 	default:
361 		matched = 0;
362 		break;/*NOTREACHED*/
363 	}
364 
365 	return matched;
366 }
367