1 /* @(#)softmagic.c 1.12 09/07/11 joerg */
2 #ifndef lint
3 static const char sccsid[] =
4 "@(#)softmagic.c 1.12 09/07/11 joerg";
5 #endif
6 /*
7 ** find file types by using a modified "magic" file
8 **
9 ** based on file v3.22 by Ian F. Darwin (see below)
10 **
11 ** Modified for mkhybrid James Pearson 19/5/98
12 */
13
14 /*
15 * softmagic - interpret variable magic from /etc/magic
16 *
17 * Copyright (c) Ian F. Darwin, 1987.
18 * Written by Ian F. Darwin.
19 *
20 * This software is not subject to any export provision of the United States
21 * Department of Commerce, and may be exported to any country or planet.
22 *
23 * Redistribution and use in source and binary forms, with or without
24 * modification, are permitted provided that the following conditions
25 * are met:
26 * 1. Redistributions of source code must retain the above copyright
27 * notice immediately at the beginning of the file, without modification,
28 * this list of conditions, and the following disclaimer.
29 * 2. Redistributions in binary form must reproduce the above copyright
30 * notice, this list of conditions and the following disclaimer in the
31 * documentation and/or other materials provided with the distribution.
32 *
33 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
34 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
35 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
36 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
37 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
38 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
39 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
40 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
41 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
42 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
43 * SUCH DAMAGE.
44 */
45
46 #include <stdio.h>
47 #include <string.h>
48 #include <stdlib.h>
49
50 #include "file.h"
51
52 #ifndef lint
53 static const char moduleid[] =
54 "@(#)Id: softmagic.c,v 1.34 1997/01/15 19:28:35 christos Exp";
55 #endif /* lint */
56
57 #ifdef DEBUG
58 int debug = 1; /* debugging */
59 #else
60 #define debug 0 /* debugging */
61 #endif /* DEBUG */
62
63 static char *match (unsigned char *, int);
64 static int mget (union VALUETYPE *,
65 unsigned char *, struct magic *, int);
66 /* QNX has a mcheck() prototyp in a public include file */
67 static int magcheck (union VALUETYPE *, struct magic *);
68 #ifdef __used__
69 static void mdebug (Int32_t, char *, int);
70 #endif
71 static int mconvert (union VALUETYPE *, struct magic *);
72
73 /*
74 * softmagic - lookup one file in database
75 * (already read from /etc/magic by apprentice.c).
76 * Passed the name and FILE * of one file to be typed.
77 */
78 /*ARGSUSED1*/ /* nbytes passed for regularity, maybe need later */
79 char *
softmagic(unsigned char * buf,int nbytes)80 softmagic(unsigned char *buf, int nbytes)
81 {
82 return (match(buf, nbytes));
83 }
84
85 /*
86 * Go through the whole list, stopping if you find a match. Process all
87 * the continuations of that match before returning.
88 *
89 * We support multi-level continuations:
90 *
91 * At any time when processing a successful top-level match, there is a
92 * current continuation level; it represents the level of the last
93 * successfully matched continuation.
94 *
95 * Continuations above that level are skipped as, if we see one, it
96 * means that the continuation that controls them - i.e, the
97 * lower-level continuation preceding them - failed to match.
98 *
99 * Continuations below that level are processed as, if we see one,
100 * it means we've finished processing or skipping higher-level
101 * continuations under the control of a successful or unsuccessful
102 * lower-level continuation, and are now seeing the next lower-level
103 * continuation and should process it. The current continuation
104 * level reverts to the level of the one we're seeing.
105 *
106 * Continuations at the current level are processed as, if we see
107 * one, there's no lower-level continuation that may have failed.
108 *
109 * If a continuation matches, we bump the current continuation level
110 * so that higher-level continuations are processed.
111 */
112 static char *
match(unsigned char * s,int nbytes)113 match(unsigned char *s, int nbytes)
114 {
115 int magindex = 0;
116 union VALUETYPE p;
117
118 for (magindex = 0; magindex < __f_nmagic; magindex++) {
119 /* if main entry matches, print it... */
120 if (!mget(&p, s, &__f_magic[magindex], nbytes) ||
121 !magcheck(&p, &__f_magic[magindex])) {
122 /*
123 * main entry didn't match,
124 * flush its continuations
125 */
126 while (magindex < __f_nmagic &&
127 __f_magic[magindex + 1].cont_level != 0)
128 magindex++;
129 continue;
130 }
131
132 return (__f_magic[magindex].desc);
133 }
134 return 0; /* no match at all */
135 }
136
137
138 /*
139 * Convert the byte order of the data we are looking at
140 */
141 static int
mconvert(union VALUETYPE * p,struct magic * m)142 mconvert(union VALUETYPE *p, struct magic *m)
143 {
144 switch (m->type) {
145 case BYTE:
146 case SHORT:
147 case LONG:
148 case DATE:
149 return 1;
150 case STRING:
151 {
152 char *ptr;
153
154 /* Null terminate and eat the return */
155 p->s[sizeof(p->s) - 1] = '\0';
156 if ((ptr = strchr(p->s, '\n')) != NULL)
157 *ptr = '\0';
158 return 1;
159 }
160 case BESHORT:
161 p->h = (short)((p->hs[0]<<8)|(p->hs[1]));
162 return 1;
163 case BELONG:
164 case BEDATE:
165 p->l = (Int32_t)
166 ((p->hl[0]<<24)|(p->hl[1]<<16)|(p->hl[2]<<8)|(p->hl[3]));
167 return 1;
168 case LESHORT:
169 p->h = (short)((p->hs[1]<<8)|(p->hs[0]));
170 return 1;
171 case LELONG:
172 case LEDATE:
173 p->l = (Int32_t)
174 ((p->hl[3]<<24)|(p->hl[2]<<16)|(p->hl[1]<<8)|(p->hl[0]));
175 return 1;
176 default:
177 return 0;
178 }
179 }
180
181 #ifdef __used__
182 static void
mdebug(Int32_t offset,char * str,int len)183 mdebug(Int32_t offset, char *str, int len)
184 {
185 (void) fprintf(stderr, "mget @%d: ", offset);
186 showstr(stderr, (char *) str, len);
187 (void) fputc('\n', stderr);
188 (void) fputc('\n', stderr);
189 }
190 #endif
191
192 static int
mget(union VALUETYPE * p,unsigned char * s,struct magic * m,int nbytes)193 mget(union VALUETYPE* p, unsigned char *s, struct magic *m, int nbytes)
194 {
195 Int32_t offset = m->offset;
196
197 if (offset + sizeof(union VALUETYPE) <= nbytes)
198 memcpy(p, s + offset, sizeof(union VALUETYPE));
199 else {
200 /*
201 * the usefulness of padding with zeroes eludes me, it
202 * might even cause problems
203 */
204 Int32_t have = nbytes - offset;
205 memset(p, 0, sizeof(union VALUETYPE));
206 if (have > 0)
207 memcpy(p, s + offset, have);
208 }
209
210 if (!mconvert(p, m))
211 return 0;
212
213 if (m->flag & INDIR) {
214
215 switch (m->in.type) {
216 case BYTE:
217 offset = p->b + m->in.offset;
218 break;
219 case SHORT:
220 offset = p->h + m->in.offset;
221 break;
222 case LONG:
223 offset = p->l + m->in.offset;
224 break;
225 }
226
227 if (offset + sizeof(union VALUETYPE) > nbytes)
228 return 0;
229
230 memcpy(p, s + offset, sizeof(union VALUETYPE));
231
232 if (!mconvert(p, m))
233 return 0;
234 }
235 return 1;
236 }
237
238 static int
magcheck(union VALUETYPE * p,struct magic * m)239 magcheck(union VALUETYPE* p, struct magic *m)
240 {
241 register UInt32_t l = m->value.l;
242 register UInt32_t 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_t) v > (Int32_t) l;
325 if (debug)
326 (void) fprintf(stderr, "%d > %d = %d\n",
327 (Int32_t)v, (Int32_t)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_t) v < (Int32_t) l;
340 if (debug)
341 (void) fprintf(stderr, "%d < %d = %d\n",
342 (Int32_t)v, (Int32_t)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