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