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.
33 #include <sys/types.h>
38 FILE_RCSID("@(#)$Id: softmagic.c,v 1.46 2001/07/23 00:02:32 christos Exp $")
41 static int match __P((struct magic *, uint32, unsigned char *, int));
42 static int mget __P((union VALUETYPE *,
43 unsigned char *, struct magic *, int));
44 static int mcheck __P((union VALUETYPE *, struct magic *));
45 static int32 mprint __P((union VALUETYPE *, struct magic *));
46 static void mdebug __P((int32, char *, int));
47 static int mconvert __P((union VALUETYPE *, struct magic *));
52 * softmagic - lookup one file in database
53 * (already read from /etc/magic by apprentice.c).
54 * Passed the name and FILE * of one file to be typed.
56 /*ARGSUSED1*/ /* nbytes passed for regularity, maybe need later */
58 softmagic(buf, nbytes)
64 for (ml = mlist.next; ml != &mlist; ml = ml->next)
65 if (match(ml->magic, ml->nmagic, buf, nbytes))
72 * Go through the whole list, stopping if you find a match. Process all
73 * the continuations of that match before returning.
75 * We support multi-level continuations:
77 * At any time when processing a successful top-level match, there is a
78 * current continuation level; it represents the level of the last
79 * successfully matched continuation.
81 * Continuations above that level are skipped as, if we see one, it
82 * means that the continuation that controls them - i.e, the
83 * lower-level continuation preceding them - failed to match.
85 * Continuations below that level are processed as, if we see one,
86 * it means we've finished processing or skipping higher-level
87 * continuations under the control of a successful or unsuccessful
88 * lower-level continuation, and are now seeing the next lower-level
89 * continuation and should process it. The current continuation
90 * level reverts to the level of the one we're seeing.
92 * Continuations at the current level are processed as, if we see
93 * one, there's no lower-level continuation that may have failed.
95 * If a continuation matches, we bump the current continuation level
96 * so that higher-level continuations are processed.
99 match(magic, nmagic, s, nbytes)
107 int need_separator = 0;
109 static int32 *tmpoff = NULL;
110 static size_t tmplen = 0;
112 int returnval = 0; /* if a match is found it is set to 1*/
113 int firstline = 1; /* a flag to print X\n X\n- X */
116 if ((tmpoff = (int32 *) malloc(tmplen = 20)) == NULL)
117 error("out of memory\n");
119 for (magindex = 0; magindex < nmagic; magindex++) {
120 /* if main entry matches, print it... */
121 if (!mget(&p, s, &magic[magindex], nbytes) ||
122 !mcheck(&p, &magic[magindex])) {
124 * main entry didn't match,
125 * flush its continuations
127 while (magindex < nmagic &&
128 magic[magindex + 1].cont_level != 0)
133 if (! firstline) { /* we found another match */
134 /* put a newline and '-' to do some simple formatting*/
138 tmpoff[cont_level] = mprint(&p, &magic[magindex]);
140 * If we printed something, we'll need to print
141 * a blank before we print something else.
143 if (magic[magindex].desc[0])
145 /* and any continuations that match */
146 if (++cont_level >= tmplen)
147 if ((tmpoff = (int32 *) realloc(tmpoff,
148 tmplen += 20)) == NULL)
149 error("out of memory\n");
150 while (magic[magindex+1].cont_level != 0 &&
151 ++magindex < nmagic) {
152 if (cont_level >= magic[magindex].cont_level) {
153 if (cont_level > magic[magindex].cont_level) {
155 * We're at the end of the level
156 * "cont_level" continuations.
158 cont_level = magic[magindex].cont_level;
160 if (magic[magindex].flag & OFFADD) {
161 oldoff=magic[magindex].offset;
162 magic[magindex].offset +=
163 tmpoff[cont_level-1];
165 if (mget(&p, s, &magic[magindex], nbytes) &&
166 mcheck(&p, &magic[magindex])) {
168 * This continuation matched.
169 * Print its message, with
170 * a blank before it if
171 * the previous item printed
172 * and this item isn't empty.
174 /* space if previous printed */
176 && (magic[magindex].nospflag == 0)
177 && (magic[magindex].desc[0] != '\0')
183 mprint(&p, &magic[magindex]);
184 if (magic[magindex].desc[0])
188 * If we see any continuations
192 if (++cont_level >= tmplen)
194 (int32 *) realloc(tmpoff,
195 tmplen += 20)) == NULL)
196 error("out of memory\n");
198 if (magic[magindex].flag & OFFADD) {
199 magic[magindex].offset = oldoff;
206 return 1; /* don't keep searching */
209 return returnval; /* This is hit if -k is set or there is no match */
223 v = signextend(m, p->b);
224 (void) printf(m->desc, (unsigned char) v);
225 t = m->offset + sizeof(char);
231 v = signextend(m, p->h);
232 (void) printf(m->desc, (unsigned short) v);
233 t = m->offset + sizeof(short);
239 v = signextend(m, p->l);
240 (void) printf(m->desc, (uint32) v);
241 t = m->offset + sizeof(int32);
246 if (m->reln == '=') {
247 (void) printf(m->desc, m->value.s);
248 t = m->offset + strlen(m->value.s);
251 if (*m->value.s == '\0') {
252 char *cp = strchr(p->s,'\n');
256 (void) printf(m->desc, p->s);
257 t = m->offset + strlen(p->s);
264 (void) printf(m->desc, fmttime(p->l, 1));
265 t = m->offset + sizeof(time_t);
271 (void) printf(m->desc, fmttime(p->l, 0));
272 t = m->offset + sizeof(time_t);
276 error("invalid m->type (%d) in mprint().\n", m->type);
283 * Convert the byte order of the data we are looking at
284 * While we're here, let's apply the mask operation
285 * (unless you have a better idea)
295 switch (m->mask_op&0x7F) {
321 if (m->mask_op & OPINVERSE)
326 switch (m->mask_op&0x7F) {
352 if (m->mask_op & OPINVERSE)
359 switch (m->mask_op&0x7F) {
385 if (m->mask_op & OPINVERSE)
392 /* Null terminate and eat *trailing* return */
393 p->s[sizeof(p->s) - 1] = '\0';
394 n = strlen(p->s) - 1;
401 char *ptr1 = p->s, *ptr2 = ptr1 + 1;
403 if (n >= sizeof(p->s))
404 n = sizeof(p->s) - 1;
408 n = strlen(p->s) - 1;
414 p->h = (short)((p->hs[0]<<8)|(p->hs[1]));
416 switch (m->mask_op&0x7F) {
442 if (m->mask_op & OPINVERSE)
449 ((p->hl[0]<<24)|(p->hl[1]<<16)|(p->hl[2]<<8)|(p->hl[3]));
451 switch (m->mask_op&0x7F) {
477 if (m->mask_op & OPINVERSE)
481 p->h = (short)((p->hs[1]<<8)|(p->hs[0]));
483 switch (m->mask_op&0x7F) {
509 if (m->mask_op & OPINVERSE)
516 ((p->hl[3]<<24)|(p->hl[2]<<16)|(p->hl[1]<<8)|(p->hl[0]));
518 switch (m->mask_op&0x7F) {
544 if (m->mask_op & OPINVERSE)
548 error("invalid type %d in mconvert().\n", m->type);
555 mdebug(offset, str, len)
560 (void) fprintf(stderr, "mget @%d: ", offset);
561 showstr(stderr, (char *) str, len);
562 (void) fputc('\n', stderr);
563 (void) fputc('\n', stderr);
567 mget(p, s, m, nbytes)
573 int32 offset = m->offset;
575 if (offset + sizeof(union VALUETYPE) <= nbytes)
576 memcpy(p, s + offset, sizeof(union VALUETYPE));
579 * the usefulness of padding with zeroes eludes me, it
580 * might even cause problems
582 int32 have = nbytes - offset;
583 memset(p, 0, sizeof(union VALUETYPE));
585 memcpy(p, s + offset, have);
590 mdebug(offset, (char *) p, sizeof(union VALUETYPE));
594 if (m->flag & INDIR) {
596 switch (m->in_type) {
599 switch (m->in_op&0x7F) {
601 offset = p->b & m->in_offset;
604 offset = p->b | m->in_offset;
607 offset = p->b ^ m->in_offset;
610 offset = p->b + m->in_offset;
613 offset = p->b - m->in_offset;
616 offset = p->b * m->in_offset;
619 offset = p->b / m->in_offset;
622 offset = p->b % m->in_offset;
625 if (m->in_op & OPINVERSE)
630 switch (m->in_op&0x7F) {
632 offset = (short)((p->hs[0]<<8)|
637 offset = (short)((p->hs[0]<<8)|
642 offset = (short)((p->hs[0]<<8)|
647 offset = (short)((p->hs[0]<<8)|
652 offset = (short)((p->hs[0]<<8)|
657 offset = (short)((p->hs[0]<<8)|
662 offset = (short)((p->hs[0]<<8)|
667 offset = (short)((p->hs[0]<<8)|
672 if (m->in_op & OPINVERSE)
677 switch (m->in_op&0x7F) {
679 offset = (short)((p->hs[1]<<8)|
684 offset = (short)((p->hs[1]<<8)|
689 offset = (short)((p->hs[1]<<8)|
694 offset = (short)((p->hs[1]<<8)|
699 offset = (short)((p->hs[1]<<8)|
704 offset = (short)((p->hs[1]<<8)|
709 offset = (short)((p->hs[1]<<8)|
714 offset = (short)((p->hs[1]<<8)|
719 if (m->in_op & OPINVERSE)
724 switch (m->in_op&0x7F) {
726 offset = p->h & m->in_offset;
729 offset = p->h | m->in_offset;
732 offset = p->h ^ m->in_offset;
735 offset = p->h + m->in_offset;
738 offset = p->h - m->in_offset;
741 offset = p->h * m->in_offset;
744 offset = p->h / m->in_offset;
747 offset = p->h % m->in_offset;
750 if (m->in_op & OPINVERSE)
755 switch (m->in_op&0x7F) {
757 offset = (int32)((p->hl[0]<<24)|
764 offset = (int32)((p->hl[0]<<24)|
771 offset = (int32)((p->hl[0]<<24)|
778 offset = (int32)((p->hl[0]<<24)|
785 offset = (int32)((p->hl[0]<<24)|
792 offset = (int32)((p->hl[0]<<24)|
799 offset = (int32)((p->hl[0]<<24)|
806 offset = (int32)((p->hl[0]<<24)|
813 if (m->in_op & OPINVERSE)
818 switch (m->in_op&0x7F) {
820 offset = (int32)((p->hl[3]<<24)|
827 offset = (int32)((p->hl[3]<<24)|
834 offset = (int32)((p->hl[3]<<24)|
841 offset = (int32)((p->hl[3]<<24)|
848 offset = (int32)((p->hl[3]<<24)|
855 offset = (int32)((p->hl[3]<<24)|
862 offset = (int32)((p->hl[3]<<24)|
869 offset = (int32)((p->hl[3]<<24)|
876 if (m->in_op & OPINVERSE)
881 switch (m->in_op&0x7F) {
883 offset = p->l & m->in_offset;
886 offset = p->l | m->in_offset;
889 offset = p->l ^ m->in_offset;
892 offset = p->l + m->in_offset;
895 offset = p->l - m->in_offset;
898 offset = p->l * m->in_offset;
901 offset = p->l / m->in_offset;
904 offset = p->l % m->in_offset;
906 /* case TOOMANYSWITCHBLOCKS:
907 * ugh = p->eye % m->strain;
910 * off = p->tab & m->in_gest;
914 if (m->in_op & OPINVERSE)
919 if (offset + sizeof(union VALUETYPE) > nbytes)
922 memcpy(p, s + offset, sizeof(union VALUETYPE));
925 mdebug(offset, (char *) p, sizeof(union VALUETYPE));
939 uint32 l = m->value.l;
943 if ( (m->value.s[0] == 'x') && (m->value.s[1] == '\0') ) {
944 fprintf(stderr, "BOINK");
976 * What we want here is:
977 * v = strncmp(m->value.s, p->s, m->vallen);
978 * but ignoring any nulls. bcmp doesn't give -/+/0
979 * and isn't universally available anyway.
981 unsigned char *a = (unsigned char*)m->value.s;
982 unsigned char *b = (unsigned char*)p->s;
986 if (0L == m->mask) { /* normal string: do it fast */
988 if ((v = *b++ - *a++) != '\0')
990 } else { /* combine the others */
992 if ((m->mask & STRING_IGNORE_LOWERCASE) &&
994 if ((v = tolower(*b++) - *a++) != '\0')
996 } else if ((m->mask & STRING_COMPACT_BLANK) &&
1006 } else if (isspace(*a) &&
1007 (m->mask & STRING_COMPACT_OPTIONAL_BLANK)) {
1012 if ((v = *b++ - *a++) != '\0')
1020 error("invalid type %d in mcheck().\n", m->type);
1021 return 0;/*NOTREACHED*/
1024 if(m->type != STRING && m->type != PSTRING)
1025 v = signextend(m, v);
1030 (void) fprintf(stderr, "%u == *any* = 1\n", v);
1037 (void) fprintf(stderr, "%u != %u = %d\n",
1044 (void) fprintf(stderr, "%u == %u = %d\n",
1049 if (m->flag & UNSIGNED) {
1052 (void) fprintf(stderr, "%u > %u = %d\n",
1056 matched = (int32) v > (int32) l;
1058 (void) fprintf(stderr, "%d > %d = %d\n",
1064 if (m->flag & UNSIGNED) {
1067 (void) fprintf(stderr, "%u < %u = %d\n",
1071 matched = (int32) v < (int32) l;
1073 (void) fprintf(stderr, "%d < %d = %d\n",
1079 matched = (v & l) == l;
1081 (void) fprintf(stderr, "((%x & %x) == %x) = %d\n",
1086 matched = (v & l) != l;
1088 (void) fprintf(stderr, "((%x & %x) != %x) = %d\n",
1094 error("mcheck: can't happen: invalid relation %d.\n", m->reln);
1095 break;/*NOTREACHED*/