Annotation of src/usr.bin/file/softmagic.c, Revision 1.10
1.10 ! deraadt 1: /* $OpenBSD: softmagic.c,v 1.9 2003/03/11 21:26:26 ian Exp $ */
1.3 millert 2:
1.1 deraadt 3: /*
4: * softmagic - interpret variable magic from /etc/magic
5: *
1.9 ian 6: * Copyright (c) Ian F. Darwin 1986-1995.
7: * Software written by Ian F. Darwin and others;
8: * maintained 1995-present by Christos Zoulas and others.
9: *
10: * Redistribution and use in source and binary forms, with or without
11: * modification, are permitted provided that the following conditions
12: * are met:
13: * 1. Redistributions of source code must retain the above copyright
14: * notice immediately at the beginning of the file, without modification,
15: * this list of conditions, and the following disclaimer.
16: * 2. Redistributions in binary form must reproduce the above copyright
17: * notice, this list of conditions and the following disclaimer in the
18: * documentation and/or other materials provided with the distribution.
19: *
20: * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
21: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23: * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
24: * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30: * SUCH DAMAGE.
1.1 deraadt 31: */
32:
1.4 mickey 33: #include <sys/types.h>
1.1 deraadt 34: #include <stdio.h>
35: #include <string.h>
1.3 millert 36: #include <stdlib.h>
1.1 deraadt 37: #include <time.h>
1.4 mickey 38: #include <err.h>
1.1 deraadt 39:
40: #include "file.h"
41:
42: #ifndef lint
1.10 ! deraadt 43: static char *moduleid = "$OpenBSD: softmagic.c,v 1.9 2003/03/11 21:26:26 ian Exp $";
1.1 deraadt 44: #endif /* lint */
45:
1.6 millert 46: static int match(unsigned char *, int);
1.7 millert 47: static int mget(union VALUETYPE *, unsigned char *, struct magic *, int);
1.6 millert 48: static int mcheck(union VALUETYPE *, struct magic *);
1.8 itojun 49: static int32_t mprint(union VALUETYPE *, struct magic *);
50: static void mdebug(int32_t, char *, int);
1.6 millert 51: static int mconvert(union VALUETYPE *, struct magic *);
1.1 deraadt 52:
53: /*
54: * softmagic - lookup one file in database
55: * (already read from /etc/magic by apprentice.c).
56: * Passed the name and FILE * of one file to be typed.
57: */
58: /*ARGSUSED1*/ /* nbytes passed for regularity, maybe need later */
59: int
60: softmagic(buf, nbytes)
61: unsigned char *buf;
62: int nbytes;
63: {
64: if (match(buf, nbytes))
65: return 1;
66:
67: return 0;
68: }
69:
70: /*
71: * Go through the whole list, stopping if you find a match. Process all
72: * the continuations of that match before returning.
73: *
74: * We support multi-level continuations:
75: *
76: * At any time when processing a successful top-level match, there is a
77: * current continuation level; it represents the level of the last
78: * successfully matched continuation.
79: *
80: * Continuations above that level are skipped as, if we see one, it
81: * means that the continuation that controls them - i.e, the
82: * lower-level continuation preceding them - failed to match.
83: *
84: * Continuations below that level are processed as, if we see one,
85: * it means we've finished processing or skipping higher-level
86: * continuations under the control of a successful or unsuccessful
87: * lower-level continuation, and are now seeing the next lower-level
88: * continuation and should process it. The current continuation
89: * level reverts to the level of the one we're seeing.
90: *
91: * Continuations at the current level are processed as, if we see
92: * one, there's no lower-level continuation that may have failed.
93: *
94: * If a continuation matches, we bump the current continuation level
95: * so that higher-level continuations are processed.
96: */
97: static int
98: match(s, nbytes)
99: unsigned char *s;
100: int nbytes;
101: {
102: int magindex = 0;
103: int cont_level = 0;
104: int need_separator = 0;
105: union VALUETYPE p;
1.8 itojun 106: static int32_t *tmpoff = NULL;
1.3 millert 107: static size_t tmplen = 0;
1.8 itojun 108: int32_t oldoff = 0;
1.3 millert 109:
110: if (tmpoff == NULL)
1.8 itojun 111: if ((tmpoff = (int32_t *) malloc(tmplen = 20)) == NULL)
1.4 mickey 112: err(1, "malloc");
1.1 deraadt 113:
114: for (magindex = 0; magindex < nmagic; magindex++) {
115: /* if main entry matches, print it... */
116: if (!mget(&p, s, &magic[magindex], nbytes) ||
117: !mcheck(&p, &magic[magindex])) {
118: /*
119: * main entry didn't match,
120: * flush its continuations
121: */
122: while (magindex < nmagic &&
123: magic[magindex + 1].cont_level != 0)
124: magindex++;
125: continue;
126: }
127:
1.3 millert 128: tmpoff[cont_level] = mprint(&p, &magic[magindex]);
1.1 deraadt 129: /*
130: * If we printed something, we'll need to print
131: * a blank before we print something else.
132: */
133: if (magic[magindex].desc[0])
134: need_separator = 1;
135: /* and any continuations that match */
1.3 millert 136: if (++cont_level >= tmplen)
1.8 itojun 137: if ((tmpoff = (int32_t *) realloc(tmpoff,
1.3 millert 138: tmplen += 20)) == NULL)
1.4 mickey 139: err(1, "malloc");
1.1 deraadt 140: while (magic[magindex+1].cont_level != 0 &&
141: ++magindex < nmagic) {
142: if (cont_level >= magic[magindex].cont_level) {
143: if (cont_level > magic[magindex].cont_level) {
144: /*
145: * We're at the end of the level
146: * "cont_level" continuations.
147: */
148: cont_level = magic[magindex].cont_level;
149: }
1.3 millert 150: if (magic[magindex].flag & ADD) {
151: oldoff=magic[magindex].offset;
152: magic[magindex].offset += tmpoff[cont_level-1];
153: }
1.1 deraadt 154: if (mget(&p, s, &magic[magindex], nbytes) &&
155: mcheck(&p, &magic[magindex])) {
156: /*
157: * This continuation matched.
158: * Print its message, with
159: * a blank before it if
160: * the previous item printed
161: * and this item isn't empty.
162: */
163: /* space if previous printed */
164: if (need_separator
165: && (magic[magindex].nospflag == 0)
166: && (magic[magindex].desc[0] != '\0')
167: ) {
168: (void) putchar(' ');
169: need_separator = 0;
170: }
1.3 millert 171: tmpoff[cont_level] = mprint(&p, &magic[magindex]);
1.1 deraadt 172: if (magic[magindex].desc[0])
173: need_separator = 1;
174:
175: /*
176: * If we see any continuations
177: * at a higher level,
178: * process them.
179: */
1.3 millert 180: if (++cont_level >= tmplen)
181: if ((tmpoff =
1.8 itojun 182: (int32_t *) realloc(tmpoff,
1.3 millert 183: tmplen += 20)) == NULL)
1.4 mickey 184: err(1, "malloc");
1.3 millert 185: }
186: if (magic[magindex].flag & ADD) {
187: magic[magindex].offset = oldoff;
1.1 deraadt 188: }
189: }
190: }
191: return 1; /* all through */
192: }
193: return 0; /* no match at all */
194: }
195:
1.8 itojun 196: static int32_t
1.1 deraadt 197: mprint(p, m)
198: union VALUETYPE *p;
199: struct magic *m;
200: {
201: char *pp, *rt;
1.8 itojun 202: uint32_t v;
203: int32_t t=0 ;
1.1 deraadt 204:
205:
206: switch (m->type) {
207: case BYTE:
208: v = p->b;
209: v = signextend(m, v) & m->mask;
210: (void) printf(m->desc, (unsigned char) v);
1.3 millert 211: t = m->offset + sizeof(char);
1.1 deraadt 212: break;
213:
214: case SHORT:
215: case BESHORT:
216: case LESHORT:
217: v = p->h;
218: v = signextend(m, v) & m->mask;
219: (void) printf(m->desc, (unsigned short) v);
1.3 millert 220: t = m->offset + sizeof(short);
1.1 deraadt 221: break;
222:
223: case LONG:
224: case BELONG:
225: case LELONG:
226: v = p->l;
227: v = signextend(m, v) & m->mask;
1.8 itojun 228: (void) printf(m->desc, (uint32_t) v);
229: t = m->offset + sizeof(int32_t);
1.1 deraadt 230: break;
231:
232: case STRING:
233: if (m->reln == '=') {
234: (void) printf(m->desc, m->value.s);
1.3 millert 235: t = m->offset + strlen(m->value.s);
1.1 deraadt 236: }
237: else {
1.3 millert 238: if (*m->value.s == '\0') {
239: char *cp = strchr(p->s,'\n');
240: if (cp)
241: *cp = '\0';
242: }
1.1 deraadt 243: (void) printf(m->desc, p->s);
1.3 millert 244: t = m->offset + strlen(p->s);
1.1 deraadt 245: }
1.3 millert 246: break;
1.1 deraadt 247:
248: case DATE:
249: case BEDATE:
250: case LEDATE:
251: pp = ctime((time_t*) &p->l);
252: if ((rt = strchr(pp, '\n')) != NULL)
253: *rt = '\0';
254: (void) printf(m->desc, pp);
1.3 millert 255: t = m->offset + sizeof(time_t);
256: break;
257:
1.1 deraadt 258: default:
1.4 mickey 259: errx(1, "invalid m->type (%d) in mprint().", m->type);
1.1 deraadt 260: /*NOTREACHED*/
261: }
1.3 millert 262: return(t);
1.1 deraadt 263: }
264:
265: /*
266: * Convert the byte order of the data we are looking at
267: */
268: static int
269: mconvert(p, m)
270: union VALUETYPE *p;
271: struct magic *m;
272: {
273: switch (m->type) {
274: case BYTE:
275: case SHORT:
276: case LONG:
277: case DATE:
278: return 1;
279: case STRING:
1.3 millert 280: {
281: char *ptr;
282:
283: /* Null terminate and eat the return */
284: p->s[sizeof(p->s) - 1] = '\0';
285: if ((ptr = strchr(p->s, '\n')) != NULL)
286: *ptr = '\0';
287: return 1;
288: }
1.1 deraadt 289: case BESHORT:
290: p->h = (short)((p->hs[0]<<8)|(p->hs[1]));
291: return 1;
292: case BELONG:
293: case BEDATE:
1.8 itojun 294: p->l = (int32_t)
1.1 deraadt 295: ((p->hl[0]<<24)|(p->hl[1]<<16)|(p->hl[2]<<8)|(p->hl[3]));
296: return 1;
297: case LESHORT:
298: p->h = (short)((p->hs[1]<<8)|(p->hs[0]));
299: return 1;
300: case LELONG:
301: case LEDATE:
1.8 itojun 302: p->l = (int32_t)
1.1 deraadt 303: ((p->hl[3]<<24)|(p->hl[2]<<16)|(p->hl[1]<<8)|(p->hl[0]));
304: return 1;
305: default:
1.4 mickey 306: errx(1, "invalid type %d in mconvert().", m->type);
1.1 deraadt 307: return 0;
308: }
309: }
310:
311:
312: static void
313: mdebug(offset, str, len)
1.8 itojun 314: int32_t offset;
1.1 deraadt 315: char *str;
316: int len;
317: {
1.3 millert 318: (void) fprintf(stderr, "mget @%d: ", offset);
1.1 deraadt 319: showstr(stderr, (char *) str, len);
320: (void) fputc('\n', stderr);
321: (void) fputc('\n', stderr);
322: }
323:
324: static int
325: mget(p, s, m, nbytes)
326: union VALUETYPE* p;
327: unsigned char *s;
328: struct magic *m;
329: int nbytes;
330: {
1.8 itojun 331: int32_t offset = m->offset;
1.1 deraadt 332:
333: if (offset + sizeof(union VALUETYPE) <= nbytes)
334: memcpy(p, s + offset, sizeof(union VALUETYPE));
335: else {
336: /*
337: * the usefulness of padding with zeroes eludes me, it
338: * might even cause problems
339: */
1.8 itojun 340: int32_t have = nbytes - offset;
1.1 deraadt 341: memset(p, 0, sizeof(union VALUETYPE));
342: if (have > 0)
343: memcpy(p, s + offset, have);
344: }
345:
346:
347: if (debug) {
348: mdebug(offset, (char *) p, sizeof(union VALUETYPE));
349: mdump(m);
350: }
351:
352: if (!mconvert(p, m))
353: return 0;
354:
355: if (m->flag & INDIR) {
356:
357: switch (m->in.type) {
358: case BYTE:
359: offset = p->b + m->in.offset;
360: break;
361: case SHORT:
362: offset = p->h + m->in.offset;
363: break;
364: case LONG:
365: offset = p->l + m->in.offset;
366: break;
367: }
368:
369: if (offset + sizeof(union VALUETYPE) > nbytes)
370: return 0;
371:
372: memcpy(p, s + offset, sizeof(union VALUETYPE));
373:
374: if (debug) {
375: mdebug(offset, (char *) p, sizeof(union VALUETYPE));
376: mdump(m);
377: }
378:
379: if (!mconvert(p, m))
380: return 0;
381: }
382: return 1;
383: }
384:
385: static int
386: mcheck(p, m)
387: union VALUETYPE* p;
388: struct magic *m;
389: {
1.8 itojun 390: uint32_t l = m->value.l;
391: uint32_t v;
1.1 deraadt 392: int matched;
393:
394: if ( (m->value.s[0] == 'x') && (m->value.s[1] == '\0') ) {
395: fprintf(stderr, "BOINK");
396: return 1;
397: }
398:
399:
400: switch (m->type) {
401: case BYTE:
402: v = p->b;
403: break;
404:
405: case SHORT:
406: case BESHORT:
407: case LESHORT:
408: v = p->h;
409: break;
410:
411: case LONG:
412: case BELONG:
413: case LELONG:
414: case DATE:
415: case BEDATE:
416: case LEDATE:
417: v = p->l;
418: break;
419:
420: case STRING:
421: l = 0;
422: /* What we want here is:
423: * v = strncmp(m->value.s, p->s, m->vallen);
424: * but ignoring any nulls. bcmp doesn't give -/+/0
425: * and isn't universally available anyway.
426: */
427: v = 0;
428: {
1.5 mpech 429: unsigned char *a = (unsigned char*)m->value.s;
430: unsigned char *b = (unsigned char*)p->s;
431: int len = m->vallen;
1.1 deraadt 432:
433: while (--len >= 0)
1.3 millert 434: if ((v = *b++ - *a++) != '\0')
1.1 deraadt 435: break;
436: }
437: break;
438: default:
1.4 mickey 439: errx(1, "invalid type %d in mcheck().", m->type);
1.1 deraadt 440: return 0;/*NOTREACHED*/
441: }
442:
443: v = signextend(m, v) & m->mask;
444:
445: switch (m->reln) {
446: case 'x':
447: if (debug)
1.3 millert 448: (void) fprintf(stderr, "%u == *any* = 1\n", v);
1.1 deraadt 449: matched = 1;
450: break;
451:
452: case '!':
453: matched = v != l;
454: if (debug)
1.3 millert 455: (void) fprintf(stderr, "%u != %u = %d\n",
1.1 deraadt 456: v, l, matched);
457: break;
458:
459: case '=':
460: matched = v == l;
461: if (debug)
1.3 millert 462: (void) fprintf(stderr, "%u == %u = %d\n",
1.1 deraadt 463: v, l, matched);
464: break;
465:
466: case '>':
467: if (m->flag & UNSIGNED) {
468: matched = v > l;
469: if (debug)
1.3 millert 470: (void) fprintf(stderr, "%u > %u = %d\n",
1.1 deraadt 471: v, l, matched);
472: }
473: else {
1.8 itojun 474: matched = (int32_t) v > (int32_t) l;
1.1 deraadt 475: if (debug)
1.3 millert 476: (void) fprintf(stderr, "%d > %d = %d\n",
1.1 deraadt 477: v, l, matched);
478: }
479: break;
480:
481: case '<':
482: if (m->flag & UNSIGNED) {
483: matched = v < l;
484: if (debug)
1.3 millert 485: (void) fprintf(stderr, "%u < %u = %d\n",
1.1 deraadt 486: v, l, matched);
487: }
488: else {
1.8 itojun 489: matched = (int32_t) v < (int32_t) l;
1.1 deraadt 490: if (debug)
1.3 millert 491: (void) fprintf(stderr, "%d < %d = %d\n",
1.1 deraadt 492: v, l, matched);
493: }
494: break;
495:
496: case '&':
497: matched = (v & l) == l;
498: if (debug)
1.3 millert 499: (void) fprintf(stderr, "((%x & %x) == %x) = %d\n",
1.1 deraadt 500: v, l, l, matched);
501: break;
502:
503: case '^':
504: matched = (v & l) != l;
505: if (debug)
1.3 millert 506: (void) fprintf(stderr, "((%x & %x) != %x) = %d\n",
1.1 deraadt 507: v, l, l, matched);
508: break;
509:
510: default:
511: matched = 0;
1.4 mickey 512: errx(1, "mcheck: can't happen: invalid relation %d.", m->reln);
1.1 deraadt 513: break;/*NOTREACHED*/
514: }
515:
516: return matched;
517: }