Annotation of src/usr.bin/file/softmagic.c, Revision 1.1.1.1
1.1 deraadt 1: /*
2: * softmagic - interpret variable magic from /etc/magic
3: *
4: * Copyright (c) Ian F. Darwin, 1987.
5: * Written by Ian F. Darwin.
6: *
7: * This software is not subject to any license of the American Telephone
8: * and Telegraph Company or of the Regents of the University of California.
9: *
10: * Permission is granted to anyone to use this software for any purpose on
11: * any computer system, and to alter it and redistribute it freely, subject
12: * to the following restrictions:
13: *
14: * 1. The author is not responsible for the consequences of use of this
15: * software, no matter how awful, even if they arise from flaws in it.
16: *
17: * 2. The origin of this software must not be misrepresented, either by
18: * explicit claim or by omission. Since few users ever read sources,
19: * credits must appear in the documentation.
20: *
21: * 3. Altered versions must be plainly marked as such, and must not be
22: * misrepresented as being the original software. Since few users
23: * ever read sources, credits must appear in the documentation.
24: *
25: * 4. This notice may not be removed or altered.
26: */
27:
28: #include <stdio.h>
29: #include <string.h>
30: #include <time.h>
31: #include <sys/types.h>
32:
33: #include "file.h"
34:
35: #ifndef lint
36: static char *moduleid =
37: "@(#)$Id: softmagic.c,v 1.9 1995/05/21 00:13:32 christos Exp $";
38: #endif /* lint */
39:
40: static int match __P((unsigned char *, int));
41: static int mget __P((union VALUETYPE *,
42: unsigned char *, struct magic *, int));
43: static int mcheck __P((union VALUETYPE *, struct magic *));
44: static void mprint __P((union VALUETYPE *, struct magic *));
45: static void mdebug __P((long, char *, int));
46: static int mconvert __P((union VALUETYPE *, struct magic *));
47:
48: /*
49: * softmagic - lookup one file in database
50: * (already read from /etc/magic by apprentice.c).
51: * Passed the name and FILE * of one file to be typed.
52: */
53: /*ARGSUSED1*/ /* nbytes passed for regularity, maybe need later */
54: int
55: softmagic(buf, nbytes)
56: unsigned char *buf;
57: int nbytes;
58: {
59: if (match(buf, nbytes))
60: return 1;
61:
62: return 0;
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 int
93: match(s, nbytes)
94: unsigned char *s;
95: int nbytes;
96: {
97: int magindex = 0;
98: int cont_level = 0;
99: int need_separator = 0;
100: union VALUETYPE p;
101:
102: for (magindex = 0; magindex < nmagic; magindex++) {
103: /* if main entry matches, print it... */
104: if (!mget(&p, s, &magic[magindex], nbytes) ||
105: !mcheck(&p, &magic[magindex])) {
106: /*
107: * main entry didn't match,
108: * flush its continuations
109: */
110: while (magindex < nmagic &&
111: magic[magindex + 1].cont_level != 0)
112: magindex++;
113: continue;
114: }
115:
116: mprint(&p, &magic[magindex]);
117: /*
118: * If we printed something, we'll need to print
119: * a blank before we print something else.
120: */
121: if (magic[magindex].desc[0])
122: need_separator = 1;
123: /* and any continuations that match */
124: cont_level++;
125: while (magic[magindex+1].cont_level != 0 &&
126: ++magindex < nmagic) {
127: if (cont_level >= magic[magindex].cont_level) {
128: if (cont_level > magic[magindex].cont_level) {
129: /*
130: * We're at the end of the level
131: * "cont_level" continuations.
132: */
133: cont_level = magic[magindex].cont_level;
134: }
135: if (mget(&p, s, &magic[magindex], nbytes) &&
136: mcheck(&p, &magic[magindex])) {
137: /*
138: * This continuation matched.
139: * Print its message, with
140: * a blank before it if
141: * the previous item printed
142: * and this item isn't empty.
143: */
144: /* space if previous printed */
145: if (need_separator
146: && (magic[magindex].nospflag == 0)
147: && (magic[magindex].desc[0] != '\0')
148: ) {
149: (void) putchar(' ');
150: need_separator = 0;
151: }
152: mprint(&p, &magic[magindex]);
153: if (magic[magindex].desc[0])
154: need_separator = 1;
155:
156: /*
157: * If we see any continuations
158: * at a higher level,
159: * process them.
160: */
161: cont_level++;
162: }
163: }
164: }
165: return 1; /* all through */
166: }
167: return 0; /* no match at all */
168: }
169:
170: static void
171: mprint(p, m)
172: union VALUETYPE *p;
173: struct magic *m;
174: {
175: char *pp, *rt;
176: unsigned long v;
177:
178:
179: switch (m->type) {
180: case BYTE:
181: v = p->b;
182: v = signextend(m, v) & m->mask;
183: (void) printf(m->desc, (unsigned char) v);
184: break;
185:
186: case SHORT:
187: case BESHORT:
188: case LESHORT:
189: v = p->h;
190: v = signextend(m, v) & m->mask;
191: (void) printf(m->desc, (unsigned short) v);
192: break;
193:
194: case LONG:
195: case BELONG:
196: case LELONG:
197: v = p->l;
198: v = signextend(m, v) & m->mask;
199: (void) printf(m->desc, (unsigned long) v);
200: break;
201:
202: case STRING:
203: if (m->reln == '=') {
204: (void) printf(m->desc, m->value.s);
205: }
206: else {
207: (void) printf(m->desc, p->s);
208: }
209: return;
210:
211: case DATE:
212: case BEDATE:
213: case LEDATE:
214: pp = ctime((time_t*) &p->l);
215: if ((rt = strchr(pp, '\n')) != NULL)
216: *rt = '\0';
217: (void) printf(m->desc, pp);
218: return;
219: default:
220: error("invalid m->type (%d) in mprint().\n", m->type);
221: /*NOTREACHED*/
222: }
223: }
224:
225: /*
226: * Convert the byte order of the data we are looking at
227: */
228: static int
229: mconvert(p, m)
230: union VALUETYPE *p;
231: struct magic *m;
232: {
233: char *rt;
234:
235: switch (m->type) {
236: case BYTE:
237: case SHORT:
238: case LONG:
239: case DATE:
240: return 1;
241: case STRING:
242: /* Null terminate and eat the return */
243: p->s[sizeof(p->s) - 1] = '\0';
244: if ((rt = strchr(p->s, '\n')) != NULL)
245: *rt = '\0';
246: return 1;
247: case BESHORT:
248: p->h = (short)((p->hs[0]<<8)|(p->hs[1]));
249: return 1;
250: case BELONG:
251: case BEDATE:
252: p->l = (long)
253: ((p->hl[0]<<24)|(p->hl[1]<<16)|(p->hl[2]<<8)|(p->hl[3]));
254: return 1;
255: case LESHORT:
256: p->h = (short)((p->hs[1]<<8)|(p->hs[0]));
257: return 1;
258: case LELONG:
259: case LEDATE:
260: p->l = (long)
261: ((p->hl[3]<<24)|(p->hl[2]<<16)|(p->hl[1]<<8)|(p->hl[0]));
262: return 1;
263: default:
264: error("invalid type %d in mconvert().\n", m->type);
265: return 0;
266: }
267: }
268:
269:
270: static void
271: mdebug(offset, str, len)
272: long offset;
273: char *str;
274: int len;
275: {
276: (void) fprintf(stderr, "mget @%ld: ", offset);
277: showstr(stderr, (char *) str, len);
278: (void) fputc('\n', stderr);
279: (void) fputc('\n', stderr);
280: }
281:
282: static int
283: mget(p, s, m, nbytes)
284: union VALUETYPE* p;
285: unsigned char *s;
286: struct magic *m;
287: int nbytes;
288: {
289: long offset = m->offset;
290:
291: if (offset + sizeof(union VALUETYPE) <= nbytes)
292: memcpy(p, s + offset, sizeof(union VALUETYPE));
293: else {
294: /*
295: * the usefulness of padding with zeroes eludes me, it
296: * might even cause problems
297: */
298: long have = nbytes - offset;
299: memset(p, 0, sizeof(union VALUETYPE));
300: if (have > 0)
301: memcpy(p, s + offset, have);
302: }
303:
304:
305: if (debug) {
306: mdebug(offset, (char *) p, sizeof(union VALUETYPE));
307: mdump(m);
308: }
309:
310: if (!mconvert(p, m))
311: return 0;
312:
313: if (m->flag & INDIR) {
314:
315: switch (m->in.type) {
316: case BYTE:
317: offset = p->b + m->in.offset;
318: break;
319: case SHORT:
320: offset = p->h + m->in.offset;
321: break;
322: case LONG:
323: offset = p->l + m->in.offset;
324: break;
325: }
326:
327: if (offset + sizeof(union VALUETYPE) > nbytes)
328: return 0;
329:
330: memcpy(p, s + offset, sizeof(union VALUETYPE));
331:
332: if (debug) {
333: mdebug(offset, (char *) p, sizeof(union VALUETYPE));
334: mdump(m);
335: }
336:
337: if (!mconvert(p, m))
338: return 0;
339: }
340: return 1;
341: }
342:
343: static int
344: mcheck(p, m)
345: union VALUETYPE* p;
346: struct magic *m;
347: {
348: register unsigned long l = m->value.l;
349: register unsigned long v;
350: int matched;
351:
352: if ( (m->value.s[0] == 'x') && (m->value.s[1] == '\0') ) {
353: fprintf(stderr, "BOINK");
354: return 1;
355: }
356:
357:
358: switch (m->type) {
359: case BYTE:
360: v = p->b;
361: break;
362:
363: case SHORT:
364: case BESHORT:
365: case LESHORT:
366: v = p->h;
367: break;
368:
369: case LONG:
370: case BELONG:
371: case LELONG:
372: case DATE:
373: case BEDATE:
374: case LEDATE:
375: v = p->l;
376: break;
377:
378: case STRING:
379: l = 0;
380: /* What we want here is:
381: * v = strncmp(m->value.s, p->s, m->vallen);
382: * but ignoring any nulls. bcmp doesn't give -/+/0
383: * and isn't universally available anyway.
384: */
385: v = 0;
386: {
387: register unsigned char *a = (unsigned char*)m->value.s;
388: register unsigned char *b = (unsigned char*)p->s;
389: register int len = m->vallen;
390:
391: while (--len >= 0)
392: if ((v = *b++ - *a++) != 0)
393: break;
394: }
395: break;
396: default:
397: error("invalid type %d in mcheck().\n", m->type);
398: return 0;/*NOTREACHED*/
399: }
400:
401: v = signextend(m, v) & m->mask;
402:
403: switch (m->reln) {
404: case 'x':
405: if (debug)
406: (void) fprintf(stderr, "%lu == *any* = 1\n", v);
407: matched = 1;
408: break;
409:
410: case '!':
411: matched = v != l;
412: if (debug)
413: (void) fprintf(stderr, "%lu != %lu = %d\n",
414: v, l, matched);
415: break;
416:
417: case '=':
418: matched = v == l;
419: if (debug)
420: (void) fprintf(stderr, "%lu == %lu = %d\n",
421: v, l, matched);
422: break;
423:
424: case '>':
425: if (m->flag & UNSIGNED) {
426: matched = v > l;
427: if (debug)
428: (void) fprintf(stderr, "%lu > %lu = %d\n",
429: v, l, matched);
430: }
431: else {
432: matched = (long) v > (long) l;
433: if (debug)
434: (void) fprintf(stderr, "%ld > %ld = %d\n",
435: v, l, matched);
436: }
437: break;
438:
439: case '<':
440: if (m->flag & UNSIGNED) {
441: matched = v < l;
442: if (debug)
443: (void) fprintf(stderr, "%lu < %lu = %d\n",
444: v, l, matched);
445: }
446: else {
447: matched = (long) v < (long) l;
448: if (debug)
449: (void) fprintf(stderr, "%ld < %ld = %d\n",
450: v, l, matched);
451: }
452: break;
453:
454: case '&':
455: matched = (v & l) == l;
456: if (debug)
457: (void) fprintf(stderr, "((%lx & %lx) == %lx) = %d\n",
458: v, l, l, matched);
459: break;
460:
461: case '^':
462: matched = (v & l) != l;
463: if (debug)
464: (void) fprintf(stderr, "((%lx & %lx) != %lx) = %d\n",
465: v, l, l, matched);
466: break;
467:
468: default:
469: matched = 0;
470: error("mcheck: can't happen: invalid relation %d.\n", m->reln);
471: break;/*NOTREACHED*/
472: }
473:
474: return matched;
475: }