Annotation of src/usr.bin/file/softmagic.c, Revision 1.11
1.11 ! tedu 1: /* $OpenBSD$ */
1.1 deraadt 2: /*
1.9 ian 3: * Copyright (c) Ian F. Darwin 1986-1995.
4: * Software written by Ian F. Darwin and others;
5: * maintained 1995-present by Christos Zoulas and others.
6: *
7: * Redistribution and use in source and binary forms, with or without
8: * modification, are permitted provided that the following conditions
9: * are met:
10: * 1. Redistributions of source code must retain the above copyright
11: * notice immediately at the beginning of the file, without modification,
12: * this list of conditions, and the following disclaimer.
13: * 2. Redistributions in binary form must reproduce the above copyright
14: * notice, this list of conditions and the following disclaimer in the
15: * documentation and/or other materials provided with the distribution.
16: *
17: * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20: * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
21: * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27: * SUCH DAMAGE.
1.1 deraadt 28: */
1.11 ! tedu 29: /*
! 30: * softmagic - interpret variable magic from MAGIC
! 31: */
1.1 deraadt 32:
1.11 ! tedu 33: #include "file.h"
! 34: #include "magic.h"
1.1 deraadt 35: #include <string.h>
1.11 ! tedu 36: #include <ctype.h>
1.3 millert 37: #include <stdlib.h>
1.1 deraadt 38: #include <time.h>
1.11 ! tedu 39: #include <regex.h>
1.1 deraadt 40:
41:
42: #ifndef lint
1.11 ! tedu 43: FILE_RCSID("@(#)$Id: softmagic.c,v 1.65 2004/03/09 18:49:58 christos Exp $")
1.1 deraadt 44: #endif /* lint */
45:
1.11 ! tedu 46: private int match(struct magic_set *, struct magic *, uint32_t,
! 47: const unsigned char *, size_t);
! 48: private int mget(struct magic_set *, union VALUETYPE *, const unsigned char *,
! 49: struct magic *, size_t);
! 50: private int mcheck(struct magic_set *, union VALUETYPE *, struct magic *);
! 51: private int32_t mprint(struct magic_set *, union VALUETYPE *, struct magic *);
! 52: private void mdebug(uint32_t, const char *, size_t);
! 53: private int mconvert(struct magic_set *, union VALUETYPE *, struct magic *);
! 54: private int check_mem(struct magic_set *, unsigned int);
1.1 deraadt 55:
56: /*
57: * softmagic - lookup one file in database
1.11 ! tedu 58: * (already read from MAGIC by apprentice.c).
1.1 deraadt 59: * Passed the name and FILE * of one file to be typed.
60: */
61: /*ARGSUSED1*/ /* nbytes passed for regularity, maybe need later */
1.11 ! tedu 62: protected int
! 63: file_softmagic(struct magic_set *ms, const unsigned char *buf, size_t nbytes)
1.1 deraadt 64: {
1.11 ! tedu 65: struct mlist *ml;
! 66: for (ml = ms->mlist->next; ml != ms->mlist; ml = ml->next)
! 67: if (match(ms, ml->magic, ml->nmagic, buf, nbytes))
! 68: return 1;
1.1 deraadt 69:
70: return 0;
71: }
72:
73: /*
74: * Go through the whole list, stopping if you find a match. Process all
75: * the continuations of that match before returning.
76: *
77: * We support multi-level continuations:
78: *
79: * At any time when processing a successful top-level match, there is a
80: * current continuation level; it represents the level of the last
81: * successfully matched continuation.
82: *
83: * Continuations above that level are skipped as, if we see one, it
84: * means that the continuation that controls them - i.e, the
85: * lower-level continuation preceding them - failed to match.
86: *
87: * Continuations below that level are processed as, if we see one,
88: * it means we've finished processing or skipping higher-level
89: * continuations under the control of a successful or unsuccessful
90: * lower-level continuation, and are now seeing the next lower-level
91: * continuation and should process it. The current continuation
92: * level reverts to the level of the one we're seeing.
93: *
94: * Continuations at the current level are processed as, if we see
95: * one, there's no lower-level continuation that may have failed.
96: *
97: * If a continuation matches, we bump the current continuation level
98: * so that higher-level continuations are processed.
99: */
1.11 ! tedu 100: private int
! 101: match(struct magic_set *ms, struct magic *magic, uint32_t nmagic,
! 102: const unsigned char *s, size_t nbytes)
1.1 deraadt 103: {
1.11 ! tedu 104: uint32_t magindex = 0;
! 105: unsigned int cont_level = 0;
1.1 deraadt 106: int need_separator = 0;
107: union VALUETYPE p;
1.8 itojun 108: int32_t oldoff = 0;
1.11 ! tedu 109: int returnval = 0; /* if a match is found it is set to 1*/
! 110: int firstline = 1; /* a flag to print X\n X\n- X */
1.3 millert 111:
1.11 ! tedu 112: if (check_mem(ms, cont_level) == -1)
! 113: return -1;
1.1 deraadt 114:
115: for (magindex = 0; magindex < nmagic; magindex++) {
116: /* if main entry matches, print it... */
1.11 ! tedu 117: int flush = !mget(ms, &p, s, &magic[magindex], nbytes);
! 118: switch (mcheck(ms, &p, &magic[magindex])) {
! 119: case -1:
! 120: return -1;
! 121: case 0:
! 122: flush++;
! 123: break;
! 124: default:
! 125: break;
! 126: }
! 127: if (flush) {
! 128: /*
! 129: * main entry didn't match,
! 130: * flush its continuations
! 131: */
! 132: while (magindex < nmagic - 1 &&
! 133: magic[magindex + 1].cont_level != 0)
! 134: magindex++;
! 135: continue;
1.1 deraadt 136: }
137:
1.11 ! tedu 138: if (!firstline) { /* we found another match */
! 139: /* put a newline and '-' to do some simple formatting*/
! 140: if (file_printf(ms, "\n- ") == -1)
! 141: return -1;
! 142: }
! 143:
! 144: if ((ms->c.off[cont_level] = mprint(ms, &p, &magic[magindex]))
! 145: == -1)
! 146: return -1;
1.1 deraadt 147: /*
148: * If we printed something, we'll need to print
149: * a blank before we print something else.
150: */
151: if (magic[magindex].desc[0])
152: need_separator = 1;
153: /* and any continuations that match */
1.11 ! tedu 154: if (check_mem(ms, ++cont_level) == -1)
! 155: return -1;
! 156:
1.1 deraadt 157: while (magic[magindex+1].cont_level != 0 &&
158: ++magindex < nmagic) {
1.11 ! tedu 159: if (cont_level < magic[magindex].cont_level)
! 160: continue;
! 161: if (cont_level > magic[magindex].cont_level) {
! 162: /*
! 163: * We're at the end of the level
! 164: * "cont_level" continuations.
! 165: */
! 166: cont_level = magic[magindex].cont_level;
! 167: }
! 168: if (magic[magindex].flag & OFFADD) {
! 169: oldoff=magic[magindex].offset;
! 170: magic[magindex].offset += ms->c.off[cont_level-1];
! 171: }
! 172: if (!mget(ms, &p, s, &magic[magindex], nbytes))
! 173: goto done;
! 174:
! 175: switch (mcheck(ms, &p, &magic[magindex])) {
! 176: case -1:
! 177: return -1;
! 178: case 0:
! 179: break;
! 180: default:
! 181: /*
! 182: * This continuation matched.
! 183: * Print its message, with
! 184: * a blank before it if
! 185: * the previous item printed
! 186: * and this item isn't empty.
! 187: */
! 188: /* space if previous printed */
! 189: if (need_separator
! 190: && (magic[magindex].nospflag == 0)
! 191: && (magic[magindex].desc[0] != '\0')) {
! 192: if (file_printf(ms, " ") == -1)
! 193: return -1;
! 194: need_separator = 0;
1.1 deraadt 195: }
1.11 ! tedu 196: if ((ms->c.off[cont_level] = mprint(ms, &p,
! 197: &magic[magindex])) == -1)
! 198: return -1;
! 199: if (magic[magindex].desc[0])
! 200: need_separator = 1;
! 201:
! 202: /*
! 203: * If we see any continuations
! 204: * at a higher level,
! 205: * process them.
! 206: */
! 207: if (check_mem(ms, ++cont_level) == -1)
! 208: return -1;
! 209: }
! 210: done:
! 211: if (magic[magindex].flag & OFFADD) {
! 212: magic[magindex].offset = oldoff;
1.1 deraadt 213: }
214: }
1.11 ! tedu 215: firstline = 0;
! 216: returnval = 1;
! 217: if ((ms->flags & MAGIC_CONTINUE) == 0) {
! 218: return 1; /* don't keep searching */
! 219: }
1.1 deraadt 220: }
1.11 ! tedu 221: return returnval; /* This is hit if -k is set or there is no match */
! 222: }
! 223:
! 224: private int
! 225: check_mem(struct magic_set *ms, unsigned int level)
! 226: {
! 227: size_t len;
! 228:
! 229: if (level < ms->c.len)
! 230: return 0;
! 231:
! 232: len = (ms->c.len += 20) * sizeof(*ms->c.off);
! 233: ms->c.off = (ms->c.off == NULL) ? malloc(len) : realloc(ms->c.off, len);
! 234: if (ms->c.off != NULL)
! 235: return 0;
! 236: file_oomem(ms);
! 237: return -1;
1.1 deraadt 238: }
239:
1.11 ! tedu 240: private int32_t
! 241: mprint(struct magic_set *ms, union VALUETYPE *p, struct magic *m)
1.1 deraadt 242: {
1.8 itojun 243: uint32_t v;
244: int32_t t=0 ;
1.1 deraadt 245:
246:
247: switch (m->type) {
1.11 ! tedu 248: case FILE_BYTE:
! 249: v = file_signextend(ms, m, (size_t)p->b);
! 250: if (file_printf(ms, m->desc, (unsigned char) v) == -1)
! 251: return -1;
1.3 millert 252: t = m->offset + sizeof(char);
1.1 deraadt 253: break;
254:
1.11 ! tedu 255: case FILE_SHORT:
! 256: case FILE_BESHORT:
! 257: case FILE_LESHORT:
! 258: v = file_signextend(ms, m, (size_t)p->h);
! 259: if (file_printf(ms, m->desc, (unsigned short) v) == -1)
! 260: return -1;
1.3 millert 261: t = m->offset + sizeof(short);
1.1 deraadt 262: break;
263:
1.11 ! tedu 264: case FILE_LONG:
! 265: case FILE_BELONG:
! 266: case FILE_LELONG:
! 267: v = file_signextend(ms, m, p->l);
! 268: if (file_printf(ms, m->desc, (uint32_t) v) == -1)
! 269: return -1;
1.8 itojun 270: t = m->offset + sizeof(int32_t);
1.1 deraadt 271: break;
272:
1.11 ! tedu 273: case FILE_STRING:
! 274: case FILE_PSTRING:
1.1 deraadt 275: if (m->reln == '=') {
1.11 ! tedu 276: if (file_printf(ms, m->desc, m->value.s) == -1)
! 277: return -1;
1.3 millert 278: t = m->offset + strlen(m->value.s);
1.1 deraadt 279: }
280: else {
1.3 millert 281: if (*m->value.s == '\0') {
282: char *cp = strchr(p->s,'\n');
283: if (cp)
284: *cp = '\0';
285: }
1.11 ! tedu 286: if (file_printf(ms, m->desc, p->s) == -1)
! 287: return -1;
1.3 millert 288: t = m->offset + strlen(p->s);
1.1 deraadt 289: }
1.3 millert 290: break;
1.1 deraadt 291:
1.11 ! tedu 292: case FILE_DATE:
! 293: case FILE_BEDATE:
! 294: case FILE_LEDATE:
! 295: if (file_printf(ms, m->desc, file_fmttime(p->l, 1)) == -1)
! 296: return -1;
1.3 millert 297: t = m->offset + sizeof(time_t);
298: break;
299:
1.11 ! tedu 300: case FILE_LDATE:
! 301: case FILE_BELDATE:
! 302: case FILE_LELDATE:
! 303: if (file_printf(ms, m->desc, file_fmttime(p->l, 0)) == -1)
! 304: return -1;
! 305: t = m->offset + sizeof(time_t);
! 306: break;
! 307: case FILE_REGEX:
! 308: if (file_printf(ms, m->desc, p->s) == -1)
! 309: return -1;
! 310: t = m->offset + strlen(p->s);
! 311: break;
! 312:
1.1 deraadt 313: default:
1.11 ! tedu 314: file_error(ms, 0, "invalid m->type (%d) in mprint()", m->type);
! 315: return -1;
1.1 deraadt 316: }
1.3 millert 317: return(t);
1.1 deraadt 318: }
319:
320: /*
321: * Convert the byte order of the data we are looking at
1.11 ! tedu 322: * While we're here, let's apply the mask operation
! 323: * (unless you have a better idea)
1.1 deraadt 324: */
1.11 ! tedu 325: private int
! 326: mconvert(struct magic_set *ms, union VALUETYPE *p, struct magic *m)
1.1 deraadt 327: {
328: switch (m->type) {
1.11 ! tedu 329: case FILE_BYTE:
! 330: if (m->mask)
! 331: switch (m->mask_op&0x7F) {
! 332: case FILE_OPAND:
! 333: p->b &= m->mask;
! 334: break;
! 335: case FILE_OPOR:
! 336: p->b |= m->mask;
! 337: break;
! 338: case FILE_OPXOR:
! 339: p->b ^= m->mask;
! 340: break;
! 341: case FILE_OPADD:
! 342: p->b += m->mask;
! 343: break;
! 344: case FILE_OPMINUS:
! 345: p->b -= m->mask;
! 346: break;
! 347: case FILE_OPMULTIPLY:
! 348: p->b *= m->mask;
! 349: break;
! 350: case FILE_OPDIVIDE:
! 351: p->b /= m->mask;
! 352: break;
! 353: case FILE_OPMODULO:
! 354: p->b %= m->mask;
! 355: break;
! 356: }
! 357: if (m->mask_op & FILE_OPINVERSE)
! 358: p->b = ~p->b;
1.1 deraadt 359: return 1;
1.11 ! tedu 360: case FILE_SHORT:
! 361: if (m->mask)
! 362: switch (m->mask_op&0x7F) {
! 363: case FILE_OPAND:
! 364: p->h &= m->mask;
! 365: break;
! 366: case FILE_OPOR:
! 367: p->h |= m->mask;
! 368: break;
! 369: case FILE_OPXOR:
! 370: p->h ^= m->mask;
! 371: break;
! 372: case FILE_OPADD:
! 373: p->h += m->mask;
! 374: break;
! 375: case FILE_OPMINUS:
! 376: p->h -= m->mask;
! 377: break;
! 378: case FILE_OPMULTIPLY:
! 379: p->h *= m->mask;
! 380: break;
! 381: case FILE_OPDIVIDE:
! 382: p->h /= m->mask;
! 383: break;
! 384: case FILE_OPMODULO:
! 385: p->h %= m->mask;
! 386: break;
! 387: }
! 388: if (m->mask_op & FILE_OPINVERSE)
! 389: p->h = ~p->h;
! 390: return 1;
! 391: case FILE_LONG:
! 392: case FILE_DATE:
! 393: case FILE_LDATE:
! 394: if (m->mask)
! 395: switch (m->mask_op&0x7F) {
! 396: case FILE_OPAND:
! 397: p->l &= m->mask;
! 398: break;
! 399: case FILE_OPOR:
! 400: p->l |= m->mask;
! 401: break;
! 402: case FILE_OPXOR:
! 403: p->l ^= m->mask;
! 404: break;
! 405: case FILE_OPADD:
! 406: p->l += m->mask;
! 407: break;
! 408: case FILE_OPMINUS:
! 409: p->l -= m->mask;
! 410: break;
! 411: case FILE_OPMULTIPLY:
! 412: p->l *= m->mask;
! 413: break;
! 414: case FILE_OPDIVIDE:
! 415: p->l /= m->mask;
! 416: break;
! 417: case FILE_OPMODULO:
! 418: p->l %= m->mask;
! 419: break;
! 420: }
! 421: if (m->mask_op & FILE_OPINVERSE)
! 422: p->l = ~p->l;
! 423: return 1;
! 424: case FILE_STRING:
1.3 millert 425: {
1.11 ! tedu 426: int n;
1.3 millert 427:
1.11 ! tedu 428: /* Null terminate and eat *trailing* return */
1.3 millert 429: p->s[sizeof(p->s) - 1] = '\0';
1.11 ! tedu 430: n = strlen(p->s) - 1;
! 431: if (p->s[n] == '\n')
! 432: p->s[n] = '\0';
1.3 millert 433: return 1;
434: }
1.11 ! tedu 435: case FILE_PSTRING:
! 436: {
! 437: char *ptr1 = p->s, *ptr2 = ptr1 + 1;
! 438: unsigned int n = *p->s;
! 439: if (n >= sizeof(p->s))
! 440: n = sizeof(p->s) - 1;
! 441: while (n--)
! 442: *ptr1++ = *ptr2++;
! 443: *ptr1 = '\0';
! 444: n = strlen(p->s) - 1;
! 445: if (p->s[n] == '\n')
! 446: p->s[n] = '\0';
! 447: return 1;
! 448: }
! 449: case FILE_BESHORT:
1.1 deraadt 450: p->h = (short)((p->hs[0]<<8)|(p->hs[1]));
1.11 ! tedu 451: if (m->mask)
! 452: switch (m->mask_op&0x7F) {
! 453: case FILE_OPAND:
! 454: p->h &= m->mask;
! 455: break;
! 456: case FILE_OPOR:
! 457: p->h |= m->mask;
! 458: break;
! 459: case FILE_OPXOR:
! 460: p->h ^= m->mask;
! 461: break;
! 462: case FILE_OPADD:
! 463: p->h += m->mask;
! 464: break;
! 465: case FILE_OPMINUS:
! 466: p->h -= m->mask;
! 467: break;
! 468: case FILE_OPMULTIPLY:
! 469: p->h *= m->mask;
! 470: break;
! 471: case FILE_OPDIVIDE:
! 472: p->h /= m->mask;
! 473: break;
! 474: case FILE_OPMODULO:
! 475: p->h %= m->mask;
! 476: break;
! 477: }
! 478: if (m->mask_op & FILE_OPINVERSE)
! 479: p->h = ~p->h;
1.1 deraadt 480: return 1;
1.11 ! tedu 481: case FILE_BELONG:
! 482: case FILE_BEDATE:
! 483: case FILE_BELDATE:
1.8 itojun 484: p->l = (int32_t)
1.1 deraadt 485: ((p->hl[0]<<24)|(p->hl[1]<<16)|(p->hl[2]<<8)|(p->hl[3]));
1.11 ! tedu 486: if (m->mask)
! 487: switch (m->mask_op&0x7F) {
! 488: case FILE_OPAND:
! 489: p->l &= m->mask;
! 490: break;
! 491: case FILE_OPOR:
! 492: p->l |= m->mask;
! 493: break;
! 494: case FILE_OPXOR:
! 495: p->l ^= m->mask;
! 496: break;
! 497: case FILE_OPADD:
! 498: p->l += m->mask;
! 499: break;
! 500: case FILE_OPMINUS:
! 501: p->l -= m->mask;
! 502: break;
! 503: case FILE_OPMULTIPLY:
! 504: p->l *= m->mask;
! 505: break;
! 506: case FILE_OPDIVIDE:
! 507: p->l /= m->mask;
! 508: break;
! 509: case FILE_OPMODULO:
! 510: p->l %= m->mask;
! 511: break;
! 512: }
! 513: if (m->mask_op & FILE_OPINVERSE)
! 514: p->l = ~p->l;
1.1 deraadt 515: return 1;
1.11 ! tedu 516: case FILE_LESHORT:
1.1 deraadt 517: p->h = (short)((p->hs[1]<<8)|(p->hs[0]));
1.11 ! tedu 518: if (m->mask)
! 519: switch (m->mask_op&0x7F) {
! 520: case FILE_OPAND:
! 521: p->h &= m->mask;
! 522: break;
! 523: case FILE_OPOR:
! 524: p->h |= m->mask;
! 525: break;
! 526: case FILE_OPXOR:
! 527: p->h ^= m->mask;
! 528: break;
! 529: case FILE_OPADD:
! 530: p->h += m->mask;
! 531: break;
! 532: case FILE_OPMINUS:
! 533: p->h -= m->mask;
! 534: break;
! 535: case FILE_OPMULTIPLY:
! 536: p->h *= m->mask;
! 537: break;
! 538: case FILE_OPDIVIDE:
! 539: p->h /= m->mask;
! 540: break;
! 541: case FILE_OPMODULO:
! 542: p->h %= m->mask;
! 543: break;
! 544: }
! 545: if (m->mask_op & FILE_OPINVERSE)
! 546: p->h = ~p->h;
1.1 deraadt 547: return 1;
1.11 ! tedu 548: case FILE_LELONG:
! 549: case FILE_LEDATE:
! 550: case FILE_LELDATE:
1.8 itojun 551: p->l = (int32_t)
1.1 deraadt 552: ((p->hl[3]<<24)|(p->hl[2]<<16)|(p->hl[1]<<8)|(p->hl[0]));
1.11 ! tedu 553: if (m->mask)
! 554: switch (m->mask_op&0x7F) {
! 555: case FILE_OPAND:
! 556: p->l &= m->mask;
! 557: break;
! 558: case FILE_OPOR:
! 559: p->l |= m->mask;
! 560: break;
! 561: case FILE_OPXOR:
! 562: p->l ^= m->mask;
! 563: break;
! 564: case FILE_OPADD:
! 565: p->l += m->mask;
! 566: break;
! 567: case FILE_OPMINUS:
! 568: p->l -= m->mask;
! 569: break;
! 570: case FILE_OPMULTIPLY:
! 571: p->l *= m->mask;
! 572: break;
! 573: case FILE_OPDIVIDE:
! 574: p->l /= m->mask;
! 575: break;
! 576: case FILE_OPMODULO:
! 577: p->l %= m->mask;
! 578: break;
! 579: }
! 580: if (m->mask_op & FILE_OPINVERSE)
! 581: p->l = ~p->l;
! 582: return 1;
! 583: case FILE_REGEX:
1.1 deraadt 584: return 1;
585: default:
1.11 ! tedu 586: file_error(ms, 0, "invalid type %d in mconvert()", m->type);
1.1 deraadt 587: return 0;
588: }
589: }
590:
591:
1.11 ! tedu 592: private void
! 593: mdebug(uint32_t offset, const char *str, size_t len)
1.1 deraadt 594: {
1.3 millert 595: (void) fprintf(stderr, "mget @%d: ", offset);
1.11 ! tedu 596: file_showstr(stderr, str, len);
1.1 deraadt 597: (void) fputc('\n', stderr);
598: (void) fputc('\n', stderr);
599: }
600:
1.11 ! tedu 601: private int
! 602: mget(struct magic_set *ms, union VALUETYPE *p, const unsigned char *s,
! 603: struct magic *m, size_t nbytes)
1.1 deraadt 604: {
1.11 ! tedu 605: uint32_t offset = m->offset;
1.1 deraadt 606:
1.11 ! tedu 607: if (m->type == FILE_REGEX) {
! 608: /*
! 609: * offset is interpreted as last line to search,
! 610: * (starting at 1), not as bytes-from start-of-file
! 611: */
! 612: unsigned char *b, *last = NULL;
! 613: if ((p->buf = strdup((const char *)s)) == NULL) {
! 614: file_oomem(ms);
! 615: return -1;
! 616: }
! 617: for (b = (unsigned char *)p->buf; offset &&
! 618: (b = (unsigned char *)strchr((char *)b, '\n')) != NULL;
! 619: offset--, s++)
! 620: last = b;
! 621: if (last != NULL)
! 622: *last = '\0';
! 623: } else if (offset + sizeof(union VALUETYPE) <= nbytes)
1.1 deraadt 624: memcpy(p, s + offset, sizeof(union VALUETYPE));
625: else {
626: /*
627: * the usefulness of padding with zeroes eludes me, it
628: * might even cause problems
629: */
630: memset(p, 0, sizeof(union VALUETYPE));
1.11 ! tedu 631: if (offset < nbytes)
! 632: memcpy(p, s + offset, nbytes - offset);
1.1 deraadt 633: }
634:
1.11 ! tedu 635: /* Verify we have enough data to match magic type */
! 636: switch (m->type) {
! 637: case FILE_BYTE:
! 638: if (nbytes < (offset + 1)) /* should alway be true */
! 639: return 0;
! 640: break;
1.1 deraadt 641:
1.11 ! tedu 642: case FILE_SHORT:
! 643: case FILE_BESHORT:
! 644: case FILE_LESHORT:
! 645: if (nbytes < (offset + 2))
! 646: return 0;
! 647: break;
! 648:
! 649: case FILE_LONG:
! 650: case FILE_BELONG:
! 651: case FILE_LELONG:
! 652: case FILE_DATE:
! 653: case FILE_BEDATE:
! 654: case FILE_LEDATE:
! 655: case FILE_LDATE:
! 656: case FILE_BELDATE:
! 657: case FILE_LELDATE:
! 658: if (nbytes < (offset + 4))
! 659: return 0;
! 660: break;
! 661:
! 662: case FILE_STRING:
! 663: case FILE_PSTRING:
! 664: if (nbytes < (offset + m->vallen))
! 665: return 0;
! 666: break;
1.1 deraadt 667: }
668:
1.11 ! tedu 669: if ((ms->flags & MAGIC_DEBUG) != 0) {
! 670: mdebug(offset, (char *)(void *)p, sizeof(union VALUETYPE));
! 671: file_mdump(m);
! 672: }
1.1 deraadt 673:
674: if (m->flag & INDIR) {
1.11 ! tedu 675: switch (m->in_type) {
! 676: case FILE_BYTE:
! 677: if (m->in_offset)
! 678: switch (m->in_op&0x7F) {
! 679: case FILE_OPAND:
! 680: offset = p->b & m->in_offset;
! 681: break;
! 682: case FILE_OPOR:
! 683: offset = p->b | m->in_offset;
! 684: break;
! 685: case FILE_OPXOR:
! 686: offset = p->b ^ m->in_offset;
! 687: break;
! 688: case FILE_OPADD:
! 689: offset = p->b + m->in_offset;
! 690: break;
! 691: case FILE_OPMINUS:
! 692: offset = p->b - m->in_offset;
! 693: break;
! 694: case FILE_OPMULTIPLY:
! 695: offset = p->b * m->in_offset;
! 696: break;
! 697: case FILE_OPDIVIDE:
! 698: offset = p->b / m->in_offset;
! 699: break;
! 700: case FILE_OPMODULO:
! 701: offset = p->b % m->in_offset;
! 702: break;
! 703: }
! 704: if (m->in_op & FILE_OPINVERSE)
! 705: offset = ~offset;
! 706: break;
! 707: case FILE_BESHORT:
! 708: if (m->in_offset)
! 709: switch (m->in_op&0x7F) {
! 710: case FILE_OPAND:
! 711: offset = (short)((p->hs[0]<<8)|
! 712: (p->hs[1])) &
! 713: m->in_offset;
! 714: break;
! 715: case FILE_OPOR:
! 716: offset = (short)((p->hs[0]<<8)|
! 717: (p->hs[1])) |
! 718: m->in_offset;
! 719: break;
! 720: case FILE_OPXOR:
! 721: offset = (short)((p->hs[0]<<8)|
! 722: (p->hs[1])) ^
! 723: m->in_offset;
! 724: break;
! 725: case FILE_OPADD:
! 726: offset = (short)((p->hs[0]<<8)|
! 727: (p->hs[1])) +
! 728: m->in_offset;
! 729: break;
! 730: case FILE_OPMINUS:
! 731: offset = (short)((p->hs[0]<<8)|
! 732: (p->hs[1])) -
! 733: m->in_offset;
! 734: break;
! 735: case FILE_OPMULTIPLY:
! 736: offset = (short)((p->hs[0]<<8)|
! 737: (p->hs[1])) *
! 738: m->in_offset;
! 739: break;
! 740: case FILE_OPDIVIDE:
! 741: offset = (short)((p->hs[0]<<8)|
! 742: (p->hs[1])) /
! 743: m->in_offset;
! 744: break;
! 745: case FILE_OPMODULO:
! 746: offset = (short)((p->hs[0]<<8)|
! 747: (p->hs[1])) %
! 748: m->in_offset;
! 749: break;
! 750: }
! 751: if (m->in_op & FILE_OPINVERSE)
! 752: offset = ~offset;
! 753: break;
! 754: case FILE_LESHORT:
! 755: if (m->in_offset)
! 756: switch (m->in_op&0x7F) {
! 757: case FILE_OPAND:
! 758: offset = (short)((p->hs[1]<<8)|
! 759: (p->hs[0])) &
! 760: m->in_offset;
! 761: break;
! 762: case FILE_OPOR:
! 763: offset = (short)((p->hs[1]<<8)|
! 764: (p->hs[0])) |
! 765: m->in_offset;
! 766: break;
! 767: case FILE_OPXOR:
! 768: offset = (short)((p->hs[1]<<8)|
! 769: (p->hs[0])) ^
! 770: m->in_offset;
! 771: break;
! 772: case FILE_OPADD:
! 773: offset = (short)((p->hs[1]<<8)|
! 774: (p->hs[0])) +
! 775: m->in_offset;
! 776: break;
! 777: case FILE_OPMINUS:
! 778: offset = (short)((p->hs[1]<<8)|
! 779: (p->hs[0])) -
! 780: m->in_offset;
! 781: break;
! 782: case FILE_OPMULTIPLY:
! 783: offset = (short)((p->hs[1]<<8)|
! 784: (p->hs[0])) *
! 785: m->in_offset;
! 786: break;
! 787: case FILE_OPDIVIDE:
! 788: offset = (short)((p->hs[1]<<8)|
! 789: (p->hs[0])) /
! 790: m->in_offset;
! 791: break;
! 792: case FILE_OPMODULO:
! 793: offset = (short)((p->hs[1]<<8)|
! 794: (p->hs[0])) %
! 795: m->in_offset;
! 796: break;
! 797: }
! 798: if (m->in_op & FILE_OPINVERSE)
! 799: offset = ~offset;
! 800: break;
! 801: case FILE_SHORT:
! 802: if (m->in_offset)
! 803: switch (m->in_op&0x7F) {
! 804: case FILE_OPAND:
! 805: offset = p->h & m->in_offset;
! 806: break;
! 807: case FILE_OPOR:
! 808: offset = p->h | m->in_offset;
! 809: break;
! 810: case FILE_OPXOR:
! 811: offset = p->h ^ m->in_offset;
! 812: break;
! 813: case FILE_OPADD:
! 814: offset = p->h + m->in_offset;
! 815: break;
! 816: case FILE_OPMINUS:
! 817: offset = p->h - m->in_offset;
! 818: break;
! 819: case FILE_OPMULTIPLY:
! 820: offset = p->h * m->in_offset;
! 821: break;
! 822: case FILE_OPDIVIDE:
! 823: offset = p->h / m->in_offset;
! 824: break;
! 825: case FILE_OPMODULO:
! 826: offset = p->h % m->in_offset;
! 827: break;
! 828: }
! 829: if (m->in_op & FILE_OPINVERSE)
! 830: offset = ~offset;
! 831: break;
! 832: case FILE_BELONG:
! 833: if (m->in_offset)
! 834: switch (m->in_op&0x7F) {
! 835: case FILE_OPAND:
! 836: offset = (int32_t)((p->hl[0]<<24)|
! 837: (p->hl[1]<<16)|
! 838: (p->hl[2]<<8)|
! 839: (p->hl[3])) &
! 840: m->in_offset;
! 841: break;
! 842: case FILE_OPOR:
! 843: offset = (int32_t)((p->hl[0]<<24)|
! 844: (p->hl[1]<<16)|
! 845: (p->hl[2]<<8)|
! 846: (p->hl[3])) |
! 847: m->in_offset;
! 848: break;
! 849: case FILE_OPXOR:
! 850: offset = (int32_t)((p->hl[0]<<24)|
! 851: (p->hl[1]<<16)|
! 852: (p->hl[2]<<8)|
! 853: (p->hl[3])) ^
! 854: m->in_offset;
! 855: break;
! 856: case FILE_OPADD:
! 857: offset = (int32_t)((p->hl[0]<<24)|
! 858: (p->hl[1]<<16)|
! 859: (p->hl[2]<<8)|
! 860: (p->hl[3])) +
! 861: m->in_offset;
! 862: break;
! 863: case FILE_OPMINUS:
! 864: offset = (int32_t)((p->hl[0]<<24)|
! 865: (p->hl[1]<<16)|
! 866: (p->hl[2]<<8)|
! 867: (p->hl[3])) -
! 868: m->in_offset;
! 869: break;
! 870: case FILE_OPMULTIPLY:
! 871: offset = (int32_t)((p->hl[0]<<24)|
! 872: (p->hl[1]<<16)|
! 873: (p->hl[2]<<8)|
! 874: (p->hl[3])) *
! 875: m->in_offset;
! 876: break;
! 877: case FILE_OPDIVIDE:
! 878: offset = (int32_t)((p->hl[0]<<24)|
! 879: (p->hl[1]<<16)|
! 880: (p->hl[2]<<8)|
! 881: (p->hl[3])) /
! 882: m->in_offset;
! 883: break;
! 884: case FILE_OPMODULO:
! 885: offset = (int32_t)((p->hl[0]<<24)|
! 886: (p->hl[1]<<16)|
! 887: (p->hl[2]<<8)|
! 888: (p->hl[3])) %
! 889: m->in_offset;
! 890: break;
! 891: }
! 892: if (m->in_op & FILE_OPINVERSE)
! 893: offset = ~offset;
1.1 deraadt 894: break;
1.11 ! tedu 895: case FILE_LELONG:
! 896: if (m->in_offset)
! 897: switch (m->in_op&0x7F) {
! 898: case FILE_OPAND:
! 899: offset = (int32_t)((p->hl[3]<<24)|
! 900: (p->hl[2]<<16)|
! 901: (p->hl[1]<<8)|
! 902: (p->hl[0])) &
! 903: m->in_offset;
! 904: break;
! 905: case FILE_OPOR:
! 906: offset = (int32_t)((p->hl[3]<<24)|
! 907: (p->hl[2]<<16)|
! 908: (p->hl[1]<<8)|
! 909: (p->hl[0])) |
! 910: m->in_offset;
! 911: break;
! 912: case FILE_OPXOR:
! 913: offset = (int32_t)((p->hl[3]<<24)|
! 914: (p->hl[2]<<16)|
! 915: (p->hl[1]<<8)|
! 916: (p->hl[0])) ^
! 917: m->in_offset;
! 918: break;
! 919: case FILE_OPADD:
! 920: offset = (int32_t)((p->hl[3]<<24)|
! 921: (p->hl[2]<<16)|
! 922: (p->hl[1]<<8)|
! 923: (p->hl[0])) +
! 924: m->in_offset;
! 925: break;
! 926: case FILE_OPMINUS:
! 927: offset = (int32_t)((p->hl[3]<<24)|
! 928: (p->hl[2]<<16)|
! 929: (p->hl[1]<<8)|
! 930: (p->hl[0])) -
! 931: m->in_offset;
! 932: break;
! 933: case FILE_OPMULTIPLY:
! 934: offset = (int32_t)((p->hl[3]<<24)|
! 935: (p->hl[2]<<16)|
! 936: (p->hl[1]<<8)|
! 937: (p->hl[0])) *
! 938: m->in_offset;
! 939: break;
! 940: case FILE_OPDIVIDE:
! 941: offset = (int32_t)((p->hl[3]<<24)|
! 942: (p->hl[2]<<16)|
! 943: (p->hl[1]<<8)|
! 944: (p->hl[0])) /
! 945: m->in_offset;
! 946: break;
! 947: case FILE_OPMODULO:
! 948: offset = (int32_t)((p->hl[3]<<24)|
! 949: (p->hl[2]<<16)|
! 950: (p->hl[1]<<8)|
! 951: (p->hl[0])) %
! 952: m->in_offset;
! 953: break;
! 954: }
! 955: if (m->in_op & FILE_OPINVERSE)
! 956: offset = ~offset;
1.1 deraadt 957: break;
1.11 ! tedu 958: case FILE_LONG:
! 959: if (m->in_offset)
! 960: switch (m->in_op&0x7F) {
! 961: case FILE_OPAND:
! 962: offset = p->l & m->in_offset;
! 963: break;
! 964: case FILE_OPOR:
! 965: offset = p->l | m->in_offset;
! 966: break;
! 967: case FILE_OPXOR:
! 968: offset = p->l ^ m->in_offset;
! 969: break;
! 970: case FILE_OPADD:
! 971: offset = p->l + m->in_offset;
! 972: break;
! 973: case FILE_OPMINUS:
! 974: offset = p->l - m->in_offset;
! 975: break;
! 976: case FILE_OPMULTIPLY:
! 977: offset = p->l * m->in_offset;
! 978: break;
! 979: case FILE_OPDIVIDE:
! 980: offset = p->l / m->in_offset;
! 981: break;
! 982: case FILE_OPMODULO:
! 983: offset = p->l % m->in_offset;
! 984: break;
! 985: /* case TOOMANYSWITCHBLOCKS:
! 986: * ugh = p->eye % m->strain;
! 987: * rub;
! 988: * case BEER:
! 989: * off = p->tab & m->in_gest;
! 990: * sleep;
! 991: */
! 992: }
! 993: if (m->in_op & FILE_OPINVERSE)
! 994: offset = ~offset;
1.1 deraadt 995: break;
996: }
997:
1.11 ! tedu 998: if (nbytes < sizeof(union VALUETYPE) ||
! 999: nbytes - sizeof(union VALUETYPE) < offset)
1.1 deraadt 1000: return 0;
1001:
1002: memcpy(p, s + offset, sizeof(union VALUETYPE));
1003:
1.11 ! tedu 1004: if ((ms->flags & MAGIC_DEBUG) != 0) {
! 1005: mdebug(offset, (char *)(void *)p,
! 1006: sizeof(union VALUETYPE));
! 1007: file_mdump(m);
1.1 deraadt 1008: }
1009: }
1.11 ! tedu 1010: if (!mconvert(ms, p, m))
! 1011: return 0;
1.1 deraadt 1012: return 1;
1013: }
1014:
1.11 ! tedu 1015: private int
! 1016: mcheck(struct magic_set *ms, union VALUETYPE *p, struct magic *m)
1.1 deraadt 1017: {
1.8 itojun 1018: uint32_t l = m->value.l;
1019: uint32_t v;
1.1 deraadt 1020: int matched;
1021:
1022: if ( (m->value.s[0] == 'x') && (m->value.s[1] == '\0') ) {
1023: return 1;
1024: }
1025:
1026:
1027: switch (m->type) {
1.11 ! tedu 1028: case FILE_BYTE:
1.1 deraadt 1029: v = p->b;
1030: break;
1031:
1.11 ! tedu 1032: case FILE_SHORT:
! 1033: case FILE_BESHORT:
! 1034: case FILE_LESHORT:
1.1 deraadt 1035: v = p->h;
1036: break;
1037:
1.11 ! tedu 1038: case FILE_LONG:
! 1039: case FILE_BELONG:
! 1040: case FILE_LELONG:
! 1041: case FILE_DATE:
! 1042: case FILE_BEDATE:
! 1043: case FILE_LEDATE:
! 1044: case FILE_LDATE:
! 1045: case FILE_BELDATE:
! 1046: case FILE_LELDATE:
1.1 deraadt 1047: v = p->l;
1048: break;
1049:
1.11 ! tedu 1050: case FILE_STRING:
! 1051: case FILE_PSTRING:
! 1052: {
! 1053: /*
! 1054: * What we want here is:
1.1 deraadt 1055: * v = strncmp(m->value.s, p->s, m->vallen);
1056: * but ignoring any nulls. bcmp doesn't give -/+/0
1057: * and isn't universally available anyway.
1058: */
1.11 ! tedu 1059: unsigned char *a = (unsigned char*)m->value.s;
! 1060: unsigned char *b = (unsigned char*)p->s;
! 1061: int len = m->vallen;
! 1062: l = 0;
1.1 deraadt 1063: v = 0;
1.11 ! tedu 1064: if (0L == m->mask) { /* normal string: do it fast */
1.1 deraadt 1065: while (--len >= 0)
1.3 millert 1066: if ((v = *b++ - *a++) != '\0')
1.11 ! tedu 1067: break;
! 1068: } else { /* combine the others */
! 1069: while (--len >= 0) {
! 1070: if ((m->mask & STRING_IGNORE_LOWERCASE) &&
! 1071: islower(*a)) {
! 1072: if ((v = tolower(*b++) - *a++) != '\0')
! 1073: break;
! 1074: } else if ((m->mask & STRING_COMPACT_BLANK) &&
! 1075: isspace(*a)) {
! 1076: a++;
! 1077: if (isspace(*b++)) {
! 1078: while (isspace(*b))
! 1079: b++;
! 1080: } else {
! 1081: v = 1;
! 1082: break;
! 1083: }
! 1084: } else if (isspace(*a) &&
! 1085: (m->mask & STRING_COMPACT_OPTIONAL_BLANK)) {
! 1086: a++;
! 1087: while (isspace(*b))
! 1088: b++;
! 1089: } else {
! 1090: if ((v = *b++ - *a++) != '\0')
! 1091: break;
! 1092: }
! 1093: }
1.1 deraadt 1094: }
1095: break;
1.11 ! tedu 1096: }
! 1097: case FILE_REGEX:
! 1098: {
! 1099: int rc;
! 1100: regex_t rx;
! 1101: char errmsg[512];
! 1102:
! 1103: rc = regcomp(&rx, m->value.s, REG_EXTENDED|REG_NOSUB);
! 1104: if (rc) {
! 1105: free(p->buf);
! 1106: regerror(rc, &rx, errmsg, sizeof(errmsg));
! 1107: file_error(ms, 0, "regex error %d, (%s)", rc, errmsg);
! 1108: return -1;
! 1109: } else {
! 1110: rc = regexec(&rx, p->buf, 0, 0, 0);
! 1111: regfree(&rx);
! 1112: free(p->buf);
! 1113: return !rc;
! 1114: }
! 1115: }
1.1 deraadt 1116: default:
1.11 ! tedu 1117: file_error(ms, 0, "invalid type %d in mcheck()", m->type);
! 1118: return -1;
1.1 deraadt 1119: }
1120:
1.11 ! tedu 1121: if (m->type != FILE_STRING && m->type != FILE_PSTRING)
! 1122: v = file_signextend(ms, m, v);
1.1 deraadt 1123:
1124: switch (m->reln) {
1125: case 'x':
1.11 ! tedu 1126: if ((ms->flags & MAGIC_DEBUG) != 0)
1.3 millert 1127: (void) fprintf(stderr, "%u == *any* = 1\n", v);
1.1 deraadt 1128: matched = 1;
1129: break;
1130:
1131: case '!':
1132: matched = v != l;
1.11 ! tedu 1133: if ((ms->flags & MAGIC_DEBUG) != 0)
1.3 millert 1134: (void) fprintf(stderr, "%u != %u = %d\n",
1.1 deraadt 1135: v, l, matched);
1136: break;
1137:
1138: case '=':
1139: matched = v == l;
1.11 ! tedu 1140: if ((ms->flags & MAGIC_DEBUG) != 0)
1.3 millert 1141: (void) fprintf(stderr, "%u == %u = %d\n",
1.1 deraadt 1142: v, l, matched);
1143: break;
1144:
1145: case '>':
1146: if (m->flag & UNSIGNED) {
1147: matched = v > l;
1.11 ! tedu 1148: if ((ms->flags & MAGIC_DEBUG) != 0)
1.3 millert 1149: (void) fprintf(stderr, "%u > %u = %d\n",
1.1 deraadt 1150: v, l, matched);
1151: }
1152: else {
1.8 itojun 1153: matched = (int32_t) v > (int32_t) l;
1.11 ! tedu 1154: if ((ms->flags & MAGIC_DEBUG) != 0)
1.3 millert 1155: (void) fprintf(stderr, "%d > %d = %d\n",
1.1 deraadt 1156: v, l, matched);
1157: }
1158: break;
1159:
1160: case '<':
1161: if (m->flag & UNSIGNED) {
1162: matched = v < l;
1.11 ! tedu 1163: if ((ms->flags & MAGIC_DEBUG) != 0)
1.3 millert 1164: (void) fprintf(stderr, "%u < %u = %d\n",
1.1 deraadt 1165: v, l, matched);
1166: }
1167: else {
1.8 itojun 1168: matched = (int32_t) v < (int32_t) l;
1.11 ! tedu 1169: if ((ms->flags & MAGIC_DEBUG) != 0)
1.3 millert 1170: (void) fprintf(stderr, "%d < %d = %d\n",
1.1 deraadt 1171: v, l, matched);
1172: }
1173: break;
1174:
1175: case '&':
1176: matched = (v & l) == l;
1.11 ! tedu 1177: if ((ms->flags & MAGIC_DEBUG) != 0)
1.3 millert 1178: (void) fprintf(stderr, "((%x & %x) == %x) = %d\n",
1.1 deraadt 1179: v, l, l, matched);
1180: break;
1181:
1182: case '^':
1183: matched = (v & l) != l;
1.11 ! tedu 1184: if ((ms->flags & MAGIC_DEBUG) != 0)
1.3 millert 1185: (void) fprintf(stderr, "((%x & %x) != %x) = %d\n",
1.1 deraadt 1186: v, l, l, matched);
1187: break;
1188:
1189: default:
1190: matched = 0;
1.11 ! tedu 1191: file_error(ms, 0, "cannot happen: invalid relation `%c'",
! 1192: m->reln);
! 1193: return -1;
1.1 deraadt 1194: }
1195:
1196: return matched;
1197: }