2 * Copyright (c) Ian F. Darwin 1986-1995.
3 * Software written by Ian F. Darwin and others;
4 * maintained 1995-present by Christos Zoulas and others.
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
9 * 1. Redistributions of source code must retain the above copyright
10 * notice immediately at the beginning of the file, without modification,
11 * this list of conditions, and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
20 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 * softmagic - interpret variable magic from MAGIC
35 FILE_RCSID("@(#)$File: softmagic.c,v 1.262 2018/06/22 20:39:50 christos Exp $")
46 private int match(struct magic_set *, struct magic *, uint32_t,
47 const struct buffer *, size_t, int, int, int, uint16_t *,
48 uint16_t *, int *, int *, int *);
49 private int mget(struct magic_set *, struct magic *, const struct buffer *,
50 const unsigned char *, size_t,
51 size_t, unsigned int, int, int, int, uint16_t *,
52 uint16_t *, int *, int *, int *);
53 private int msetoffset(struct magic_set *, struct magic *, struct buffer *,
54 const struct buffer *, size_t, unsigned int);
55 private int magiccheck(struct magic_set *, struct magic *);
56 private int32_t mprint(struct magic_set *, struct magic *);
57 private int moffset(struct magic_set *, struct magic *, const struct buffer *,
59 private void mdebug(uint32_t, const char *, size_t);
60 private int mcopy(struct magic_set *, union VALUETYPE *, int, int,
61 const unsigned char *, uint32_t, size_t, struct magic *);
62 private int mconvert(struct magic_set *, struct magic *, int);
63 private int print_sep(struct magic_set *, int);
64 private int handle_annotation(struct magic_set *, struct magic *, int);
65 private int cvt_8(union VALUETYPE *, const struct magic *);
66 private int cvt_16(union VALUETYPE *, const struct magic *);
67 private int cvt_32(union VALUETYPE *, const struct magic *);
68 private int cvt_64(union VALUETYPE *, const struct magic *);
70 #define OFFSET_OOB(n, o, i) ((n) < (uint32_t)(o) || (i) > ((n) - (o)))
71 #define BE64(p) (((uint64_t)(p)->hq[0]<<56)|((uint64_t)(p)->hq[1]<<48)| \
72 ((uint64_t)(p)->hq[2]<<40)|((uint64_t)(p)->hq[3]<<32)| \
73 ((uint64_t)(p)->hq[4]<<24)|((uint64_t)(p)->hq[5]<<16)| \
74 ((uint64_t)(p)->hq[6]<<8)|((uint64_t)(p)->hq[7]))
75 #define LE64(p) (((uint64_t)(p)->hq[7]<<56)|((uint64_t)(p)->hq[6]<<48)| \
76 ((uint64_t)(p)->hq[5]<<40)|((uint64_t)(p)->hq[4]<<32)| \
77 ((uint64_t)(p)->hq[3]<<24)|((uint64_t)(p)->hq[2]<<16)| \
78 ((uint64_t)(p)->hq[1]<<8)|((uint64_t)(p)->hq[0]))
79 #define LE32(p) (((uint32_t)(p)->hl[3]<<24)|((uint32_t)(p)->hl[2]<<16)| \
80 ((uint32_t)(p)->hl[1]<<8)|((uint32_t)(p)->hl[0]))
81 #define BE32(p) (((uint32_t)(p)->hl[0]<<24)|((uint32_t)(p)->hl[1]<<16)| \
82 ((uint32_t)(p)->hl[2]<<8)|((uint32_t)(p)->hl[3]))
83 #define ME32(p) (((uint32_t)(p)->hl[1]<<24)|((uint32_t)(p)->hl[0]<<16)| \
84 ((uint32_t)(p)->hl[3]<<8)|((uint32_t)(p)->hl[2]))
85 #define BE16(p) (((uint16_t)(p)->hs[0]<<8)|((uint16_t)(p)->hs[1]))
86 #define LE16(p) (((uint16_t)(p)->hs[1]<<8)|((uint16_t)(p)->hs[0]))
87 #define SEXT(s,v,p) ((s)?(intmax_t)(int##v##_t)(p):(intmax_t)(uint##v##_t)(p))
90 * softmagic - lookup one file in parsed, in-memory copy of database
91 * Passed the name and FILE * of one file to be typed.
93 /*ARGSUSED1*/ /* nbytes passed for regularity, maybe need later */
95 file_softmagic(struct magic_set *ms, const struct buffer *b,
96 uint16_t *indir_count, uint16_t *name_count, int mode, int text)
99 int rv, printed_something = 0, need_separator = 0;
102 if (name_count == NULL) {
106 if (indir_count == NULL) {
111 for (ml = ms->mlist[0]->next; ml != ms->mlist[0]; ml = ml->next)
112 if ((rv = match(ms, ml->magic, ml->nmagic, b, 0, mode,
113 text, 0, indir_count, name_count,
114 &printed_something, &need_separator, NULL)) != 0)
120 #define FILE_FMTDEBUG
122 #define F(a, b, c) file_fmtcheck((a), (b), (c), __FILE__, __LINE__)
124 private const char * __attribute__((__format_arg__(3)))
125 file_fmtcheck(struct magic_set *ms, const char *desc, const char *def,
126 const char *file, size_t line)
128 const char *ptr = fmtcheck(desc, def);
131 "%s, %" SIZE_T_FORMAT "u: format `%s' does not match"
132 " with `%s'", file, line, desc, def);
136 #define F(a, b, c) fmtcheck((b), (c))
140 * Go through the whole list, stopping if you find a match. Process all
141 * the continuations of that match before returning.
143 * We support multi-level continuations:
145 * At any time when processing a successful top-level match, there is a
146 * current continuation level; it represents the level of the last
147 * successfully matched continuation.
149 * Continuations above that level are skipped as, if we see one, it
150 * means that the continuation that controls them - i.e, the
151 * lower-level continuation preceding them - failed to match.
153 * Continuations below that level are processed as, if we see one,
154 * it means we've finished processing or skipping higher-level
155 * continuations under the control of a successful or unsuccessful
156 * lower-level continuation, and are now seeing the next lower-level
157 * continuation and should process it. The current continuation
158 * level reverts to the level of the one we're seeing.
160 * Continuations at the current level are processed as, if we see
161 * one, there's no lower-level continuation that may have failed.
163 * If a continuation matches, we bump the current continuation level
164 * so that higher-level continuations are processed.
167 match(struct magic_set *ms, struct magic *magic, uint32_t nmagic,
168 const struct buffer *b, size_t offset, int mode, int text,
169 int flip, uint16_t *indir_count, uint16_t *name_count,
170 int *printed_something, int *need_separator, int *returnval)
172 uint32_t magindex = 0;
173 unsigned int cont_level = 0;
174 int returnvalv = 0, e; /* if a match is found it is set to 1*/
175 int firstline = 1; /* a flag to print X\n X\n- X */
177 int print = (ms->flags & MAGIC_NODESC) == 0;
179 if (returnval == NULL)
180 returnval = &returnvalv;
182 if (file_check_mem(ms, cont_level) == -1)
185 for (magindex = 0; magindex < nmagic; magindex++) {
187 struct magic *m = &magic[magindex];
189 if (m->type != FILE_NAME)
190 if ((IS_STRING(m->type) &&
191 #define FLT (STRING_BINTEST | STRING_TEXTTEST)
192 ((text && (m->str_flags & FLT) == STRING_BINTEST) ||
193 (!text && (m->str_flags & FLT) == STRING_TEXTTEST))) ||
194 (m->flag & mode) != mode) {
197 while (magindex < nmagic - 1 &&
198 magic[magindex + 1].cont_level != 0)
201 continue; /* Skip to next top-level test*/
204 if (msetoffset(ms, m, &bb, b, offset, cont_level) == -1)
206 ms->line = m->lineno;
208 /* if main entry matches, print it... */
209 switch (mget(ms, m, b, bb.fbuf, bb.flen, offset, cont_level,
210 mode, text, flip, indir_count, name_count,
211 printed_something, need_separator, returnval)) {
215 flush = m->reln != '!';
218 if (m->type == FILE_INDIRECT)
221 switch (magiccheck(ms, m)) {
235 * main entry didn't match,
236 * flush its continuations
241 if ((e = handle_annotation(ms, m, firstline)) != 0) {
243 *printed_something = 1;
249 * If we are going to print something, we'll need to print
250 * a blank before we print something else.
254 *printed_something = 1;
255 if (print_sep(ms, firstline) == -1)
259 if (print && mprint(ms, m) == -1)
262 switch (moffset(ms, m, &bb, &ms->c.li[cont_level].off)) {
270 /* and any continuations that match */
271 if (file_check_mem(ms, ++cont_level) == -1)
274 while (magindex + 1 < nmagic &&
275 magic[magindex + 1].cont_level != 0) {
276 m = &magic[++magindex];
277 ms->line = m->lineno; /* for messages */
279 if (cont_level < m->cont_level)
281 if (cont_level > m->cont_level) {
283 * We're at the end of the level
284 * "cont_level" continuations.
286 cont_level = m->cont_level;
288 if (msetoffset(ms, m, &bb, b, offset, cont_level) == -1)
290 if (m->flag & OFFADD) {
292 ms->c.li[cont_level - 1].off;
295 #ifdef ENABLE_CONDITIONALS
296 if (m->cond == COND_ELSE ||
297 m->cond == COND_ELIF) {
298 if (ms->c.li[cont_level].last_match == 1)
302 switch (mget(ms, m, b, bb.fbuf, bb.flen, offset,
303 cont_level, mode, text, flip, indir_count,
304 name_count, printed_something, need_separator,
314 if (m->type == FILE_INDIRECT)
320 switch (flush ? 1 : magiccheck(ms, m)) {
324 #ifdef ENABLE_CONDITIONALS
325 ms->c.li[cont_level].last_match = 0;
329 #ifdef ENABLE_CONDITIONALS
330 ms->c.li[cont_level].last_match = 1;
332 if (m->type == FILE_CLEAR)
333 ms->c.li[cont_level].got_match = 0;
334 else if (ms->c.li[cont_level].got_match) {
335 if (m->type == FILE_DEFAULT)
338 ms->c.li[cont_level].got_match = 1;
340 if ((e = handle_annotation(ms, m, firstline))
343 *printed_something = 1;
348 * If we are going to print something,
349 * make sure that we have a separator first.
352 if (!*printed_something) {
353 *printed_something = 1;
354 if (print_sep(ms, firstline)
360 * This continuation matched. Print
361 * its message, with a blank before it
362 * if the previous item printed and
363 * this item isn't empty.
365 /* space if previous printed */
367 && ((m->flag & NOSPACE) == 0)
370 file_printf(ms, " ") == -1)
374 if (print && mprint(ms, m) == -1)
377 switch (moffset(ms, m, &bb,
378 &ms->c.li[cont_level].off)) {
392 * If we see any continuations
396 if (file_check_mem(ms, ++cont_level) == -1)
401 if (*printed_something) {
406 if ((ms->flags & MAGIC_CONTINUE) == 0 && *printed_something) {
407 return *returnval; /* don't keep searching */
411 return *returnval; /* This is hit if -k is set or there is no match */
415 check_fmt(struct magic_set *ms, const char *fmt)
420 if (strchr(fmt, '%') == NULL)
423 rc = file_regcomp(&rx, "%[-0-9\\.]*s", REG_EXTENDED|REG_NOSUB);
425 file_regerror(&rx, rc, ms);
427 rc = file_regexec(&rx, fmt, 0, 0, 0);
434 #if !defined(HAVE_STRNDUP) || defined(__aiws__)
436 # define strndup aix_strndup /* aix is broken */
438 char *strndup(const char *, size_t);
441 strndup(const char *str, size_t n)
446 for (len = 0; len < n && str[len]; len++)
448 if ((copy = malloc(len + 1)) == NULL)
450 (void)memcpy(copy, str, len);
454 #endif /* HAVE_STRNDUP */
457 varexpand(struct magic_set *ms, char *buf, size_t len, const char *str)
459 const char *ptr, *sptr, *e, *t, *ee, *et;
462 for (sptr = str; (ptr = strstr(sptr, "${")) != NULL;) {
463 l = (size_t)(ptr - sptr);
466 memcpy(buf, sptr, l);
470 if (!*ptr || ptr[1] != '?')
472 for (et = t = ptr + 2; *et && *et != ':'; et++)
476 for (ee = e = et + 1; *ee && *ee != '}'; ee++)
482 if (ms->mode & 0111) {
505 memcpy(buf, sptr, l);
512 mprint(struct magic_set *ms, struct magic *m)
518 char buf[128], tbuf[26], sbuf[512], ebuf[512];
520 union VALUETYPE *p = &ms->ms_value;
522 if (varexpand(ms, ebuf, sizeof(ebuf), m->desc) == -1)
529 v = file_signextend(ms, m, (uint64_t)p->b);
530 switch (check_fmt(ms, desc)) {
534 (void)snprintf(buf, sizeof(buf), "%d",
536 if (file_printf(ms, F(ms, desc, "%s"), buf) == -1)
540 if (file_printf(ms, F(ms, desc, "%d"),
541 (unsigned char) v) == -1)
545 t = ms->offset + sizeof(char);
551 v = file_signextend(ms, m, (uint64_t)p->h);
552 switch (check_fmt(ms, desc)) {
556 (void)snprintf(buf, sizeof(buf), "%u",
558 if (file_printf(ms, F(ms, desc, "%s"), buf) == -1)
562 if (file_printf(ms, F(ms, desc, "%u"),
563 (unsigned short) v) == -1)
567 t = ms->offset + sizeof(short);
574 v = file_signextend(ms, m, (uint64_t)p->l);
575 switch (check_fmt(ms, desc)) {
579 (void)snprintf(buf, sizeof(buf), "%u", (uint32_t) v);
580 if (file_printf(ms, F(ms, desc, "%s"), buf) == -1)
584 if (file_printf(ms, F(ms, desc, "%u"), (uint32_t) v) == -1)
588 t = ms->offset + sizeof(int32_t);
594 v = file_signextend(ms, m, p->q);
595 switch (check_fmt(ms, desc)) {
599 (void)snprintf(buf, sizeof(buf), "%" INT64_T_FORMAT "u",
600 (unsigned long long)v);
601 if (file_printf(ms, F(ms, desc, "%s"), buf) == -1)
605 if (file_printf(ms, F(ms, desc, "%" INT64_T_FORMAT "u"),
606 (unsigned long long) v) == -1)
610 t = ms->offset + sizeof(int64_t);
615 case FILE_BESTRING16:
616 case FILE_LESTRING16:
617 if (m->reln == '=' || m->reln == '!') {
618 if (file_printf(ms, F(ms, desc, "%s"),
619 file_printable(sbuf, sizeof(sbuf), m->value.s))
622 t = ms->offset + m->vallen;
627 /* compute t before we mangle the string? */
628 t = ms->offset + strlen(str);
630 if (*m->value.s == '\0')
631 str[strcspn(str, "\r\n")] = '\0';
633 if (m->str_flags & STRING_TRIM) {
635 while (isspace((unsigned char)*str))
641 while (isspace((unsigned char)*last))
646 if (file_printf(ms, F(ms, desc, "%s"),
647 file_printable(sbuf, sizeof(sbuf), str)) == -1)
650 if (m->type == FILE_PSTRING)
651 t += file_pstring_length_size(m);
659 if (file_printf(ms, F(ms, desc, "%s"),
660 file_fmttime(p->l, 0, tbuf)) == -1)
662 t = ms->offset + sizeof(uint32_t);
669 if (file_printf(ms, F(ms, desc, "%s"),
670 file_fmttime(p->l, FILE_T_LOCAL, tbuf)) == -1)
672 t = ms->offset + sizeof(uint32_t);
678 if (file_printf(ms, F(ms, desc, "%s"),
679 file_fmttime(p->q, 0, tbuf)) == -1)
681 t = ms->offset + sizeof(uint64_t);
687 if (file_printf(ms, F(ms, desc, "%s"),
688 file_fmttime(p->q, FILE_T_LOCAL, tbuf)) == -1)
690 t = ms->offset + sizeof(uint64_t);
696 if (file_printf(ms, F(ms, desc, "%s"),
697 file_fmttime(p->q, FILE_T_WINDOWS, tbuf)) == -1)
699 t = ms->offset + sizeof(uint64_t);
706 switch (check_fmt(ms, desc)) {
710 (void)snprintf(buf, sizeof(buf), "%g", vf);
711 if (file_printf(ms, F(ms, desc, "%s"), buf) == -1)
715 if (file_printf(ms, F(ms, desc, "%g"), vf) == -1)
719 t = ms->offset + sizeof(float);
726 switch (check_fmt(ms, desc)) {
730 (void)snprintf(buf, sizeof(buf), "%g", vd);
731 if (file_printf(ms, F(ms, desc, "%s"), buf) == -1)
735 if (file_printf(ms, F(ms, desc, "%g"), vd) == -1)
739 t = ms->offset + sizeof(double);
747 cp = strndup((const char *)ms->search.s, ms->search.rm_len);
749 file_oomem(ms, ms->search.rm_len);
752 rval = file_printf(ms, F(ms, desc, "%s"),
753 file_printable(sbuf, sizeof(sbuf), cp));
759 if ((m->str_flags & REGEX_OFFSET_START))
760 t = ms->search.offset;
762 t = ms->search.offset + ms->search.rm_len;
768 if (file_printf(ms, "%s", m->desc) == -1)
779 if (file_printf(ms, F(ms, desc, "%s"),
780 file_printable(sbuf, sizeof(sbuf), ms->ms_value.s)) == -1)
785 file_magerror(ms, "invalid m->type (%d) in mprint()", m->type);
792 moffset(struct magic_set *ms, struct magic *m, const struct buffer *b,
795 size_t nbytes = b->flen;
800 o = CAST(int32_t, (ms->offset + sizeof(char)));
806 o = CAST(int32_t, (ms->offset + sizeof(short)));
813 o = CAST(int32_t, (ms->offset + sizeof(int32_t)));
819 o = CAST(int32_t, (ms->offset + sizeof(int64_t)));
824 case FILE_BESTRING16:
825 case FILE_LESTRING16:
826 if (m->reln == '=' || m->reln == '!') {
827 o = ms->offset + m->vallen;
829 union VALUETYPE *p = &ms->ms_value;
831 if (*m->value.s == '\0')
832 p->s[strcspn(p->s, "\r\n")] = '\0';
833 o = CAST(uint32_t, (ms->offset + strlen(p->s)));
834 if (m->type == FILE_PSTRING)
835 o += (uint32_t)file_pstring_length_size(m);
843 o = CAST(int32_t, (ms->offset + sizeof(uint32_t)));
850 o = CAST(int32_t, (ms->offset + sizeof(uint32_t)));
856 o = CAST(int32_t, (ms->offset + sizeof(uint64_t)));
862 o = CAST(int32_t, (ms->offset + sizeof(uint64_t)));
868 o = CAST(int32_t, (ms->offset + sizeof(float)));
874 o = CAST(int32_t, (ms->offset + sizeof(double)));
878 if ((m->str_flags & REGEX_OFFSET_START) != 0)
879 o = CAST(int32_t, ms->search.offset);
882 (ms->search.offset + ms->search.rm_len));
886 if ((m->str_flags & REGEX_OFFSET_START) != 0)
887 o = CAST(int32_t, ms->search.offset);
889 o = CAST(int32_t, (ms->search.offset + m->vallen));
900 o = der_offs(ms, m, nbytes);
901 if (o == -1 || (size_t)o > nbytes) {
902 if ((ms->flags & MAGIC_DEBUG) != 0) {
903 (void)fprintf(stderr,
904 "Bad DER offset %d nbytes=%zu",
918 if ((size_t)o > nbytes) {
920 file_error(ms, 0, "Offset out of range %zu > %zu",
930 cvt_id3(struct magic_set *ms, uint32_t v)
932 v = ((((v >> 0) & 0x7f) << 0) |
933 (((v >> 8) & 0x7f) << 7) |
934 (((v >> 16) & 0x7f) << 14) |
935 (((v >> 24) & 0x7f) << 21));
936 if ((ms->flags & MAGIC_DEBUG) != 0)
937 fprintf(stderr, "id3 offs=%u\n", v);
942 cvt_flip(int type, int flip)
960 return FILE_LEQLDATE;
962 return FILE_LEQWDATE;
976 return FILE_BEQLDATE;
978 return FILE_BEQWDATE;
984 return FILE_LEDOUBLE;
986 return FILE_BEDOUBLE;
991 #define DO_CVT(fld, cast) \
993 switch (m->mask_op & FILE_OPS_MASK) { \
995 p->fld &= cast m->num_mask; \
998 p->fld |= cast m->num_mask; \
1001 p->fld ^= cast m->num_mask; \
1004 p->fld += cast m->num_mask; \
1006 case FILE_OPMINUS: \
1007 p->fld -= cast m->num_mask; \
1009 case FILE_OPMULTIPLY: \
1010 p->fld *= cast m->num_mask; \
1012 case FILE_OPDIVIDE: \
1013 if (cast m->num_mask == 0) \
1015 p->fld /= cast m->num_mask; \
1017 case FILE_OPMODULO: \
1018 if (cast m->num_mask == 0) \
1020 p->fld %= cast m->num_mask; \
1023 if (m->mask_op & FILE_OPINVERSE) \
1027 cvt_8(union VALUETYPE *p, const struct magic *m)
1029 DO_CVT(b, (uint8_t));
1034 cvt_16(union VALUETYPE *p, const struct magic *m)
1036 DO_CVT(h, (uint16_t));
1041 cvt_32(union VALUETYPE *p, const struct magic *m)
1043 DO_CVT(l, (uint32_t));
1048 cvt_64(union VALUETYPE *p, const struct magic *m)
1050 DO_CVT(q, (uint64_t));
1054 #define DO_CVT2(fld, cast) \
1056 switch (m->mask_op & FILE_OPS_MASK) { \
1058 p->fld += cast m->num_mask; \
1060 case FILE_OPMINUS: \
1061 p->fld -= cast m->num_mask; \
1063 case FILE_OPMULTIPLY: \
1064 p->fld *= cast m->num_mask; \
1066 case FILE_OPDIVIDE: \
1067 if (cast m->num_mask == 0) \
1069 p->fld /= cast m->num_mask; \
1074 cvt_float(union VALUETYPE *p, const struct magic *m)
1076 DO_CVT2(f, (float));
1081 cvt_double(union VALUETYPE *p, const struct magic *m)
1083 DO_CVT2(d, (double));
1088 * Convert the byte order of the data we are looking at
1089 * While we're here, let's apply the mask operation
1090 * (unless you have a better idea)
1093 mconvert(struct magic_set *ms, struct magic *m, int flip)
1095 union VALUETYPE *p = &ms->ms_value;
1097 switch (cvt_flip(m->type, flip)) {
1099 if (cvt_8(p, m) == -1)
1103 if (cvt_16(p, m) == -1)
1109 if (cvt_32(p, m) == -1)
1116 if (cvt_64(p, m) == -1)
1120 case FILE_BESTRING16:
1121 case FILE_LESTRING16: {
1122 /* Null terminate and eat *trailing* return */
1123 p->s[sizeof(p->s) - 1] = '\0';
1126 case FILE_PSTRING: {
1127 size_t sz = file_pstring_length_size(m);
1128 char *ptr1 = p->s, *ptr2 = ptr1 + sz;
1129 size_t len = file_pstring_get_length(m, ptr1);
1130 sz = sizeof(p->s) - sz; /* maximum length of string */
1133 * The size of the pascal string length (sz)
1134 * is 1, 2, or 4. We need at least 1 byte for NUL
1135 * termination, but we've already truncated the
1136 * string by p->s, so we need to deduct sz.
1137 * Because we can use one of the bytes of the length
1138 * after we shifted as NUL termination.
1148 p->h = (short)BE16(p);
1149 if (cvt_16(p, m) == -1)
1155 p->l = (int32_t)BE32(p);
1156 if (cvt_32(p, m) == -1)
1163 p->q = (uint64_t)BE64(p);
1164 if (cvt_64(p, m) == -1)
1168 p->h = (short)LE16(p);
1169 if (cvt_16(p, m) == -1)
1175 p->l = (int32_t)LE32(p);
1176 if (cvt_32(p, m) == -1)
1183 p->q = (uint64_t)LE64(p);
1184 if (cvt_64(p, m) == -1)
1190 p->l = (int32_t)ME32(p);
1191 if (cvt_32(p, m) == -1)
1195 if (cvt_float(p, m) == -1)
1200 if (cvt_float(p, m) == -1)
1205 if (cvt_float(p, m) == -1)
1209 if (cvt_double(p, m) == -1)
1214 if (cvt_double(p, m) == -1)
1219 if (cvt_double(p, m) == -1)
1231 file_magerror(ms, "invalid type %d in mconvert()", m->type);
1235 file_magerror(ms, "zerodivide in mconvert()");
1241 mdebug(uint32_t offset, const char *str, size_t len)
1243 (void) fprintf(stderr, "mget/%" SIZE_T_FORMAT "u @%d: ", len, offset);
1244 file_showstr(stderr, str, len);
1245 (void) fputc('\n', stderr);
1246 (void) fputc('\n', stderr);
1250 mcopy(struct magic_set *ms, union VALUETYPE *p, int type, int indir,
1251 const unsigned char *s, uint32_t offset, size_t nbytes, struct magic *m)
1254 * Note: FILE_SEARCH and FILE_REGEX do not actually copy
1255 * anything, but setup pointers into the source
1261 if (offset > nbytes)
1262 offset = CAST(uint32_t, nbytes);
1263 ms->search.s = RCAST(const char *, s) + offset;
1264 ms->search.s_len = nbytes - offset;
1265 ms->search.offset = offset;
1271 const char *last; /* end of search region */
1272 const char *buf; /* start of search region */
1274 size_t lines, linecnt, bytecnt;
1276 if (s == NULL || nbytes < offset) {
1277 ms->search.s_len = 0;
1278 ms->search.s = NULL;
1282 if (m->str_flags & REGEX_LINE_COUNT) {
1283 linecnt = m->str_range;
1284 bytecnt = linecnt * 80;
1287 bytecnt = m->str_range;
1290 if (bytecnt == 0 || bytecnt > nbytes - offset)
1291 bytecnt = nbytes - offset;
1292 if (bytecnt > ms->regex_max)
1293 bytecnt = ms->regex_max;
1295 buf = RCAST(const char *, s) + offset;
1296 end = last = RCAST(const char *, s) + bytecnt + offset;
1297 /* mget() guarantees buf <= last */
1298 for (lines = linecnt, b = buf; lines && b < end &&
1299 ((b = CAST(const char *,
1300 memchr(c = b, '\n', CAST(size_t, (end - b)))))
1301 || (b = CAST(const char *,
1302 memchr(c, '\r', CAST(size_t, (end - c))))));
1305 if (b < end - 1 && b[0] == '\r' && b[1] == '\n')
1312 ms->search.s_len = last - buf;
1313 ms->search.offset = offset;
1314 ms->search.rm_len = 0;
1317 case FILE_BESTRING16:
1318 case FILE_LESTRING16: {
1319 const unsigned char *src = s + offset;
1320 const unsigned char *esrc = s + nbytes;
1322 char *edst = &p->s[sizeof(p->s) - 1];
1324 if (type == FILE_BESTRING16)
1327 /* check that offset is within range */
1328 if (offset >= nbytes)
1330 for (/*EMPTY*/; src < esrc; src += 2, dst++) {
1336 if (type == FILE_BESTRING16 ?
1337 *(src - 1) != '\0' :
1338 ((src + 1 < esrc) &&
1339 *(src + 1) != '\0'))
1346 case FILE_STRING: /* XXX - these two should not need */
1347 case FILE_PSTRING: /* to copy anything, but do anyway. */
1353 if (offset >= nbytes) {
1354 (void)memset(p, '\0', sizeof(*p));
1357 if (nbytes - offset < sizeof(*p))
1358 nbytes = nbytes - offset;
1360 nbytes = sizeof(*p);
1362 (void)memcpy(p, s + offset, nbytes);
1365 * the usefulness of padding with zeroes eludes me, it
1366 * might even cause problems
1368 if (nbytes < sizeof(*p))
1369 (void)memset(((char *)(void *)p) + nbytes, '\0',
1370 sizeof(*p) - nbytes);
1375 do_ops(struct magic *m, intmax_t lhs, intmax_t off)
1379 switch (m->in_op & FILE_OPS_MASK) {
1395 case FILE_OPMULTIPLY:
1407 if (m->in_op & FILE_OPINVERSE)
1410 return (uint32_t)offset;
1414 msetoffset(struct magic_set *ms, struct magic *m, struct buffer *bb,
1415 const struct buffer *b, size_t o, unsigned int cont_level)
1417 if (m->offset < 0) {
1418 if (cont_level > 0) {
1419 if (m->flag & (OFFADD|INDIROFFADD))
1422 file_error(ms, 0, "negative offset %d at continuation"
1423 "level %u", m->offset, cont_level);
1427 if (buffer_fill(b) == -1)
1431 file_magerror(ms, "non zero offset %zu at"
1432 " level %u", o, cont_level);
1435 if ((size_t)-m->offset > b->elen)
1437 buffer_init(bb, -1, b->ebuf, b->elen);
1438 ms->eoffset = ms->offset = b->elen + m->offset;
1440 if (cont_level == 0) {
1442 // XXX: Pass real fd, then who frees bb?
1443 buffer_init(bb, -1, b->fbuf, b->flen);
1444 ms->offset = m->offset;
1447 ms->offset = ms->eoffset + m->offset;
1450 if ((ms->flags & MAGIC_DEBUG) != 0) {
1451 fprintf(stderr, "bb=[%p,%zu], %d [b=%p,%zu], [o=%#x, c=%d]\n",
1452 bb->fbuf, bb->flen, ms->offset, b->fbuf, b->flen,
1453 m->offset, cont_level);
1459 mget(struct magic_set *ms, struct magic *m, const struct buffer *b,
1460 const unsigned char *s, size_t nbytes, size_t o, unsigned int cont_level,
1461 int mode, int text, int flip, uint16_t *indir_count, uint16_t *name_count,
1462 int *printed_something, int *need_separator, int *returnval)
1464 uint32_t offset = ms->offset;
1468 int rv, oneed_separator, in_type;
1470 union VALUETYPE *p = &ms->ms_value;
1473 if (*indir_count >= ms->indir_max) {
1474 file_error(ms, 0, "indirect count (%hu) exceeded",
1479 if (*name_count >= ms->name_max) {
1480 file_error(ms, 0, "name use count (%hu) exceeded",
1487 if (mcopy(ms, p, m->type, m->flag & INDIR, s, (uint32_t)(offset + o),
1488 (uint32_t)nbytes, m) == -1)
1491 if ((ms->flags & MAGIC_DEBUG) != 0) {
1492 fprintf(stderr, "mget(type=%d, flag=%#x, offset=%u, o=%"
1493 SIZE_T_FORMAT "u, " "nbytes=%" SIZE_T_FORMAT
1494 "u, il=%hu, nc=%hu)\n",
1495 m->type, m->flag, offset, o, nbytes,
1496 *indir_count, *name_count);
1497 mdebug(offset, (char *)(void *)p, sizeof(union VALUETYPE));
1498 #ifndef COMPILE_ONLY
1503 if (m->flag & INDIR) {
1504 intmax_t off = m->in_offset;
1505 const int sgn = m->in_op & FILE_OPSIGNED;
1506 if (m->in_op & FILE_OPINDIRECT) {
1507 const union VALUETYPE *q = CAST(const union VALUETYPE *,
1508 ((const void *)(s + offset + off)));
1509 if (OFFSET_OOB(nbytes, offset + off, sizeof(*q)))
1511 switch (cvt_flip(m->in_type, flip)) {
1513 off = SEXT(sgn,8,q->b);
1516 off = SEXT(sgn,16,q->h);
1519 off = SEXT(sgn,16,BE16(q));
1522 off = SEXT(sgn,16,LE16(q));
1525 off = SEXT(sgn,32,q->l);
1529 off = SEXT(sgn,32,BE32(q));
1533 off = SEXT(sgn,32,LE32(q));
1536 off = SEXT(sgn,32,ME32(q));
1539 off = SEXT(sgn,64,BE64(q));
1542 off = SEXT(sgn,64,LE64(q));
1547 if ((ms->flags & MAGIC_DEBUG) != 0)
1548 fprintf(stderr, "indirect offs=%jd\n", off);
1550 switch (in_type = cvt_flip(m->in_type, flip)) {
1552 if (OFFSET_OOB(nbytes, offset, 1))
1554 offset = do_ops(m, SEXT(sgn,8,p->b), off);
1557 if (OFFSET_OOB(nbytes, offset, 2))
1559 offset = do_ops(m, SEXT(sgn,16,BE16(p)), off);
1562 if (OFFSET_OOB(nbytes, offset, 2))
1564 offset = do_ops(m, SEXT(sgn,16,LE16(p)), off);
1567 if (OFFSET_OOB(nbytes, offset, 2))
1569 offset = do_ops(m, SEXT(sgn,16,p->h), off);
1573 if (OFFSET_OOB(nbytes, offset, 4))
1576 if (in_type == FILE_BEID3)
1577 lhs = cvt_id3(ms, (uint32_t)lhs);
1578 offset = do_ops(m, SEXT(sgn,32,lhs), off);
1582 if (OFFSET_OOB(nbytes, offset, 4))
1585 if (in_type == FILE_LEID3)
1586 lhs = cvt_id3(ms, (uint32_t)lhs);
1587 offset = do_ops(m, SEXT(sgn,32,lhs), off);
1590 if (OFFSET_OOB(nbytes, offset, 4))
1592 offset = do_ops(m, SEXT(sgn,32,ME32(p)), off);
1595 if (OFFSET_OOB(nbytes, offset, 4))
1597 offset = do_ops(m, SEXT(sgn,32,p->l), off);
1600 if (OFFSET_OOB(nbytes, offset, 8))
1602 offset = do_ops(m, SEXT(sgn,64,LE64(p)), off);
1605 if (OFFSET_OOB(nbytes, offset, 8))
1607 offset = do_ops(m, SEXT(sgn,64,BE64(p)), off);
1613 if (m->flag & INDIROFFADD) {
1614 offset += ms->c.li[cont_level-1].off;
1616 if ((ms->flags & MAGIC_DEBUG) != 0)
1618 "indirect *zero* offset\n");
1621 if ((ms->flags & MAGIC_DEBUG) != 0)
1622 fprintf(stderr, "indirect +offs=%u\n", offset);
1624 if (mcopy(ms, p, m->type, 0, s, offset, nbytes, m) == -1)
1626 ms->offset = offset;
1628 if ((ms->flags & MAGIC_DEBUG) != 0) {
1629 mdebug(offset, (char *)(void *)p,
1630 sizeof(union VALUETYPE));
1631 #ifndef COMPILE_ONLY
1637 /* Verify we have enough data to match magic type */
1640 if (OFFSET_OOB(nbytes, offset, 1))
1647 if (OFFSET_OOB(nbytes, offset, 2))
1666 if (OFFSET_OOB(nbytes, offset, 4))
1673 if (OFFSET_OOB(nbytes, offset, 8))
1680 if (OFFSET_OOB(nbytes, offset, m->vallen))
1685 if (nbytes < offset)
1690 if (m->str_flags & INDIRECT_RELATIVE)
1691 offset += CAST(uint32_t, o);
1695 if (nbytes < offset)
1698 if ((pb = file_push_buffer(ms)) == NULL)
1703 bb.fbuf = s + offset;
1704 bb.flen = nbytes - offset;
1705 rv = file_softmagic(ms, &bb,
1706 indir_count, name_count, BINTEST, text);
1708 if ((ms->flags & MAGIC_DEBUG) != 0)
1709 fprintf(stderr, "indirect @offs=%u[%d]\n", offset, rv);
1711 rbuf = file_pop_buffer(ms, pb);
1712 if (rbuf == NULL && ms->event_flags & EVENT_HAD_ERR)
1716 if ((ms->flags & MAGIC_NODESC) == 0 &&
1717 file_printf(ms, F(ms, m->desc, "%u"), offset) == -1) {
1721 if (file_printf(ms, "%s", rbuf) == -1) {
1730 if (nbytes < offset)
1737 if (file_magicfind(ms, rbuf, &ml) == -1) {
1738 file_error(ms, 0, "cannot find entry `%s'", rbuf);
1742 oneed_separator = *need_separator;
1743 if (m->flag & NOSPACE)
1744 *need_separator = 0;
1745 rv = match(ms, ml.magic, ml.nmagic, b, offset + o,
1746 mode, text, flip, indir_count, name_count,
1747 printed_something, need_separator, returnval);
1749 *need_separator = oneed_separator;
1753 if (ms->flags & MAGIC_NODESC)
1755 if (file_printf(ms, "%s", m->desc) == -1)
1759 case FILE_DEFAULT: /* nothing to check */
1764 if (!mconvert(ms, m, flip))
1770 file_strncmp(const char *s1, const char *s2, size_t len, uint32_t flags)
1773 * Convert the source args to unsigned here so that (1) the
1774 * compare will be unsigned as it is in strncmp() and (2) so
1775 * the ctype functions will work correctly without extra
1778 const unsigned char *a = (const unsigned char *)s1;
1779 const unsigned char *b = (const unsigned char *)s2;
1780 const unsigned char *eb = b + len;
1784 * What we want here is v = strncmp(s1, s2, len),
1785 * but ignoring any nulls.
1788 if (0L == flags) { /* normal string: do it fast */
1790 if ((v = *b++ - *a++) != '\0')
1793 else { /* combine the others */
1799 if ((flags & STRING_IGNORE_LOWERCASE) &&
1801 if ((v = tolower(*b++) - *a++) != '\0')
1804 else if ((flags & STRING_IGNORE_UPPERCASE) &&
1806 if ((v = toupper(*b++) - *a++) != '\0')
1809 else if ((flags & STRING_COMPACT_WHITESPACE) &&
1812 if (isspace(*b++)) {
1814 while (b < eb && isspace(*b))
1822 else if ((flags & STRING_COMPACT_OPTIONAL_WHITESPACE) &&
1825 while (b < eb && isspace(*b))
1829 if ((v = *b++ - *a++) != '\0')
1838 file_strncmp16(const char *a, const char *b, size_t len, uint32_t flags)
1841 * XXX - The 16-bit string compare probably needs to be done
1842 * differently, especially if the flags are to be supported.
1843 * At the moment, I am unsure.
1846 return file_strncmp(a, b, len, flags);
1850 magiccheck(struct magic_set *ms, struct magic *m)
1852 uint64_t l = m->value.q;
1857 union VALUETYPE *p = &ms->ms_value;
1927 file_magerror(ms, "cannot happen with float: invalid relation `%c'",
1960 file_magerror(ms, "cannot happen with double: invalid relation `%c'", m->reln);
1974 v = file_strncmp(m->value.s, p->s, (size_t)m->vallen, m->str_flags);
1977 case FILE_BESTRING16:
1978 case FILE_LESTRING16:
1980 v = file_strncmp16(m->value.s, p->s, (size_t)m->vallen, m->str_flags);
1983 case FILE_SEARCH: { /* search ms->search.s for the string m->value.s */
1987 if (ms->search.s == NULL)
1990 slen = MIN(m->vallen, sizeof(m->value.s));
1994 for (idx = 0; m->str_range == 0 || idx < m->str_range; idx++) {
1995 if (slen + idx > ms->search.s_len)
1998 v = file_strncmp(m->value.s, ms->search.s + idx, slen,
2000 if (v == 0) { /* found match */
2001 ms->search.offset += idx;
2002 ms->search.rm_len = ms->search.s_len - idx;
2013 if (ms->search.s == NULL)
2017 rc = file_regcomp(&rx, m->value.s,
2018 REG_EXTENDED|REG_NEWLINE|
2019 ((m->str_flags & STRING_IGNORE_CASE) ? REG_ICASE : 0));
2021 file_regerror(&rx, rc, ms);
2025 size_t slen = ms->search.s_len;
2028 copy = CAST(char *, malloc(slen));
2031 file_error(ms, errno,
2032 "can't allocate %" SIZE_T_FORMAT "u bytes",
2036 memcpy(copy, ms->search.s, slen);
2037 copy[--slen] = '\0';
2040 search = CCAST(char *, "");
2043 rc = file_regexec(&rx, (const char *)search,
2048 ms->search.s += (int)pmatch.rm_so;
2049 ms->search.offset += (size_t)pmatch.rm_so;
2051 (size_t)(pmatch.rm_eo - pmatch.rm_so);
2060 file_regerror(&rx, rc, ms);
2066 if (v == (uint64_t)-1)
2075 matched = der_cmp(ms, m);
2076 if (matched == -1) {
2077 if ((ms->flags & MAGIC_DEBUG) != 0) {
2078 (void) fprintf(stderr,
2079 "EOF comparing DER entries");
2085 file_magerror(ms, "invalid type %d in magiccheck()", m->type);
2089 v = file_signextend(ms, m, v);
2093 if ((ms->flags & MAGIC_DEBUG) != 0)
2094 (void) fprintf(stderr, "%" INT64_T_FORMAT
2095 "u == *any* = 1\n", (unsigned long long)v);
2101 if ((ms->flags & MAGIC_DEBUG) != 0)
2102 (void) fprintf(stderr, "%" INT64_T_FORMAT "u != %"
2103 INT64_T_FORMAT "u = %d\n", (unsigned long long)v,
2104 (unsigned long long)l, matched);
2109 if ((ms->flags & MAGIC_DEBUG) != 0)
2110 (void) fprintf(stderr, "%" INT64_T_FORMAT "u == %"
2111 INT64_T_FORMAT "u = %d\n", (unsigned long long)v,
2112 (unsigned long long)l, matched);
2116 if (m->flag & UNSIGNED) {
2118 if ((ms->flags & MAGIC_DEBUG) != 0)
2119 (void) fprintf(stderr, "%" INT64_T_FORMAT
2120 "u > %" INT64_T_FORMAT "u = %d\n",
2121 (unsigned long long)v,
2122 (unsigned long long)l, matched);
2125 matched = (int64_t) v > (int64_t) l;
2126 if ((ms->flags & MAGIC_DEBUG) != 0)
2127 (void) fprintf(stderr, "%" INT64_T_FORMAT
2128 "d > %" INT64_T_FORMAT "d = %d\n",
2129 (long long)v, (long long)l, matched);
2134 if (m->flag & UNSIGNED) {
2136 if ((ms->flags & MAGIC_DEBUG) != 0)
2137 (void) fprintf(stderr, "%" INT64_T_FORMAT
2138 "u < %" INT64_T_FORMAT "u = %d\n",
2139 (unsigned long long)v,
2140 (unsigned long long)l, matched);
2143 matched = (int64_t) v < (int64_t) l;
2144 if ((ms->flags & MAGIC_DEBUG) != 0)
2145 (void) fprintf(stderr, "%" INT64_T_FORMAT
2146 "d < %" INT64_T_FORMAT "d = %d\n",
2147 (long long)v, (long long)l, matched);
2152 matched = (v & l) == l;
2153 if ((ms->flags & MAGIC_DEBUG) != 0)
2154 (void) fprintf(stderr, "((%" INT64_T_FORMAT "x & %"
2155 INT64_T_FORMAT "x) == %" INT64_T_FORMAT
2156 "x) = %d\n", (unsigned long long)v,
2157 (unsigned long long)l, (unsigned long long)l,
2162 matched = (v & l) != l;
2163 if ((ms->flags & MAGIC_DEBUG) != 0)
2164 (void) fprintf(stderr, "((%" INT64_T_FORMAT "x & %"
2165 INT64_T_FORMAT "x) != %" INT64_T_FORMAT
2166 "x) = %d\n", (unsigned long long)v,
2167 (unsigned long long)l, (unsigned long long)l,
2172 file_magerror(ms, "cannot happen: invalid relation `%c'",
2181 handle_annotation(struct magic_set *ms, struct magic *m, int firstline)
2183 if ((ms->flags & MAGIC_APPLE) && m->apple[0]) {
2184 if (!firstline && file_printf(ms, "\n- ") == -1)
2186 if (file_printf(ms, "%.8s", m->apple) == -1)
2190 if ((ms->flags & MAGIC_EXTENSION) && m->ext[0]) {
2191 if (!firstline && file_printf(ms, "\n- ") == -1)
2193 if (file_printf(ms, "%s", m->ext) == -1)
2197 if ((ms->flags & MAGIC_MIME_TYPE) && m->mimetype[0]) {
2200 if (!firstline && file_printf(ms, "\n- ") == -1)
2202 if (varexpand(ms, buf, sizeof(buf), m->mimetype) == -1)
2206 if (file_printf(ms, "%s", p) == -1)
2214 print_sep(struct magic_set *ms, int firstline)
2216 // if (ms->flags & MAGIC_NODESC)
2221 * we found another match
2222 * put a newline and '-' to do some simple formatting
2224 return file_printf(ms, "\n- ");