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.51 2002/07/03 18:26:38 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(tmplen = 20)) == NULL)
109 error("out of memory\n");
111 for (magindex = 0; magindex < nmagic; magindex++) {
112 /* if main entry matches, print it... */
113 if (!mget(&p, s, &magic[magindex], nbytes) ||
114 !mcheck(&p, &magic[magindex])) {
116 * main entry didn't match,
117 * flush its continuations
119 while (magindex < nmagic &&
120 magic[magindex + 1].cont_level != 0)
125 if (! firstline) { /* we found another match */
126 /* put a newline and '-' to do some simple formatting*/
130 tmpoff[cont_level] = mprint(&p, &magic[magindex]);
132 * If we printed something, we'll need to print
133 * a blank before we print something else.
135 if (magic[magindex].desc[0])
137 /* and any continuations that match */
138 if (++cont_level >= tmplen)
139 if ((tmpoff = (int32_t *) realloc(tmpoff,
140 tmplen += 20)) == NULL)
141 error("out of memory\n");
142 while (magic[magindex+1].cont_level != 0 &&
143 ++magindex < nmagic) {
144 if (cont_level >= magic[magindex].cont_level) {
145 if (cont_level > magic[magindex].cont_level) {
147 * We're at the end of the level
148 * "cont_level" continuations.
150 cont_level = magic[magindex].cont_level;
152 if (magic[magindex].flag & OFFADD) {
153 oldoff=magic[magindex].offset;
154 magic[magindex].offset +=
155 tmpoff[cont_level-1];
157 if (mget(&p, s, &magic[magindex], nbytes) &&
158 mcheck(&p, &magic[magindex])) {
160 * This continuation matched.
161 * Print its message, with
162 * a blank before it if
163 * the previous item printed
164 * and this item isn't empty.
166 /* space if previous printed */
168 && (magic[magindex].nospflag == 0)
169 && (magic[magindex].desc[0] != '\0')
175 mprint(&p, &magic[magindex]);
176 if (magic[magindex].desc[0])
180 * If we see any continuations
184 if (++cont_level >= tmplen)
186 (int32_t *) realloc(tmpoff,
187 tmplen += 20)) == NULL)
188 error("out of memory\n");
190 if (magic[magindex].flag & OFFADD) {
191 magic[magindex].offset = oldoff;
198 return 1; /* don't keep searching */
201 return returnval; /* This is hit if -k is set or there is no match */
205 mprint(union VALUETYPE *p, struct magic *m)
213 v = signextend(m, p->b);
214 (void) printf(m->desc, (unsigned char) v);
215 t = m->offset + sizeof(char);
221 v = signextend(m, p->h);
222 (void) printf(m->desc, (unsigned short) v);
223 t = m->offset + sizeof(short);
229 v = signextend(m, p->l);
230 (void) printf(m->desc, (uint32_t) v);
231 t = m->offset + sizeof(int32_t);
236 if (m->reln == '=') {
237 (void) printf(m->desc, m->value.s);
238 t = m->offset + strlen(m->value.s);
241 if (*m->value.s == '\0') {
242 char *cp = strchr(p->s,'\n');
246 (void) printf(m->desc, p->s);
247 t = m->offset + strlen(p->s);
254 (void) printf(m->desc, fmttime(p->l, 1));
255 t = m->offset + sizeof(time_t);
261 (void) printf(m->desc, fmttime(p->l, 0));
262 t = m->offset + sizeof(time_t);
265 (void) printf(m->desc, p->s);
266 t = m->offset + strlen(p->s);
270 error("invalid m->type (%d) in mprint().\n", m->type);
277 * Convert the byte order of the data we are looking at
278 * While we're here, let's apply the mask operation
279 * (unless you have a better idea)
282 mconvert(union VALUETYPE *p, struct magic *m)
287 switch (m->mask_op&0x7F) {
313 if (m->mask_op & OPINVERSE)
318 switch (m->mask_op&0x7F) {
344 if (m->mask_op & OPINVERSE)
351 switch (m->mask_op&0x7F) {
377 if (m->mask_op & OPINVERSE)
384 /* Null terminate and eat *trailing* return */
385 p->s[sizeof(p->s) - 1] = '\0';
386 n = strlen(p->s) - 1;
393 char *ptr1 = p->s, *ptr2 = ptr1 + 1;
395 if (n >= sizeof(p->s))
396 n = sizeof(p->s) - 1;
400 n = strlen(p->s) - 1;
406 p->h = (short)((p->hs[0]<<8)|(p->hs[1]));
408 switch (m->mask_op&0x7F) {
434 if (m->mask_op & OPINVERSE)
441 ((p->hl[0]<<24)|(p->hl[1]<<16)|(p->hl[2]<<8)|(p->hl[3]));
443 switch (m->mask_op&0x7F) {
469 if (m->mask_op & OPINVERSE)
473 p->h = (short)((p->hs[1]<<8)|(p->hs[0]));
475 switch (m->mask_op&0x7F) {
501 if (m->mask_op & OPINVERSE)
508 ((p->hl[3]<<24)|(p->hl[2]<<16)|(p->hl[1]<<8)|(p->hl[0]));
510 switch (m->mask_op&0x7F) {
536 if (m->mask_op & OPINVERSE)
542 error("invalid type %d in mconvert().\n", m->type);
549 mdebug(int32_t offset, char *str, int len)
551 (void) fprintf(stderr, "mget @%d: ", offset);
552 showstr(stderr, (char *) str, len);
553 (void) fputc('\n', stderr);
554 (void) fputc('\n', stderr);
558 mget(union VALUETYPE *p, unsigned char *s, struct magic *m, int nbytes)
560 int32_t offset = m->offset;
562 if (m->type == REGEX) {
564 * offset is interpreted as last line to search,
565 * (starting at 1), not as bytes-from start-of-file
569 for (; offset && (s = strchr(s, '\n')) != NULL; offset--, s++)
573 } else if (offset + sizeof(union VALUETYPE) <= nbytes)
574 memcpy(p, s + offset, sizeof(union VALUETYPE));
577 * the usefulness of padding with zeroes eludes me, it
578 * might even cause problems
580 int32_t have = nbytes - offset;
581 memset(p, 0, sizeof(union VALUETYPE));
583 memcpy(p, s + offset, have);
587 mdebug(offset, (char *) p, sizeof(union VALUETYPE));
591 if (m->flag & INDIR) {
592 switch (m->in_type) {
595 switch (m->in_op&0x7F) {
597 offset = p->b & m->in_offset;
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 if (m->in_op & OPINVERSE)
626 switch (m->in_op&0x7F) {
628 offset = (short)((p->hs[0]<<8)|
633 offset = (short)((p->hs[0]<<8)|
638 offset = (short)((p->hs[0]<<8)|
643 offset = (short)((p->hs[0]<<8)|
648 offset = (short)((p->hs[0]<<8)|
653 offset = (short)((p->hs[0]<<8)|
658 offset = (short)((p->hs[0]<<8)|
663 offset = (short)((p->hs[0]<<8)|
668 if (m->in_op & OPINVERSE)
673 switch (m->in_op&0x7F) {
675 offset = (short)((p->hs[1]<<8)|
680 offset = (short)((p->hs[1]<<8)|
685 offset = (short)((p->hs[1]<<8)|
690 offset = (short)((p->hs[1]<<8)|
695 offset = (short)((p->hs[1]<<8)|
700 offset = (short)((p->hs[1]<<8)|
705 offset = (short)((p->hs[1]<<8)|
710 offset = (short)((p->hs[1]<<8)|
715 if (m->in_op & OPINVERSE)
720 switch (m->in_op&0x7F) {
722 offset = p->h & m->in_offset;
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 if (m->in_op & OPINVERSE)
751 switch (m->in_op&0x7F) {
753 offset = (int32_t)((p->hl[0]<<24)|
760 offset = (int32_t)((p->hl[0]<<24)|
767 offset = (int32_t)((p->hl[0]<<24)|
774 offset = (int32_t)((p->hl[0]<<24)|
781 offset = (int32_t)((p->hl[0]<<24)|
788 offset = (int32_t)((p->hl[0]<<24)|
795 offset = (int32_t)((p->hl[0]<<24)|
802 offset = (int32_t)((p->hl[0]<<24)|
809 if (m->in_op & OPINVERSE)
814 switch (m->in_op&0x7F) {
816 offset = (int32_t)((p->hl[3]<<24)|
823 offset = (int32_t)((p->hl[3]<<24)|
830 offset = (int32_t)((p->hl[3]<<24)|
837 offset = (int32_t)((p->hl[3]<<24)|
844 offset = (int32_t)((p->hl[3]<<24)|
851 offset = (int32_t)((p->hl[3]<<24)|
858 offset = (int32_t)((p->hl[3]<<24)|
865 offset = (int32_t)((p->hl[3]<<24)|
872 if (m->in_op & OPINVERSE)
877 switch (m->in_op&0x7F) {
879 offset = p->l & m->in_offset;
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;
902 /* case TOOMANYSWITCHBLOCKS:
903 * ugh = p->eye % m->strain;
906 * off = p->tab & m->in_gest;
910 if (m->in_op & OPINVERSE)
915 if (offset + sizeof(union VALUETYPE) > nbytes)
918 memcpy(p, s + offset, sizeof(union VALUETYPE));
921 mdebug(offset, (char *) p, sizeof(union VALUETYPE));
931 mcheck(union VALUETYPE *p, struct magic *m)
933 uint32_t l = m->value.l;
937 if ( (m->value.s[0] == 'x') && (m->value.s[1] == '\0') ) {
938 fprintf(stderr, "BOINK");
970 * What we want here is:
971 * v = strncmp(m->value.s, p->s, m->vallen);
972 * but ignoring any nulls. bcmp doesn't give -/+/0
973 * and isn't universally available anyway.
975 unsigned char *a = (unsigned char*)m->value.s;
976 unsigned char *b = (unsigned char*)p->s;
980 if (0L == m->mask) { /* normal string: do it fast */
982 if ((v = *b++ - *a++) != '\0')
984 } else { /* combine the others */
986 if ((m->mask & STRING_IGNORE_LOWERCASE) &&
988 if ((v = tolower(*b++) - *a++) != '\0')
990 } else if ((m->mask & STRING_COMPACT_BLANK) &&
1000 } else if (isspace(*a) &&
1001 (m->mask & STRING_COMPACT_OPTIONAL_BLANK)) {
1006 if ((v = *b++ - *a++) != '\0')
1019 rc = regcomp(&rx, m->value.s, REG_EXTENDED|REG_NOSUB);
1021 regerror(rc, &rx, errmsg, sizeof(errmsg));
1022 error("regex error %d, (%s)\n", rc, errmsg);
1024 rc = regexec(&rx, p->buf, 0, 0, 0);
1029 error("invalid type %d in mcheck().\n", m->type);
1030 return 0;/*NOTREACHED*/
1033 if(m->type != STRING && m->type != PSTRING)
1034 v = signextend(m, v);
1039 (void) fprintf(stderr, "%u == *any* = 1\n", v);
1046 (void) fprintf(stderr, "%u != %u = %d\n",
1053 (void) fprintf(stderr, "%u == %u = %d\n",
1058 if (m->flag & UNSIGNED) {
1061 (void) fprintf(stderr, "%u > %u = %d\n",
1065 matched = (int32_t) v > (int32_t) l;
1067 (void) fprintf(stderr, "%d > %d = %d\n",
1073 if (m->flag & UNSIGNED) {
1076 (void) fprintf(stderr, "%u < %u = %d\n",
1080 matched = (int32_t) v < (int32_t) l;
1082 (void) fprintf(stderr, "%d < %d = %d\n",
1088 matched = (v & l) == l;
1090 (void) fprintf(stderr, "((%x & %x) == %x) = %d\n",
1095 matched = (v & l) != l;
1097 (void) fprintf(stderr, "((%x & %x) != %x) = %d\n",
1103 error("mcheck: can't happen: invalid relation %d.\n", m->reln);
1104 break;/*NOTREACHED*/