Annotation of src/usr.bin/file/softmagic.c, Revision 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: }