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 *
softmagic(buf,nbytes)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 *
match(s,nbytes)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
mconvert(p,m)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
mget(p,s,m,nbytes)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
mcheck(p,m)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