2 * softmagic - interpret variable magic from MAGIC
4 * Copyright (c) Ian F. Darwin, 1987.
5 * Written by Ian F. Darwin.
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.
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:
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.
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.
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.
25 * 4. This notice may not be removed or altered.
37 FILE_RCSID("@(#)$Id: softmagic.c,v 1.54 2003/02/25 13:04:32 christos Exp $")
40 static int match(struct magic *, uint32_t, unsigned char *, int);
41 static int mget(union VALUETYPE *, unsigned char *, struct magic *, int);
42 static int mcheck(union VALUETYPE *, struct magic *);
43 static int32_t mprint(union VALUETYPE *, struct magic *);
44 static void mdebug(int32_t, char *, int);
45 static int mconvert(union VALUETYPE *, struct magic *);
50 * softmagic - lookup one file in database
51 * (already read from MAGIC by apprentice.c).
52 * Passed the name and FILE * of one file to be typed.
54 /*ARGSUSED1*/ /* nbytes passed for regularity, maybe need later */
56 softmagic(unsigned char *buf, int nbytes)
60 for (ml = mlist.next; ml != &mlist; ml = ml->next)
61 if (match(ml->magic, ml->nmagic, buf, nbytes))
68 * Go through the whole list, stopping if you find a match. Process all
69 * the continuations of that match before returning.
71 * We support multi-level continuations:
73 * At any time when processing a successful top-level match, there is a
74 * current continuation level; it represents the level of the last
75 * successfully matched continuation.
77 * Continuations above that level are skipped as, if we see one, it
78 * means that the continuation that controls them - i.e, the
79 * lower-level continuation preceding them - failed to match.
81 * Continuations below that level are processed as, if we see one,
82 * it means we've finished processing or skipping higher-level
83 * continuations under the control of a successful or unsuccessful
84 * lower-level continuation, and are now seeing the next lower-level
85 * continuation and should process it. The current continuation
86 * level reverts to the level of the one we're seeing.
88 * Continuations at the current level are processed as, if we see
89 * one, there's no lower-level continuation that may have failed.
91 * If a continuation matches, we bump the current continuation level
92 * so that higher-level continuations are processed.
95 match(struct magic *magic, uint32_t nmagic, unsigned char *s, int nbytes)
99 int need_separator = 0;
101 static int32_t *tmpoff = NULL;
102 static size_t tmplen = 0;
104 int returnval = 0; /* if a match is found it is set to 1*/
105 int firstline = 1; /* a flag to print X\n X\n- X */
108 if ((tmpoff = (int32_t *) malloc(
109 (tmplen = 20) * sizeof(*tmpoff))) == NULL)
110 error("out of memory\n");
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])) {
117 * main entry didn't match,
118 * flush its continuations
120 while (magindex < nmagic &&
121 magic[magindex + 1].cont_level != 0)
126 if (! firstline) { /* we found another match */
127 /* put a newline and '-' to do some simple formatting*/
131 tmpoff[cont_level] = mprint(&p, &magic[magindex]);
133 * If we printed something, we'll need to print
134 * a blank before we print something else.
136 if (magic[magindex].desc[0])
138 /* and any continuations that match */
139 if (++cont_level >= tmplen)
140 if ((tmpoff = (int32_t *) realloc(tmpoff,
141 (tmplen += 20) * sizeof(*tmpoff))) == NULL)
142 error("out of memory\n");
143 while (magic[magindex+1].cont_level != 0 &&
144 ++magindex < nmagic) {
145 if (cont_level >= magic[magindex].cont_level) {
146 if (cont_level > magic[magindex].cont_level) {
148 * We're at the end of the level
149 * "cont_level" continuations.
151 cont_level = magic[magindex].cont_level;
153 if (magic[magindex].flag & OFFADD) {
154 oldoff=magic[magindex].offset;
155 magic[magindex].offset +=
156 tmpoff[cont_level-1];
158 if (mget(&p, s, &magic[magindex], nbytes) &&
159 mcheck(&p, &magic[magindex])) {
161 * This continuation matched.
162 * Print its message, with
163 * a blank before it if
164 * the previous item printed
165 * and this item isn't empty.
167 /* space if previous printed */
169 && (magic[magindex].nospflag == 0)
170 && (magic[magindex].desc[0] != '\0')
176 mprint(&p, &magic[magindex]);
177 if (magic[magindex].desc[0])
181 * If we see any continuations
185 if (++cont_level >= tmplen)
187 (int32_t *) realloc(tmpoff,
189 * sizeof(*tmpoff))) == NULL)
190 error("out of memory\n");
192 if (magic[magindex].flag & OFFADD) {
193 magic[magindex].offset = oldoff;
200 return 1; /* don't keep searching */
203 return returnval; /* This is hit if -k is set or there is no match */
207 mprint(union VALUETYPE *p, struct magic *m)
215 v = signextend(m, p->b);
216 (void) printf(m->desc, (unsigned char) v);
217 t = m->offset + sizeof(char);
223 v = signextend(m, p->h);
224 (void) printf(m->desc, (unsigned short) v);
225 t = m->offset + sizeof(short);
231 v = signextend(m, p->l);
232 (void) printf(m->desc, (uint32_t) v);
233 t = m->offset + sizeof(int32_t);
238 if (m->reln == '=') {
239 (void) printf(m->desc, m->value.s);
240 t = m->offset + strlen(m->value.s);
243 if (*m->value.s == '\0') {
244 char *cp = strchr(p->s,'\n');
248 (void) printf(m->desc, p->s);
249 t = m->offset + strlen(p->s);
256 (void) printf(m->desc, fmttime(p->l, 1));
257 t = m->offset + sizeof(time_t);
263 (void) printf(m->desc, fmttime(p->l, 0));
264 t = m->offset + sizeof(time_t);
267 (void) printf(m->desc, p->s);
268 t = m->offset + strlen(p->s);
272 error("invalid m->type (%d) in mprint().\n", m->type);
279 * Convert the byte order of the data we are looking at
280 * While we're here, let's apply the mask operation
281 * (unless you have a better idea)
284 mconvert(union VALUETYPE *p, struct magic *m)
289 switch (m->mask_op&0x7F) {
315 if (m->mask_op & OPINVERSE)
320 switch (m->mask_op&0x7F) {
346 if (m->mask_op & OPINVERSE)
353 switch (m->mask_op&0x7F) {
379 if (m->mask_op & OPINVERSE)
386 /* Null terminate and eat *trailing* return */
387 p->s[sizeof(p->s) - 1] = '\0';
388 n = strlen(p->s) - 1;
395 char *ptr1 = p->s, *ptr2 = ptr1 + 1;
397 if (n >= sizeof(p->s))
398 n = sizeof(p->s) - 1;
402 n = strlen(p->s) - 1;
408 p->h = (short)((p->hs[0]<<8)|(p->hs[1]));
410 switch (m->mask_op&0x7F) {
436 if (m->mask_op & OPINVERSE)
443 ((p->hl[0]<<24)|(p->hl[1]<<16)|(p->hl[2]<<8)|(p->hl[3]));
445 switch (m->mask_op&0x7F) {
471 if (m->mask_op & OPINVERSE)
475 p->h = (short)((p->hs[1]<<8)|(p->hs[0]));
477 switch (m->mask_op&0x7F) {
503 if (m->mask_op & OPINVERSE)
510 ((p->hl[3]<<24)|(p->hl[2]<<16)|(p->hl[1]<<8)|(p->hl[0]));
512 switch (m->mask_op&0x7F) {
538 if (m->mask_op & OPINVERSE)
544 error("invalid type %d in mconvert().\n", m->type);
551 mdebug(int32_t offset, char *str, int len)
553 (void) fprintf(stderr, "mget @%d: ", offset);
554 showstr(stderr, (char *) str, len);
555 (void) fputc('\n', stderr);
556 (void) fputc('\n', stderr);
560 mget(union VALUETYPE *p, unsigned char *s, struct magic *m, int nbytes)
562 int32_t offset = m->offset;
564 if (m->type == REGEX) {
566 * offset is interpreted as last line to search,
567 * (starting at 1), not as bytes-from start-of-file
569 unsigned char *last = NULL;
571 for (; offset && (s = (unsigned char *)strchr(s, '\n')) != NULL;
576 } else if (offset + sizeof(union VALUETYPE) <= nbytes)
577 memcpy(p, s + offset, sizeof(union VALUETYPE));
580 * the usefulness of padding with zeroes eludes me, it
581 * might even cause problems
583 int32_t have = nbytes - offset;
584 memset(p, 0, sizeof(union VALUETYPE));
586 memcpy(p, s + offset, have);
590 mdebug(offset, (char *) p, sizeof(union VALUETYPE));
594 if (m->flag & INDIR) {
595 switch (m->in_type) {
598 switch (m->in_op&0x7F) {
600 offset = p->b & m->in_offset;
603 offset = p->b | m->in_offset;
606 offset = p->b ^ m->in_offset;
609 offset = p->b + m->in_offset;
612 offset = p->b - m->in_offset;
615 offset = p->b * m->in_offset;
618 offset = p->b / m->in_offset;
621 offset = p->b % m->in_offset;
624 if (m->in_op & OPINVERSE)
629 switch (m->in_op&0x7F) {
631 offset = (short)((p->hs[0]<<8)|
636 offset = (short)((p->hs[0]<<8)|
641 offset = (short)((p->hs[0]<<8)|
646 offset = (short)((p->hs[0]<<8)|
651 offset = (short)((p->hs[0]<<8)|
656 offset = (short)((p->hs[0]<<8)|
661 offset = (short)((p->hs[0]<<8)|
666 offset = (short)((p->hs[0]<<8)|
671 if (m->in_op & OPINVERSE)
676 switch (m->in_op&0x7F) {
678 offset = (short)((p->hs[1]<<8)|
683 offset = (short)((p->hs[1]<<8)|
688 offset = (short)((p->hs[1]<<8)|
693 offset = (short)((p->hs[1]<<8)|
698 offset = (short)((p->hs[1]<<8)|
703 offset = (short)((p->hs[1]<<8)|
708 offset = (short)((p->hs[1]<<8)|
713 offset = (short)((p->hs[1]<<8)|
718 if (m->in_op & OPINVERSE)
723 switch (m->in_op&0x7F) {
725 offset = p->h & m->in_offset;
728 offset = p->h | m->in_offset;
731 offset = p->h ^ m->in_offset;
734 offset = p->h + m->in_offset;
737 offset = p->h - m->in_offset;
740 offset = p->h * m->in_offset;
743 offset = p->h / m->in_offset;
746 offset = p->h % m->in_offset;
749 if (m->in_op & OPINVERSE)
754 switch (m->in_op&0x7F) {
756 offset = (int32_t)((p->hl[0]<<24)|
763 offset = (int32_t)((p->hl[0]<<24)|
770 offset = (int32_t)((p->hl[0]<<24)|
777 offset = (int32_t)((p->hl[0]<<24)|
784 offset = (int32_t)((p->hl[0]<<24)|
791 offset = (int32_t)((p->hl[0]<<24)|
798 offset = (int32_t)((p->hl[0]<<24)|
805 offset = (int32_t)((p->hl[0]<<24)|
812 if (m->in_op & OPINVERSE)
817 switch (m->in_op&0x7F) {
819 offset = (int32_t)((p->hl[3]<<24)|
826 offset = (int32_t)((p->hl[3]<<24)|
833 offset = (int32_t)((p->hl[3]<<24)|
840 offset = (int32_t)((p->hl[3]<<24)|
847 offset = (int32_t)((p->hl[3]<<24)|
854 offset = (int32_t)((p->hl[3]<<24)|
861 offset = (int32_t)((p->hl[3]<<24)|
868 offset = (int32_t)((p->hl[3]<<24)|
875 if (m->in_op & OPINVERSE)
880 switch (m->in_op&0x7F) {
882 offset = p->l & m->in_offset;
885 offset = p->l | m->in_offset;
888 offset = p->l ^ m->in_offset;
891 offset = p->l + m->in_offset;
894 offset = p->l - m->in_offset;
897 offset = p->l * m->in_offset;
900 offset = p->l / m->in_offset;
903 offset = p->l % m->in_offset;
905 /* case TOOMANYSWITCHBLOCKS:
906 * ugh = p->eye % m->strain;
909 * off = p->tab & m->in_gest;
913 if (m->in_op & OPINVERSE)
918 if (offset + sizeof(union VALUETYPE) > nbytes)
921 memcpy(p, s + offset, sizeof(union VALUETYPE));
924 mdebug(offset, (char *) p, sizeof(union VALUETYPE));
934 mcheck(union VALUETYPE *p, struct magic *m)
936 uint32_t l = m->value.l;
940 if ( (m->value.s[0] == 'x') && (m->value.s[1] == '\0') ) {
941 fprintf(stderr, "BOINK");
973 * What we want here is:
974 * v = strncmp(m->value.s, p->s, m->vallen);
975 * but ignoring any nulls. bcmp doesn't give -/+/0
976 * and isn't universally available anyway.
978 unsigned char *a = (unsigned char*)m->value.s;
979 unsigned char *b = (unsigned char*)p->s;
983 if (0L == m->mask) { /* normal string: do it fast */
985 if ((v = *b++ - *a++) != '\0')
987 } else { /* combine the others */
989 if ((m->mask & STRING_IGNORE_LOWERCASE) &&
991 if ((v = tolower(*b++) - *a++) != '\0')
993 } else if ((m->mask & STRING_COMPACT_BLANK) &&
1003 } else if (isspace(*a) &&
1004 (m->mask & STRING_COMPACT_OPTIONAL_BLANK)) {
1009 if ((v = *b++ - *a++) != '\0')
1022 rc = regcomp(&rx, m->value.s, REG_EXTENDED|REG_NOSUB);
1024 regerror(rc, &rx, errmsg, sizeof(errmsg));
1025 error("regex error %d, (%s)\n", rc, errmsg);
1027 rc = regexec(&rx, p->buf, 0, 0, 0);
1032 error("invalid type %d in mcheck().\n", m->type);
1033 return 0;/*NOTREACHED*/
1036 if(m->type != STRING && m->type != PSTRING)
1037 v = signextend(m, v);
1042 (void) fprintf(stderr, "%u == *any* = 1\n", v);
1049 (void) fprintf(stderr, "%u != %u = %d\n",
1056 (void) fprintf(stderr, "%u == %u = %d\n",
1061 if (m->flag & UNSIGNED) {
1064 (void) fprintf(stderr, "%u > %u = %d\n",
1068 matched = (int32_t) v > (int32_t) l;
1070 (void) fprintf(stderr, "%d > %d = %d\n",
1076 if (m->flag & UNSIGNED) {
1079 (void) fprintf(stderr, "%u < %u = %d\n",
1083 matched = (int32_t) v < (int32_t) l;
1085 (void) fprintf(stderr, "%d < %d = %d\n",
1091 matched = (v & l) == l;
1093 (void) fprintf(stderr, "((%x & %x) == %x) = %d\n",
1098 matched = (v & l) != l;
1100 (void) fprintf(stderr, "((%x & %x) != %x) = %d\n",
1106 error("mcheck: can't happen: invalid relation %d.\n", m->reln);
1107 break;/*NOTREACHED*/