1 /*
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.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
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.
15 *
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
26 * SUCH DAMAGE.
27 */
28 /*
29 * softmagic - interpret variable magic from MAGIC
30 */
31
32 #include "file.h"
33
34 #ifndef lint
35 FILE_RCSID("@(#)$File: softmagic.c,v 1.259 2018/03/11 01:23:52 christos Exp $")
36 #endif /* lint */
37
38 #include "magic.h"
39 #include <assert.h>
40 #include <string.h>
41 #include <ctype.h>
42 #include <stdlib.h>
43 #include <time.h>
44 #include "der.h"
45
46 #ifndef PREG_OFFSET_CAPTURE
47 # define PREG_OFFSET_CAPTURE (1<<8)
48 #endif
49
50 private int match(struct magic_set *, struct magic *, uint32_t,
51 const struct buffer *, size_t, int, int, int, uint16_t *,
52 uint16_t *, int *, int *, int *);
53 private int mget(struct magic_set *, struct magic *, const struct buffer *,
54 const unsigned char *, size_t,
55 size_t, unsigned int, int, int, int, uint16_t *,
56 uint16_t *, int *, int *, int *);
57 private int msetoffset(struct magic_set *, struct magic *, struct buffer *,
58 const struct buffer *, size_t, unsigned int);
59 private int magiccheck(struct magic_set *, struct magic *);
60 private int32_t mprint(struct magic_set *, struct magic *,
61 const struct buffer *);
62 private int moffset(struct magic_set *, struct magic *, const struct buffer *,
63 int32_t *);
64 private void mdebug(uint32_t, const char *, size_t);
65 private int mcopy(struct magic_set *, union VALUETYPE *, int, int,
66 const unsigned char *, uint32_t, size_t, struct magic *);
67 private int mconvert(struct magic_set *, struct magic *, int);
68 private int print_sep(struct magic_set *, int);
69 private int handle_annotation(struct magic_set *, struct magic *,
70 const struct buffer *, int);
71 private int cvt_8(union VALUETYPE *, const struct magic *);
72 private int cvt_16(union VALUETYPE *, const struct magic *);
73 private int cvt_32(union VALUETYPE *, const struct magic *);
74 private int cvt_64(union VALUETYPE *, const struct magic *);
75
76 #define OFFSET_OOB(n, o, i) ((n) < (uint32_t)(o) || (i) > ((n) - (o)))
77 #define BE64(p) (((uint64_t)(p)->hq[0]<<56)|((uint64_t)(p)->hq[1]<<48)| \
78 ((uint64_t)(p)->hq[2]<<40)|((uint64_t)(p)->hq[3]<<32)| \
79 ((uint64_t)(p)->hq[4]<<24)|((uint64_t)(p)->hq[5]<<16)| \
80 ((uint64_t)(p)->hq[6]<<8)|((uint64_t)(p)->hq[7]))
81 #define LE64(p) (((uint64_t)(p)->hq[7]<<56)|((uint64_t)(p)->hq[6]<<48)| \
82 ((uint64_t)(p)->hq[5]<<40)|((uint64_t)(p)->hq[4]<<32)| \
83 ((uint64_t)(p)->hq[3]<<24)|((uint64_t)(p)->hq[2]<<16)| \
84 ((uint64_t)(p)->hq[1]<<8)|((uint64_t)(p)->hq[0]))
85 #define LE32(p) (((uint32_t)(p)->hl[3]<<24)|((uint32_t)(p)->hl[2]<<16)| \
86 ((uint32_t)(p)->hl[1]<<8)|((uint32_t)(p)->hl[0]))
87 #define BE32(p) (((uint32_t)(p)->hl[0]<<24)|((uint32_t)(p)->hl[1]<<16)| \
88 ((uint32_t)(p)->hl[2]<<8)|((uint32_t)(p)->hl[3]))
89 #define ME32(p) (((uint32_t)(p)->hl[1]<<24)|((uint32_t)(p)->hl[0]<<16)| \
90 ((uint32_t)(p)->hl[3]<<8)|((uint32_t)(p)->hl[2]))
91 #define BE16(p) (((uint16_t)(p)->hs[0]<<8)|((uint16_t)(p)->hs[1]))
92 #define LE16(p) (((uint16_t)(p)->hs[1]<<8)|((uint16_t)(p)->hs[0]))
93 #define SEXT(s,v,p) ((s)?(intmax_t)(int##v##_t)(p):(intmax_t)(uint##v##_t)(p))
94
95 /*
96 * softmagic - lookup one file in parsed, in-memory copy of database
97 * Passed the name and FILE * of one file to be typed.
98 */
99 /*ARGSUSED1*/ /* nbytes passed for regularity, maybe need later */
100 protected int
file_softmagic(struct magic_set * ms,const struct buffer * b,uint16_t * indir_count,uint16_t * name_count,int mode,int text)101 file_softmagic(struct magic_set *ms, const struct buffer *b,
102 uint16_t *indir_count, uint16_t *name_count, int mode, int text)
103 {
104 struct mlist *ml;
105 int rv, printed_something = 0, need_separator = 0;
106 uint16_t nc, ic;
107
108 if (name_count == NULL) {
109 nc = 0;
110 name_count = &nc;
111 }
112 if (indir_count == NULL) {
113 ic = 0;
114 indir_count = ⁣
115 }
116
117 for (ml = ms->mlist[0]->next; ml != ms->mlist[0]; ml = ml->next)
118 if ((rv = match(ms, ml->magic, ml->nmagic, b, 0, mode,
119 text, 0, indir_count, name_count,
120 &printed_something, &need_separator, NULL)) != 0)
121 return rv;
122
123 return 0;
124 }
125
126
127 #if defined(FILE_FMTDEBUG) && defined(HAVE_FMTCHECK)
128 #define F(a, b, c) file_fmtcheck((a), (b), (c), __FILE__, __LINE__)
129
130 private const char * __attribute__((__format_arg__(3)))
file_fmtcheck(struct magic_set * ms,const char * desc,const char * def,const char * file,size_t line)131 file_fmtcheck(struct magic_set *ms, const char *desc, const char *def,
132 const char *file, size_t line)
133 {
134 const char *ptr = fmtcheck(desc, def);
135 if (ptr == def)
136 file_magerror(ms,
137 "%s, %" SIZE_T_FORMAT "u: format `%s' does not match"
138 " with `%s'", file, line, desc, def);
139 return ptr;
140 }
141 #elif defined(HAVE_FMTCHECK)
142 #define F(a, b, c) fmtcheck((b), (c))
143 #else
144 #define F(a, b, c) ((b))
145 #endif
146
147 /*
148 * Go through the whole list, stopping if you find a match. Process all
149 * the continuations of that match before returning.
150 *
151 * We support multi-level continuations:
152 *
153 * At any time when processing a successful top-level match, there is a
154 * current continuation level; it represents the level of the last
155 * successfully matched continuation.
156 *
157 * Continuations above that level are skipped as, if we see one, it
158 * means that the continuation that controls them - i.e, the
159 * lower-level continuation preceding them - failed to match.
160 *
161 * Continuations below that level are processed as, if we see one,
162 * it means we've finished processing or skipping higher-level
163 * continuations under the control of a successful or unsuccessful
164 * lower-level continuation, and are now seeing the next lower-level
165 * continuation and should process it. The current continuation
166 * level reverts to the level of the one we're seeing.
167 *
168 * Continuations at the current level are processed as, if we see
169 * one, there's no lower-level continuation that may have failed.
170 *
171 * If a continuation matches, we bump the current continuation level
172 * so that higher-level continuations are processed.
173 */
174 private int
match(struct magic_set * ms,struct magic * magic,uint32_t nmagic,const struct buffer * b,size_t offset,int mode,int text,int flip,uint16_t * indir_count,uint16_t * name_count,int * printed_something,int * need_separator,int * returnval)175 match(struct magic_set *ms, struct magic *magic, uint32_t nmagic,
176 const struct buffer *b, size_t offset, int mode, int text,
177 int flip, uint16_t *indir_count, uint16_t *name_count,
178 int *printed_something, int *need_separator, int *returnval)
179 {
180 uint32_t magindex = 0;
181 unsigned int cont_level = 0;
182 int returnvalv = 0, e; /* if a match is found it is set to 1*/
183 int firstline = 1; /* a flag to print X\n X\n- X */
184 struct buffer bb;
185 int print = (ms->flags & MAGIC_NODESC) == 0;
186
187 if (returnval == NULL)
188 returnval = &returnvalv;
189
190 if (file_check_mem(ms, cont_level) == -1)
191 return -1;
192
193 for (magindex = 0; magindex < nmagic; magindex++) {
194 int flush = 0;
195 struct magic *m = &magic[magindex];
196
197 if (m->type != FILE_NAME)
198 if ((IS_LIBMAGIC_STRING(m->type) &&
199 #define FLT (STRING_BINTEST | STRING_TEXTTEST)
200 ((text && (m->str_flags & FLT) == STRING_BINTEST) ||
201 (!text && (m->str_flags & FLT) == STRING_TEXTTEST))) ||
202 (m->flag & mode) != mode) {
203 flush:
204 /* Skip sub-tests */
205 while (magindex < nmagic - 1 &&
206 magic[magindex + 1].cont_level != 0)
207 magindex++;
208 cont_level = 0;
209 continue; /* Skip to next top-level test*/
210 }
211
212 if (msetoffset(ms, m, &bb, b, offset, cont_level) == -1)
213 goto flush;
214 ms->line = m->lineno;
215
216 /* if main entry matches, print it... */
217 switch (mget(ms, m, b, bb.fbuf, bb.flen, offset, cont_level,
218 mode, text, flip, indir_count, name_count,
219 printed_something, need_separator, returnval)) {
220 case -1:
221 return -1;
222 case 0:
223 flush = m->reln != '!';
224 break;
225 default:
226 if (m->type == FILE_INDIRECT)
227 *returnval = 1;
228
229 switch (magiccheck(ms, m)) {
230 case -1:
231 return -1;
232 case 0:
233 flush++;
234 break;
235 default:
236 flush = 0;
237 break;
238 }
239 break;
240 }
241 if (flush) {
242 /*
243 * main entry didn't match,
244 * flush its continuations
245 */
246 goto flush;
247 }
248
249 if ((e = handle_annotation(ms, m, b, firstline)) != 0) {
250 *need_separator = 1;
251 *printed_something = 1;
252 *returnval = 1;
253 return e;
254 }
255
256 /*
257 * If we are going to print something, we'll need to print
258 * a blank before we print something else.
259 */
260 if (*m->desc) {
261 *need_separator = 1;
262 *printed_something = 1;
263 if (print_sep(ms, firstline) == -1)
264 return -1;
265 }
266
267 if (print && mprint(ms, m, b) == -1)
268 return -1;
269
270 switch (moffset(ms, m, &bb, &ms->c.li[cont_level].off)) {
271 case -1:
272 case 0:
273 goto flush;
274 default:
275 break;
276 }
277
278 /* and any continuations that match */
279 if (file_check_mem(ms, ++cont_level) == -1)
280 return -1;
281
282 while (magindex + 1 < nmagic &&
283 magic[magindex + 1].cont_level != 0) {
284 m = &magic[++magindex];
285 ms->line = m->lineno; /* for messages */
286
287 if (cont_level < m->cont_level)
288 continue;
289 if (cont_level > m->cont_level) {
290 /*
291 * We're at the end of the level
292 * "cont_level" continuations.
293 */
294 cont_level = m->cont_level;
295 }
296 if (msetoffset(ms, m, &bb, b, offset, cont_level) == -1)
297 goto flush;
298 if (m->flag & OFFADD) {
299 ms->offset +=
300 ms->c.li[cont_level - 1].off;
301 }
302
303 #ifdef ENABLE_CONDITIONALS
304 if (m->cond == COND_ELSE ||
305 m->cond == COND_ELIF) {
306 if (ms->c.li[cont_level].last_match == 1)
307 continue;
308 }
309 #endif
310 switch (mget(ms, m, b, bb.fbuf, bb.flen, offset,
311 cont_level, mode, text, flip, indir_count,
312 name_count, printed_something, need_separator,
313 returnval)) {
314 case -1:
315 return -1;
316 case 0:
317 if (m->reln != '!')
318 continue;
319 flush = 1;
320 break;
321 default:
322 if (m->type == FILE_INDIRECT)
323 *returnval = 1;
324 flush = 0;
325 break;
326 }
327
328 switch (flush ? 1 : magiccheck(ms, m)) {
329 case -1:
330 return -1;
331 case 0:
332 #ifdef ENABLE_CONDITIONALS
333 ms->c.li[cont_level].last_match = 0;
334 #endif
335 break;
336 default:
337 #ifdef ENABLE_CONDITIONALS
338 ms->c.li[cont_level].last_match = 1;
339 #endif
340 if (m->type == FILE_CLEAR)
341 ms->c.li[cont_level].got_match = 0;
342 else if (ms->c.li[cont_level].got_match) {
343 if (m->type == FILE_DEFAULT)
344 break;
345 } else
346 ms->c.li[cont_level].got_match = 1;
347
348 if ((e = handle_annotation(ms, m, b, firstline))
349 != 0) {
350 *need_separator = 1;
351 *printed_something = 1;
352 *returnval = 1;
353 return e;
354 }
355 /*
356 * If we are going to print something,
357 * make sure that we have a separator first.
358 */
359 if (*m->desc) {
360 if (!*printed_something) {
361 *printed_something = 1;
362 if (print_sep(ms, firstline)
363 == -1)
364 return -1;
365 }
366 }
367 /*
368 * This continuation matched. Print
369 * its message, with a blank before it
370 * if the previous item printed and
371 * this item isn't empty.
372 */
373 /* space if previous printed */
374 if (*need_separator
375 && ((m->flag & NOSPACE) == 0)
376 && *m->desc) {
377 if (print &&
378 file_printf(ms, " ") == -1)
379 return -1;
380 *need_separator = 0;
381 }
382 if (print && mprint(ms, m, b) == -1)
383 return -1;
384
385 switch (moffset(ms, m, &bb,
386 &ms->c.li[cont_level].off)) {
387 case -1:
388 case 0:
389 flush = 1;
390 cont_level--;
391 break;
392 default:
393 break;
394 }
395
396 if (*m->desc)
397 *need_separator = 1;
398
399 /*
400 * If we see any continuations
401 * at a higher level,
402 * process them.
403 */
404 if (file_check_mem(ms, ++cont_level) == -1)
405 return -1;
406 break;
407 }
408 }
409 if (*printed_something) {
410 firstline = 0;
411 if (print)
412 *returnval = 1;
413 }
414 if ((ms->flags & MAGIC_CONTINUE) == 0 && *printed_something) {
415 return *returnval; /* don't keep searching */
416 }
417 cont_level = 0;
418 }
419 return *returnval; /* This is hit if -k is set or there is no match */
420 }
421
422 private int
check_fmt(struct magic_set * ms,const char * fmt)423 check_fmt(struct magic_set *ms, const char *fmt)
424 {
425 pcre_cache_entry *pce;
426 int rv = -1;
427 zend_string *pattern;
428
429 if (strchr(fmt, '%') == NULL)
430 return 0;
431
432 pattern = zend_string_init("~%[-0-9\\.]*s~", sizeof("~%[-0-9\\.]*s~") - 1, 0);
433 if ((pce = pcre_get_compiled_regex_cache_ex(pattern, 0)) == NULL) {
434 rv = -1;
435 } else {
436 pcre2_code *re = php_pcre_pce_re(pce);
437 pcre2_match_data *match_data = php_pcre_create_match_data(0, re);
438 if (match_data) {
439 rv = pcre2_match(re, (PCRE2_SPTR)fmt, strlen(fmt), 0, 0, match_data, php_pcre_mctx()) > 0;
440 php_pcre_free_match_data(match_data);
441 }
442 }
443 zend_string_release(pattern);
444 return rv;
445 }
446
447 static int
varexpand(char * buf,size_t len,const struct buffer * b,const char * str)448 varexpand(char *buf, size_t len, const struct buffer *b, const char *str)
449 {
450 const char *ptr, *sptr, *e, *t, *ee, *et;
451 size_t l;
452
453 for (sptr = str; (ptr = strstr(sptr, "${")) != NULL;) {
454 l = (size_t)(ptr - sptr);
455 if (l >= len)
456 return -1;
457 memcpy(buf, sptr, l);
458 buf += l;
459 len -= l;
460 ptr += 2;
461 if (!*ptr || ptr[1] != '?')
462 return -1;
463 for (et = t = ptr + 2; *et && *et != ':'; et++)
464 continue;
465 if (*et != ':')
466 return -1;
467 for (ee = e = et + 1; *ee && *ee != '}'; ee++)
468 continue;
469 if (*ee != '}')
470 return -1;
471 switch (*ptr) {
472 case 'x':
473 if (b->st.st_mode & 0111) {
474 ptr = t;
475 l = et - t;
476 } else {
477 ptr = e;
478 l = ee - e;
479 }
480 break;
481 default:
482 return -1;
483 }
484 if (l >= len)
485 return -1;
486 memcpy(buf, ptr, l);
487 buf += l;
488 len -= l;
489 sptr = ee + 1;
490 }
491
492 l = strlen(sptr);
493 if (l >= len)
494 return -1;
495
496 memcpy(buf, sptr, l);
497 buf[l] = '\0';
498 return 0;
499 }
500
501
502 private int32_t
mprint(struct magic_set * ms,struct magic * m,const struct buffer * b)503 mprint(struct magic_set *ms, struct magic *m, const struct buffer *b)
504 {
505 uint64_t v;
506 float vf;
507 double vd;
508 int64_t t = 0;
509 char buf[128], tbuf[26], sbuf[512], ebuf[512];
510 const char *desc;
511 union VALUETYPE *p = &ms->ms_value;
512
513 if (varexpand(ebuf, sizeof(ebuf), b, m->desc) == -1)
514 desc = m->desc;
515 else
516 desc = ebuf;
517
518 switch (m->type) {
519 case FILE_BYTE:
520 v = file_signextend(ms, m, (uint64_t)p->b);
521 switch (check_fmt(ms, desc)) {
522 case -1:
523 return -1;
524 case 1:
525 (void)snprintf(buf, sizeof(buf), "%d",
526 (unsigned char)v);
527 if (file_printf(ms, F(ms, desc, "%s"), buf) == -1)
528 return -1;
529 break;
530 default:
531 if (file_printf(ms, F(ms, desc, "%d"),
532 (unsigned char) v) == -1)
533 return -1;
534 break;
535 }
536 t = ms->offset + sizeof(char);
537 break;
538
539 case FILE_SHORT:
540 case FILE_BESHORT:
541 case FILE_LESHORT:
542 v = file_signextend(ms, m, (uint64_t)p->h);
543 switch (check_fmt(ms, desc)) {
544 case -1:
545 return -1;
546 case 1:
547 (void)snprintf(buf, sizeof(buf), "%u",
548 (unsigned short)v);
549 if (file_printf(ms, F(ms, desc, "%s"), buf) == -1)
550 return -1;
551 break;
552 default:
553 if (file_printf(ms, F(ms, desc, "%u"),
554 (unsigned short) v) == -1)
555 return -1;
556 break;
557 }
558 t = ms->offset + sizeof(short);
559 break;
560
561 case FILE_LONG:
562 case FILE_BELONG:
563 case FILE_LELONG:
564 case FILE_MELONG:
565 v = file_signextend(ms, m, (uint64_t)p->l);
566 switch (check_fmt(ms, desc)) {
567 case -1:
568 return -1;
569 case 1:
570 (void)snprintf(buf, sizeof(buf), "%u", (uint32_t) v);
571 if (file_printf(ms, F(ms, desc, "%s"), buf) == -1)
572 return -1;
573 break;
574 default:
575 if (file_printf(ms, F(ms, desc, "%u"), (uint32_t) v) == -1)
576 return -1;
577 break;
578 }
579 t = ms->offset + sizeof(int32_t);
580 break;
581
582 case FILE_QUAD:
583 case FILE_BEQUAD:
584 case FILE_LEQUAD:
585 v = file_signextend(ms, m, p->q);
586 switch (check_fmt(ms, desc)) {
587 case -1:
588 return -1;
589 case 1:
590 (void)snprintf(buf, sizeof(buf), "%" INT64_T_FORMAT "u",
591 (unsigned long long)v);
592 if (file_printf(ms, F(ms, desc, "%s"), buf) == -1)
593 return -1;
594 break;
595 default:
596 if (file_printf(ms, F(ms, desc, "%" INT64_T_FORMAT "u"),
597 (unsigned long long) v) == -1)
598 return -1;
599 break;
600 }
601 t = ms->offset + sizeof(int64_t);
602 break;
603
604 case FILE_STRING:
605 case FILE_PSTRING:
606 case FILE_BESTRING16:
607 case FILE_LESTRING16:
608 if (m->reln == '=' || m->reln == '!') {
609 if (file_printf(ms, F(ms, desc, "%s"),
610 file_printable(sbuf, sizeof(sbuf), m->value.s))
611 == -1)
612 return -1;
613 t = ms->offset + m->vallen;
614 }
615 else {
616 char *str = p->s;
617
618 /* compute t before we mangle the string? */
619 t = ms->offset + strlen(str);
620
621 if (*m->value.s == '\0')
622 str[strcspn(str, "\r\n")] = '\0';
623
624 if (m->str_flags & STRING_TRIM) {
625 char *last;
626 while (isspace((unsigned char)*str))
627 str++;
628 last = str;
629 while (*last)
630 last++;
631 --last;
632 while (isspace((unsigned char)*last))
633 last--;
634 *++last = '\0';
635 }
636
637 if (file_printf(ms, F(ms, desc, "%s"),
638 file_printable(sbuf, sizeof(sbuf), str)) == -1)
639 return -1;
640
641 if (m->type == FILE_PSTRING)
642 t += file_pstring_length_size(m);
643 }
644 break;
645
646 case FILE_DATE:
647 case FILE_BEDATE:
648 case FILE_LEDATE:
649 case FILE_MEDATE:
650 if (file_printf(ms, F(ms, desc, "%s"),
651 file_fmttime(p->l, 0, tbuf)) == -1)
652 return -1;
653 t = ms->offset + sizeof(uint32_t);
654 break;
655
656 case FILE_LDATE:
657 case FILE_BELDATE:
658 case FILE_LELDATE:
659 case FILE_MELDATE:
660 if (file_printf(ms, F(ms, desc, "%s"),
661 file_fmttime(p->l, FILE_T_LOCAL, tbuf)) == -1)
662 return -1;
663 t = ms->offset + sizeof(uint32_t);
664 break;
665
666 case FILE_QDATE:
667 case FILE_BEQDATE:
668 case FILE_LEQDATE:
669 if (file_printf(ms, F(ms, desc, "%s"),
670 file_fmttime(p->q, 0, tbuf)) == -1)
671 return -1;
672 t = ms->offset + sizeof(uint64_t);
673 break;
674
675 case FILE_QLDATE:
676 case FILE_BEQLDATE:
677 case FILE_LEQLDATE:
678 if (file_printf(ms, F(ms, desc, "%s"),
679 file_fmttime(p->q, FILE_T_LOCAL, tbuf)) == -1)
680 return -1;
681 t = ms->offset + sizeof(uint64_t);
682 break;
683
684 case FILE_QWDATE:
685 case FILE_BEQWDATE:
686 case FILE_LEQWDATE:
687 if (file_printf(ms, F(ms, desc, "%s"),
688 file_fmttime(p->q, FILE_T_WINDOWS, tbuf)) == -1)
689 return -1;
690 t = ms->offset + sizeof(uint64_t);
691 break;
692
693 case FILE_FLOAT:
694 case FILE_BEFLOAT:
695 case FILE_LEFLOAT:
696 vf = p->f;
697 switch (check_fmt(ms, desc)) {
698 case -1:
699 return -1;
700 case 1:
701 (void)snprintf(buf, sizeof(buf), "%g", vf);
702 if (file_printf(ms, F(ms, desc, "%s"), buf) == -1)
703 return -1;
704 break;
705 default:
706 if (file_printf(ms, F(ms, desc, "%g"), vf) == -1)
707 return -1;
708 break;
709 }
710 t = ms->offset + sizeof(float);
711 break;
712
713 case FILE_DOUBLE:
714 case FILE_BEDOUBLE:
715 case FILE_LEDOUBLE:
716 vd = p->d;
717 switch (check_fmt(ms, desc)) {
718 case -1:
719 return -1;
720 case 1:
721 (void)snprintf(buf, sizeof(buf), "%g", vd);
722 if (file_printf(ms, F(ms, desc, "%s"), buf) == -1)
723 return -1;
724 break;
725 default:
726 if (file_printf(ms, F(ms, desc, "%g"), vd) == -1)
727 return -1;
728 break;
729 }
730 t = ms->offset + sizeof(double);
731 break;
732
733 case FILE_SEARCH:
734 case FILE_REGEX: {
735 char *cp;
736 int rval;
737
738 cp = estrndup((const char *)ms->search.s, ms->search.rm_len);
739 rval = file_printf(ms, F(ms, desc, "%s"),
740 file_printable(sbuf, sizeof(sbuf), cp));
741 efree(cp);
742
743 if (rval == -1)
744 return -1;
745
746 if ((m->str_flags & REGEX_OFFSET_START))
747 t = ms->search.offset;
748 else
749 t = ms->search.offset + ms->search.rm_len;
750 break;
751 }
752
753 case FILE_DEFAULT:
754 case FILE_CLEAR:
755 if (file_printf(ms, "%s", m->desc) == -1)
756 return -1;
757 t = ms->offset;
758 break;
759
760 case FILE_INDIRECT:
761 case FILE_USE:
762 case FILE_NAME:
763 t = ms->offset;
764 break;
765 case FILE_DER:
766 if (file_printf(ms, F(ms, desc, "%s"),
767 file_printable(sbuf, sizeof(sbuf), ms->ms_value.s)) == -1)
768 return -1;
769 t = ms->offset;
770 break;
771 default:
772 file_magerror(ms, "invalid m->type (%d) in mprint()", m->type);
773 return -1;
774 }
775 return (int32_t)t;
776 }
777
778 private int
moffset(struct magic_set * ms,struct magic * m,const struct buffer * b,int32_t * op)779 moffset(struct magic_set *ms, struct magic *m, const struct buffer *b,
780 int32_t *op)
781 {
782 size_t nbytes = b->flen;
783 int32_t o;
784
785 switch (m->type) {
786 case FILE_BYTE:
787 o = CAST(int32_t, (ms->offset + sizeof(char)));
788 break;
789
790 case FILE_SHORT:
791 case FILE_BESHORT:
792 case FILE_LESHORT:
793 o = CAST(int32_t, (ms->offset + sizeof(short)));
794 break;
795
796 case FILE_LONG:
797 case FILE_BELONG:
798 case FILE_LELONG:
799 case FILE_MELONG:
800 o = CAST(int32_t, (ms->offset + sizeof(int32_t)));
801 break;
802
803 case FILE_QUAD:
804 case FILE_BEQUAD:
805 case FILE_LEQUAD:
806 o = CAST(int32_t, (ms->offset + sizeof(int64_t)));
807 break;
808
809 case FILE_STRING:
810 case FILE_PSTRING:
811 case FILE_BESTRING16:
812 case FILE_LESTRING16:
813 if (m->reln == '=' || m->reln == '!') {
814 o = ms->offset + m->vallen;
815 } else {
816 union VALUETYPE *p = &ms->ms_value;
817
818 if (*m->value.s == '\0')
819 p->s[strcspn(p->s, "\r\n")] = '\0';
820 o = CAST(uint32_t, (ms->offset + strlen(p->s)));
821 if (m->type == FILE_PSTRING)
822 o += (uint32_t)file_pstring_length_size(m);
823 }
824 break;
825
826 case FILE_DATE:
827 case FILE_BEDATE:
828 case FILE_LEDATE:
829 case FILE_MEDATE:
830 o = CAST(int32_t, (ms->offset + sizeof(uint32_t)));
831 break;
832
833 case FILE_LDATE:
834 case FILE_BELDATE:
835 case FILE_LELDATE:
836 case FILE_MELDATE:
837 o = CAST(int32_t, (ms->offset + sizeof(uint32_t)));
838 break;
839
840 case FILE_QDATE:
841 case FILE_BEQDATE:
842 case FILE_LEQDATE:
843 o = CAST(int32_t, (ms->offset + sizeof(uint64_t)));
844 break;
845
846 case FILE_QLDATE:
847 case FILE_BEQLDATE:
848 case FILE_LEQLDATE:
849 o = CAST(int32_t, (ms->offset + sizeof(uint64_t)));
850 break;
851
852 case FILE_FLOAT:
853 case FILE_BEFLOAT:
854 case FILE_LEFLOAT:
855 o = CAST(int32_t, (ms->offset + sizeof(float)));
856 break;
857
858 case FILE_DOUBLE:
859 case FILE_BEDOUBLE:
860 case FILE_LEDOUBLE:
861 o = CAST(int32_t, (ms->offset + sizeof(double)));
862 break;
863
864 case FILE_REGEX:
865 if ((m->str_flags & REGEX_OFFSET_START) != 0)
866 o = CAST(int32_t, ms->search.offset);
867 else
868 o = CAST(int32_t,
869 (ms->search.offset + ms->search.rm_len));
870 break;
871
872 case FILE_SEARCH:
873 if ((m->str_flags & REGEX_OFFSET_START) != 0)
874 o = CAST(int32_t, ms->search.offset);
875 else
876 o = CAST(int32_t, (ms->search.offset + m->vallen));
877 break;
878
879 case FILE_CLEAR:
880 case FILE_DEFAULT:
881 case FILE_INDIRECT:
882 o = ms->offset;
883 break;
884
885 case FILE_DER:
886 {
887 o = der_offs(ms, m, nbytes);
888 if (o == -1 || (size_t)o > nbytes) {
889 if ((ms->flags & MAGIC_DEBUG) != 0) {
890 (void)fprintf(stderr,
891 "Bad DER offset %d nbytes=%zu",
892 o, nbytes);
893 }
894 *op = 0;
895 return 0;
896 }
897 break;
898 }
899
900 default:
901 o = 0;
902 break;
903 }
904
905 if ((size_t)o > nbytes) {
906 #if 0
907 file_error(ms, 0, "Offset out of range %zu > %zu",
908 (size_t)o, nbytes);
909 #endif
910 return -1;
911 }
912 *op = o;
913 return 1;
914 }
915
916 private uint32_t
cvt_id3(struct magic_set * ms,uint32_t v)917 cvt_id3(struct magic_set *ms, uint32_t v)
918 {
919 v = ((((v >> 0) & 0x7f) << 0) |
920 (((v >> 8) & 0x7f) << 7) |
921 (((v >> 16) & 0x7f) << 14) |
922 (((v >> 24) & 0x7f) << 21));
923 if ((ms->flags & MAGIC_DEBUG) != 0)
924 fprintf(stderr, "id3 offs=%u\n", v);
925 return v;
926 }
927
928 private int
cvt_flip(int type,int flip)929 cvt_flip(int type, int flip)
930 {
931 if (flip == 0)
932 return type;
933 switch (type) {
934 case FILE_BESHORT:
935 return FILE_LESHORT;
936 case FILE_BELONG:
937 return FILE_LELONG;
938 case FILE_BEDATE:
939 return FILE_LEDATE;
940 case FILE_BELDATE:
941 return FILE_LELDATE;
942 case FILE_BEQUAD:
943 return FILE_LEQUAD;
944 case FILE_BEQDATE:
945 return FILE_LEQDATE;
946 case FILE_BEQLDATE:
947 return FILE_LEQLDATE;
948 case FILE_BEQWDATE:
949 return FILE_LEQWDATE;
950 case FILE_LESHORT:
951 return FILE_BESHORT;
952 case FILE_LELONG:
953 return FILE_BELONG;
954 case FILE_LEDATE:
955 return FILE_BEDATE;
956 case FILE_LELDATE:
957 return FILE_BELDATE;
958 case FILE_LEQUAD:
959 return FILE_BEQUAD;
960 case FILE_LEQDATE:
961 return FILE_BEQDATE;
962 case FILE_LEQLDATE:
963 return FILE_BEQLDATE;
964 case FILE_LEQWDATE:
965 return FILE_BEQWDATE;
966 case FILE_BEFLOAT:
967 return FILE_LEFLOAT;
968 case FILE_LEFLOAT:
969 return FILE_BEFLOAT;
970 case FILE_BEDOUBLE:
971 return FILE_LEDOUBLE;
972 case FILE_LEDOUBLE:
973 return FILE_BEDOUBLE;
974 default:
975 return type;
976 }
977 }
978 #define DO_CVT(fld, cast) \
979 if (m->num_mask) \
980 switch (m->mask_op & FILE_OPS_MASK) { \
981 case FILE_OPAND: \
982 p->fld &= cast m->num_mask; \
983 break; \
984 case FILE_OPOR: \
985 p->fld |= cast m->num_mask; \
986 break; \
987 case FILE_OPXOR: \
988 p->fld ^= cast m->num_mask; \
989 break; \
990 case FILE_OPADD: \
991 p->fld += cast m->num_mask; \
992 break; \
993 case FILE_OPMINUS: \
994 p->fld -= cast m->num_mask; \
995 break; \
996 case FILE_OPMULTIPLY: \
997 p->fld *= cast m->num_mask; \
998 break; \
999 case FILE_OPDIVIDE: \
1000 if (cast m->num_mask == 0) \
1001 return -1; \
1002 p->fld /= cast m->num_mask; \
1003 break; \
1004 case FILE_OPMODULO: \
1005 if (cast m->num_mask == 0) \
1006 return -1; \
1007 p->fld %= cast m->num_mask; \
1008 break; \
1009 } \
1010 if (m->mask_op & FILE_OPINVERSE) \
1011 p->fld = ~p->fld \
1012
1013 private int
cvt_8(union VALUETYPE * p,const struct magic * m)1014 cvt_8(union VALUETYPE *p, const struct magic *m)
1015 {
1016 DO_CVT(b, (uint8_t));
1017 return 0;
1018 }
1019
1020 private int
cvt_16(union VALUETYPE * p,const struct magic * m)1021 cvt_16(union VALUETYPE *p, const struct magic *m)
1022 {
1023 DO_CVT(h, (uint16_t));
1024 return 0;
1025 }
1026
1027 private int
cvt_32(union VALUETYPE * p,const struct magic * m)1028 cvt_32(union VALUETYPE *p, const struct magic *m)
1029 {
1030 DO_CVT(l, (uint32_t));
1031 return 0;
1032 }
1033
1034 private int
cvt_64(union VALUETYPE * p,const struct magic * m)1035 cvt_64(union VALUETYPE *p, const struct magic *m)
1036 {
1037 DO_CVT(q, (uint64_t));
1038 return 0;
1039 }
1040
1041 #define DO_CVT2(fld, cast) \
1042 if (m->num_mask) \
1043 switch (m->mask_op & FILE_OPS_MASK) { \
1044 case FILE_OPADD: \
1045 p->fld += cast m->num_mask; \
1046 break; \
1047 case FILE_OPMINUS: \
1048 p->fld -= cast m->num_mask; \
1049 break; \
1050 case FILE_OPMULTIPLY: \
1051 p->fld *= cast m->num_mask; \
1052 break; \
1053 case FILE_OPDIVIDE: \
1054 if (cast m->num_mask == 0) \
1055 return -1; \
1056 p->fld /= cast m->num_mask; \
1057 break; \
1058 } \
1059
1060 private int
cvt_float(union VALUETYPE * p,const struct magic * m)1061 cvt_float(union VALUETYPE *p, const struct magic *m)
1062 {
1063 DO_CVT2(f, (float));
1064 return 0;
1065 }
1066
1067 private int
cvt_double(union VALUETYPE * p,const struct magic * m)1068 cvt_double(union VALUETYPE *p, const struct magic *m)
1069 {
1070 DO_CVT2(d, (double));
1071 return 0;
1072 }
1073
1074 /*
1075 * Convert the byte order of the data we are looking at
1076 * While we're here, let's apply the mask operation
1077 * (unless you have a better idea)
1078 */
1079 private int
mconvert(struct magic_set * ms,struct magic * m,int flip)1080 mconvert(struct magic_set *ms, struct magic *m, int flip)
1081 {
1082 union VALUETYPE *p = &ms->ms_value;
1083
1084 switch (cvt_flip(m->type, flip)) {
1085 case FILE_BYTE:
1086 if (cvt_8(p, m) == -1)
1087 goto out;
1088 return 1;
1089 case FILE_SHORT:
1090 if (cvt_16(p, m) == -1)
1091 goto out;
1092 return 1;
1093 case FILE_LONG:
1094 case FILE_DATE:
1095 case FILE_LDATE:
1096 if (cvt_32(p, m) == -1)
1097 goto out;
1098 return 1;
1099 case FILE_QUAD:
1100 case FILE_QDATE:
1101 case FILE_QLDATE:
1102 case FILE_QWDATE:
1103 if (cvt_64(p, m) == -1)
1104 goto out;
1105 return 1;
1106 case FILE_STRING:
1107 case FILE_BESTRING16:
1108 case FILE_LESTRING16: {
1109 /* Null terminate and eat *trailing* return */
1110 p->s[sizeof(p->s) - 1] = '\0';
1111 return 1;
1112 }
1113 case FILE_PSTRING: {
1114 size_t sz = file_pstring_length_size(m);
1115 char *ptr1 = p->s, *ptr2 = ptr1 + sz;
1116 size_t len = file_pstring_get_length(m, ptr1);
1117 sz = sizeof(p->s) - sz; /* maximum length of string */
1118 if (len >= sz) {
1119 /*
1120 * The size of the pascal string length (sz)
1121 * is 1, 2, or 4. We need at least 1 byte for NUL
1122 * termination, but we've already truncated the
1123 * string by p->s, so we need to deduct sz.
1124 * Because we can use one of the bytes of the length
1125 * after we shifted as NUL termination.
1126 */
1127 len = sz;
1128 }
1129 while (len--)
1130 *ptr1++ = *ptr2++;
1131 *ptr1 = '\0';
1132 return 1;
1133 }
1134 case FILE_BESHORT:
1135 p->h = (short)BE16(p);
1136 if (cvt_16(p, m) == -1)
1137 goto out;
1138 return 1;
1139 case FILE_BELONG:
1140 case FILE_BEDATE:
1141 case FILE_BELDATE:
1142 p->l = (int32_t)BE32(p);
1143 if (cvt_32(p, m) == -1)
1144 goto out;
1145 return 1;
1146 case FILE_BEQUAD:
1147 case FILE_BEQDATE:
1148 case FILE_BEQLDATE:
1149 case FILE_BEQWDATE:
1150 p->q = (uint64_t)BE64(p);
1151 if (cvt_64(p, m) == -1)
1152 goto out;
1153 return 1;
1154 case FILE_LESHORT:
1155 p->h = (short)LE16(p);
1156 if (cvt_16(p, m) == -1)
1157 goto out;
1158 return 1;
1159 case FILE_LELONG:
1160 case FILE_LEDATE:
1161 case FILE_LELDATE:
1162 p->l = (int32_t)LE32(p);
1163 if (cvt_32(p, m) == -1)
1164 goto out;
1165 return 1;
1166 case FILE_LEQUAD:
1167 case FILE_LEQDATE:
1168 case FILE_LEQLDATE:
1169 case FILE_LEQWDATE:
1170 p->q = (uint64_t)LE64(p);
1171 if (cvt_64(p, m) == -1)
1172 goto out;
1173 return 1;
1174 case FILE_MELONG:
1175 case FILE_MEDATE:
1176 case FILE_MELDATE:
1177 p->l = (int32_t)ME32(p);
1178 if (cvt_32(p, m) == -1)
1179 goto out;
1180 return 1;
1181 case FILE_FLOAT:
1182 if (cvt_float(p, m) == -1)
1183 goto out;
1184 return 1;
1185 case FILE_BEFLOAT:
1186 p->l = BE32(p);
1187 if (cvt_float(p, m) == -1)
1188 goto out;
1189 return 1;
1190 case FILE_LEFLOAT:
1191 p->l = LE32(p);
1192 if (cvt_float(p, m) == -1)
1193 goto out;
1194 return 1;
1195 case FILE_DOUBLE:
1196 if (cvt_double(p, m) == -1)
1197 goto out;
1198 return 1;
1199 case FILE_BEDOUBLE:
1200 p->q = BE64(p);
1201 if (cvt_double(p, m) == -1)
1202 goto out;
1203 return 1;
1204 case FILE_LEDOUBLE:
1205 p->q = LE64(p);
1206 if (cvt_double(p, m) == -1)
1207 goto out;
1208 return 1;
1209 case FILE_REGEX:
1210 case FILE_SEARCH:
1211 case FILE_DEFAULT:
1212 case FILE_CLEAR:
1213 case FILE_NAME:
1214 case FILE_USE:
1215 case FILE_DER:
1216 return 1;
1217 default:
1218 file_magerror(ms, "invalid type %d in mconvert()", m->type);
1219 return 0;
1220 }
1221 out:
1222 file_magerror(ms, "zerodivide in mconvert()");
1223 return 0;
1224 }
1225
1226
1227 private void
mdebug(uint32_t offset,const char * str,size_t len)1228 mdebug(uint32_t offset, const char *str, size_t len)
1229 {
1230 (void) fprintf(stderr, "mget/%" SIZE_T_FORMAT "u @%d: ", len, offset);
1231 file_showstr(stderr, str, len);
1232 (void) fputc('\n', stderr);
1233 (void) fputc('\n', stderr);
1234 }
1235
1236 private int
mcopy(struct magic_set * ms,union VALUETYPE * p,int type,int indir,const unsigned char * s,uint32_t offset,size_t nbytes,struct magic * m)1237 mcopy(struct magic_set *ms, union VALUETYPE *p, int type, int indir,
1238 const unsigned char *s, uint32_t offset, size_t nbytes, struct magic *m)
1239 {
1240 /*
1241 * Note: FILE_SEARCH and FILE_REGEX do not actually copy
1242 * anything, but setup pointers into the source
1243 */
1244 if (indir == 0) {
1245 switch (type) {
1246 case FILE_DER:
1247 case FILE_SEARCH:
1248 if (offset > nbytes)
1249 offset = CAST(uint32_t, nbytes);
1250 ms->search.s = RCAST(const char *, s) + offset;
1251 ms->search.s_len = nbytes - offset;
1252 ms->search.offset = offset;
1253 return 0;
1254
1255 case FILE_REGEX: {
1256 const char *b;
1257 const char *c;
1258 const char *last; /* end of search region */
1259 const char *buf; /* start of search region */
1260 const char *end;
1261 size_t lines, linecnt, bytecnt;
1262
1263 if (s == NULL || nbytes < offset) {
1264 ms->search.s_len = 0;
1265 ms->search.s = NULL;
1266 return 0;
1267 }
1268
1269 if (m->str_flags & REGEX_LINE_COUNT) {
1270 linecnt = m->str_range;
1271 bytecnt = linecnt * 80;
1272 } else {
1273 linecnt = 0;
1274 bytecnt = m->str_range;
1275 }
1276
1277 if (bytecnt == 0 || bytecnt > nbytes - offset)
1278 bytecnt = nbytes - offset;
1279 if (bytecnt > ms->regex_max)
1280 bytecnt = ms->regex_max;
1281
1282 buf = RCAST(const char *, s) + offset;
1283 end = last = RCAST(const char *, s) + bytecnt + offset;
1284 /* mget() guarantees buf <= last */
1285 for (lines = linecnt, b = buf; lines && b < end &&
1286 ((b = CAST(const char *,
1287 memchr(c = b, '\n', CAST(size_t, (end - b)))))
1288 || (b = CAST(const char *,
1289 memchr(c, '\r', CAST(size_t, (end - c))))));
1290 lines--, b++) {
1291 last = b;
1292 if (b < end - 1 && b[0] == '\r' && b[1] == '\n')
1293 b++;
1294 }
1295 if (lines)
1296 last = end;
1297
1298 ms->search.s = buf;
1299 ms->search.s_len = last - buf;
1300 ms->search.offset = offset;
1301 ms->search.rm_len = 0;
1302 return 0;
1303 }
1304 case FILE_BESTRING16:
1305 case FILE_LESTRING16: {
1306 const unsigned char *src = s + offset;
1307 const unsigned char *esrc = s + nbytes;
1308 char *dst = p->s;
1309 char *edst = &p->s[sizeof(p->s) - 1];
1310
1311 if (type == FILE_BESTRING16)
1312 src++;
1313
1314 /* check that offset is within range */
1315 if (offset >= nbytes)
1316 break;
1317 for (/*EMPTY*/; src < esrc; src += 2, dst++) {
1318 if (dst < edst)
1319 *dst = *src;
1320 else
1321 break;
1322 if (*dst == '\0') {
1323 if (type == FILE_BESTRING16 ?
1324 *(src - 1) != '\0' :
1325 ((src + 1 < esrc) &&
1326 *(src + 1) != '\0'))
1327 *dst = ' ';
1328 }
1329 }
1330 *edst = '\0';
1331 return 0;
1332 }
1333 case FILE_STRING: /* XXX - these two should not need */
1334 case FILE_PSTRING: /* to copy anything, but do anyway. */
1335 default:
1336 break;
1337 }
1338 }
1339
1340 if (offset >= nbytes) {
1341 (void)memset(p, '\0', sizeof(*p));
1342 return 0;
1343 }
1344 if (nbytes - offset < sizeof(*p))
1345 nbytes = nbytes - offset;
1346 else
1347 nbytes = sizeof(*p);
1348
1349 (void)memcpy(p, s + offset, nbytes);
1350
1351 /*
1352 * the usefulness of padding with zeroes eludes me, it
1353 * might even cause problems
1354 */
1355 if (nbytes < sizeof(*p))
1356 (void)memset(((char *)(void *)p) + nbytes, '\0',
1357 sizeof(*p) - nbytes);
1358 return 0;
1359 }
1360
1361 private uint32_t
do_ops(struct magic * m,intmax_t lhs,intmax_t off)1362 do_ops(struct magic *m, intmax_t lhs, intmax_t off)
1363 {
1364 intmax_t offset;
1365 if (off) {
1366 switch (m->in_op & FILE_OPS_MASK) {
1367 case FILE_OPAND:
1368 offset = lhs & off;
1369 break;
1370 case FILE_OPOR:
1371 offset = lhs | off;
1372 break;
1373 case FILE_OPXOR:
1374 offset = lhs ^ off;
1375 break;
1376 case FILE_OPADD:
1377 offset = lhs + off;
1378 break;
1379 case FILE_OPMINUS:
1380 offset = lhs - off;
1381 break;
1382 case FILE_OPMULTIPLY:
1383 offset = lhs * off;
1384 break;
1385 case FILE_OPDIVIDE:
1386 offset = lhs / off;
1387 break;
1388 case FILE_OPMODULO:
1389 offset = lhs % off;
1390 break;
1391 }
1392 } else
1393 offset = lhs;
1394 if (m->in_op & FILE_OPINVERSE)
1395 offset = ~offset;
1396
1397 return (uint32_t)offset;
1398 }
1399
1400 private int
msetoffset(struct magic_set * ms,struct magic * m,struct buffer * bb,const struct buffer * b,size_t o,unsigned int cont_level)1401 msetoffset(struct magic_set *ms, struct magic *m, struct buffer *bb,
1402 const struct buffer *b, size_t o, unsigned int cont_level)
1403 {
1404 if (m->offset < 0) {
1405 if (cont_level > 0) {
1406 if (m->flag & (OFFADD|INDIROFFADD))
1407 goto normal;
1408 #if 0
1409 file_error(ms, 0, "negative offset %d at continuation"
1410 "level %u", m->offset, cont_level);
1411 return -1;
1412 #endif
1413 }
1414 if (buffer_fill(b) == -1)
1415 return -1;
1416 if (o != 0) {
1417 // Not yet!
1418 file_magerror(ms, "non zero offset %zu at"
1419 " level %u", o, cont_level);
1420 return -1;
1421 }
1422 if ((size_t)-m->offset > b->elen)
1423 return -1;
1424 buffer_init(bb, -1, b->ebuf, b->elen);
1425 ms->eoffset = ms->offset = b->elen + m->offset;
1426 } else {
1427 if (cont_level == 0) {
1428 normal:
1429 // XXX: Pass real fd, then who frees bb?
1430 buffer_init(bb, -1, b->fbuf, b->flen);
1431 ms->offset = m->offset;
1432 ms->eoffset = 0;
1433 } else {
1434 ms->offset = ms->eoffset + m->offset;
1435 }
1436 }
1437 if ((ms->flags & MAGIC_DEBUG) != 0) {
1438 fprintf(stderr, "bb=[%p,%zu], %d [b=%p,%zu], [o=%#x, c=%d]\n",
1439 bb->fbuf, bb->flen, ms->offset, b->fbuf, b->flen,
1440 m->offset, cont_level);
1441 }
1442 return 0;
1443 }
1444
1445 private int
mget(struct magic_set * ms,struct magic * m,const struct buffer * b,const unsigned char * s,size_t nbytes,size_t o,unsigned int cont_level,int mode,int text,int flip,uint16_t * indir_count,uint16_t * name_count,int * printed_something,int * need_separator,int * returnval)1446 mget(struct magic_set *ms, struct magic *m, const struct buffer *b,
1447 const unsigned char *s, size_t nbytes, size_t o, unsigned int cont_level,
1448 int mode, int text, int flip, uint16_t *indir_count, uint16_t *name_count,
1449 int *printed_something, int *need_separator, int *returnval)
1450 {
1451 uint32_t offset = ms->offset;
1452 struct buffer bb;
1453 intmax_t lhs;
1454 file_pushbuf_t *pb;
1455 int rv, oneed_separator, in_type;
1456 char *rbuf;
1457 union VALUETYPE *p = &ms->ms_value;
1458 struct mlist ml;
1459
1460 if (*indir_count >= ms->indir_max) {
1461 file_error(ms, 0, "indirect count (%hu) exceeded",
1462 *indir_count);
1463 return -1;
1464 }
1465
1466 if (*name_count >= ms->name_max) {
1467 file_error(ms, 0, "name use count (%hu) exceeded",
1468 *name_count);
1469 return -1;
1470 }
1471
1472 if (mcopy(ms, p, m->type, m->flag & INDIR, s, (uint32_t)(offset + o),
1473 (uint32_t)nbytes, m) == -1)
1474 return -1;
1475
1476 if ((ms->flags & MAGIC_DEBUG) != 0) {
1477 fprintf(stderr, "mget(type=%d, flag=%#x, offset=%u, o=%"
1478 SIZE_T_FORMAT "u, " "nbytes=%" SIZE_T_FORMAT
1479 "u, il=%hu, nc=%hu)\n",
1480 m->type, m->flag, offset, o, nbytes,
1481 *indir_count, *name_count);
1482 mdebug(offset, (char *)(void *)p, sizeof(union VALUETYPE));
1483 }
1484
1485 if (m->flag & INDIR) {
1486 intmax_t off = m->in_offset;
1487 const int sgn = m->in_op & FILE_OPSIGNED;
1488 if (m->in_op & FILE_OPINDIRECT) {
1489 const union VALUETYPE *q = CAST(const union VALUETYPE *,
1490 ((const void *)(s + offset + off)));
1491 if (OFFSET_OOB(nbytes, offset + off, sizeof(*q)))
1492 return 0;
1493 switch (cvt_flip(m->in_type, flip)) {
1494 case FILE_BYTE:
1495 off = SEXT(sgn,8,q->b);
1496 break;
1497 case FILE_SHORT:
1498 off = SEXT(sgn,16,q->h);
1499 break;
1500 case FILE_BESHORT:
1501 off = SEXT(sgn,16,BE16(q));
1502 break;
1503 case FILE_LESHORT:
1504 off = SEXT(sgn,16,LE16(q));
1505 break;
1506 case FILE_LONG:
1507 off = SEXT(sgn,32,q->l);
1508 break;
1509 case FILE_BELONG:
1510 case FILE_BEID3:
1511 off = SEXT(sgn,32,BE32(q));
1512 break;
1513 case FILE_LEID3:
1514 case FILE_LELONG:
1515 off = SEXT(sgn,32,LE32(q));
1516 break;
1517 case FILE_MELONG:
1518 off = SEXT(sgn,32,ME32(q));
1519 break;
1520 }
1521 if ((ms->flags & MAGIC_DEBUG) != 0)
1522 fprintf(stderr, "indirect offs=%jd\n", off);
1523 }
1524 switch (in_type = cvt_flip(m->in_type, flip)) {
1525 case FILE_BYTE:
1526 if (OFFSET_OOB(nbytes, offset, 1))
1527 return 0;
1528 offset = do_ops(m, SEXT(sgn,8,p->b), off);
1529 break;
1530 case FILE_BESHORT:
1531 if (OFFSET_OOB(nbytes, offset, 2))
1532 return 0;
1533 offset = do_ops(m, SEXT(sgn,16,BE16(p)), off);
1534 break;
1535 case FILE_LESHORT:
1536 if (OFFSET_OOB(nbytes, offset, 2))
1537 return 0;
1538 offset = do_ops(m, SEXT(sgn,16,LE16(p)), off);
1539 break;
1540 case FILE_SHORT:
1541 if (OFFSET_OOB(nbytes, offset, 2))
1542 return 0;
1543 offset = do_ops(m, SEXT(sgn,16,p->h), off);
1544 break;
1545 case FILE_BELONG:
1546 case FILE_BEID3:
1547 if (OFFSET_OOB(nbytes, offset, 4))
1548 return 0;
1549 lhs = BE32(p);
1550 if (in_type == FILE_BEID3)
1551 lhs = cvt_id3(ms, (uint32_t)lhs);
1552 offset = do_ops(m, SEXT(sgn,32,lhs), off);
1553 break;
1554 case FILE_LELONG:
1555 case FILE_LEID3:
1556 if (OFFSET_OOB(nbytes, offset, 4))
1557 return 0;
1558 lhs = LE32(p);
1559 if (in_type == FILE_LEID3)
1560 lhs = cvt_id3(ms, (uint32_t)lhs);
1561 offset = do_ops(m, SEXT(sgn,32,lhs), off);
1562 break;
1563 case FILE_MELONG:
1564 if (OFFSET_OOB(nbytes, offset, 4))
1565 return 0;
1566 offset = do_ops(m, SEXT(sgn,32,ME32(p)), off);
1567 break;
1568 case FILE_LONG:
1569 if (OFFSET_OOB(nbytes, offset, 4))
1570 return 0;
1571 offset = do_ops(m, SEXT(sgn,32,p->l), off);
1572 break;
1573 default:
1574 break;
1575 }
1576
1577 if (m->flag & INDIROFFADD) {
1578 offset += ms->c.li[cont_level-1].off;
1579 if (offset == 0) {
1580 if ((ms->flags & MAGIC_DEBUG) != 0)
1581 fprintf(stderr,
1582 "indirect *zero* offset\n");
1583 return 0;
1584 }
1585 if ((ms->flags & MAGIC_DEBUG) != 0)
1586 fprintf(stderr, "indirect +offs=%u\n", offset);
1587 }
1588 if (mcopy(ms, p, m->type, 0, s, offset, nbytes, m) == -1)
1589 return -1;
1590 ms->offset = offset;
1591
1592 if ((ms->flags & MAGIC_DEBUG) != 0) {
1593 mdebug(offset, (char *)(void *)p,
1594 sizeof(union VALUETYPE));
1595 }
1596 }
1597
1598 /* Verify we have enough data to match magic type */
1599 switch (m->type) {
1600 case FILE_BYTE:
1601 if (OFFSET_OOB(nbytes, offset, 1))
1602 return 0;
1603 break;
1604
1605 case FILE_SHORT:
1606 case FILE_BESHORT:
1607 case FILE_LESHORT:
1608 if (OFFSET_OOB(nbytes, offset, 2))
1609 return 0;
1610 break;
1611
1612 case FILE_LONG:
1613 case FILE_BELONG:
1614 case FILE_LELONG:
1615 case FILE_MELONG:
1616 case FILE_DATE:
1617 case FILE_BEDATE:
1618 case FILE_LEDATE:
1619 case FILE_MEDATE:
1620 case FILE_LDATE:
1621 case FILE_BELDATE:
1622 case FILE_LELDATE:
1623 case FILE_MELDATE:
1624 case FILE_FLOAT:
1625 case FILE_BEFLOAT:
1626 case FILE_LEFLOAT:
1627 if (OFFSET_OOB(nbytes, offset, 4))
1628 return 0;
1629 break;
1630
1631 case FILE_DOUBLE:
1632 case FILE_BEDOUBLE:
1633 case FILE_LEDOUBLE:
1634 if (OFFSET_OOB(nbytes, offset, 8))
1635 return 0;
1636 break;
1637
1638 case FILE_STRING:
1639 case FILE_PSTRING:
1640 case FILE_SEARCH:
1641 if (OFFSET_OOB(nbytes, offset, m->vallen))
1642 return 0;
1643 break;
1644
1645 case FILE_REGEX:
1646 if (nbytes < offset)
1647 return 0;
1648 break;
1649
1650 case FILE_INDIRECT:
1651 if (m->str_flags & INDIRECT_RELATIVE)
1652 offset += CAST(uint32_t, o);
1653 if (offset == 0)
1654 return 0;
1655
1656 if (nbytes < offset)
1657 return 0;
1658
1659 if ((pb = file_push_buffer(ms)) == NULL)
1660 return -1;
1661
1662 (*indir_count)++;
1663 bb = *b;
1664 bb.fbuf = s + offset;
1665 bb.flen = nbytes - offset;
1666 rv = file_softmagic(ms, &bb,
1667 indir_count, name_count, BINTEST, text);
1668
1669 if ((ms->flags & MAGIC_DEBUG) != 0)
1670 fprintf(stderr, "indirect @offs=%u[%d]\n", offset, rv);
1671
1672 rbuf = file_pop_buffer(ms, pb);
1673 if (rbuf == NULL && ms->event_flags & EVENT_HAD_ERR)
1674 return -1;
1675
1676 if (rv == 1) {
1677 if ((ms->flags & MAGIC_NODESC) == 0 &&
1678 file_printf(ms, F(ms, m->desc, "%u"), offset) == -1) {
1679 if (rbuf) efree(rbuf);
1680 return -1;
1681 }
1682 if (file_printf(ms, "%s", rbuf) == -1) {
1683 if (rbuf) efree(rbuf);
1684 return -1;
1685 }
1686 }
1687 if (rbuf) efree(rbuf);
1688 return rv;
1689
1690 case FILE_USE:
1691 if (nbytes < offset)
1692 return 0;
1693 rbuf = m->value.s;
1694 if (*rbuf == '^') {
1695 rbuf++;
1696 flip = !flip;
1697 }
1698 if (file_magicfind(ms, rbuf, &ml) == -1) {
1699 file_error(ms, 0, "cannot find entry `%s'", rbuf);
1700 return -1;
1701 }
1702 (*name_count)++;
1703 oneed_separator = *need_separator;
1704 if (m->flag & NOSPACE)
1705 *need_separator = 0;
1706 rv = match(ms, ml.magic, ml.nmagic, b, offset + o,
1707 mode, text, flip, indir_count, name_count,
1708 printed_something, need_separator, returnval);
1709 if (rv != 1)
1710 *need_separator = oneed_separator;
1711 return rv;
1712
1713 case FILE_NAME:
1714 if (ms->flags & MAGIC_NODESC)
1715 return 1;
1716 if (file_printf(ms, "%s", m->desc) == -1)
1717 return -1;
1718 return 1;
1719 case FILE_DER:
1720 case FILE_DEFAULT: /* nothing to check */
1721 case FILE_CLEAR:
1722 default:
1723 break;
1724 }
1725 if (!mconvert(ms, m, flip))
1726 return 0;
1727 return 1;
1728 }
1729
1730 private uint64_t
file_strncmp(const char * s1,const char * s2,size_t len,uint32_t flags)1731 file_strncmp(const char *s1, const char *s2, size_t len, uint32_t flags)
1732 {
1733 /*
1734 * Convert the source args to unsigned here so that (1) the
1735 * compare will be unsigned as it is in strncmp() and (2) so
1736 * the ctype functions will work correctly without extra
1737 * casting.
1738 */
1739 const unsigned char *a = (const unsigned char *)s1;
1740 const unsigned char *b = (const unsigned char *)s2;
1741 const unsigned char *eb = b + len;
1742 uint64_t v;
1743
1744 /*
1745 * What we want here is v = strncmp(s1, s2, len),
1746 * but ignoring any nulls.
1747 */
1748 v = 0;
1749 if (0L == flags) { /* normal string: do it fast */
1750 while (len-- > 0)
1751 if ((v = *b++ - *a++) != '\0')
1752 break;
1753 }
1754 else { /* combine the others */
1755 while (len-- > 0) {
1756 if (b >= eb) {
1757 v = 1;
1758 break;
1759 }
1760 if ((flags & STRING_IGNORE_LOWERCASE) &&
1761 islower(*a)) {
1762 if ((v = tolower(*b++) - *a++) != '\0')
1763 break;
1764 }
1765 else if ((flags & STRING_IGNORE_UPPERCASE) &&
1766 isupper(*a)) {
1767 if ((v = toupper(*b++) - *a++) != '\0')
1768 break;
1769 }
1770 else if ((flags & STRING_COMPACT_WHITESPACE) &&
1771 isspace(*a)) {
1772 a++;
1773 if (isspace(*b++)) {
1774 if (!isspace(*a))
1775 while (b < eb && isspace(*b))
1776 b++;
1777 }
1778 else {
1779 v = 1;
1780 break;
1781 }
1782 }
1783 else if ((flags & STRING_COMPACT_OPTIONAL_WHITESPACE) &&
1784 isspace(*a)) {
1785 a++;
1786 while (b < eb && isspace(*b))
1787 b++;
1788 }
1789 else {
1790 if ((v = *b++ - *a++) != '\0')
1791 break;
1792 }
1793 }
1794 }
1795 return v;
1796 }
1797
1798 private uint64_t
file_strncmp16(const char * a,const char * b,size_t len,uint32_t flags)1799 file_strncmp16(const char *a, const char *b, size_t len, uint32_t flags)
1800 {
1801 /*
1802 * XXX - The 16-bit string compare probably needs to be done
1803 * differently, especially if the flags are to be supported.
1804 * At the moment, I am unsure.
1805 */
1806 flags = 0;
1807 return file_strncmp(a, b, len, flags);
1808 }
1809
1810 public void
convert_libmagic_pattern(zval * pattern,char * val,size_t len,uint32_t options)1811 convert_libmagic_pattern(zval *pattern, char *val, size_t len, uint32_t options)
1812 {
1813 int i, j=0;
1814 zend_string *t;
1815
1816 t = zend_string_alloc(len * 2 + 4, 0);
1817
1818 ZSTR_VAL(t)[j++] = '~';
1819
1820 for (i = 0; i < len; i++, j++) {
1821 switch (val[i]) {
1822 case '~':
1823 ZSTR_VAL(t)[j++] = '\\';
1824 ZSTR_VAL(t)[j] = '~';
1825 break;
1826 default:
1827 ZSTR_VAL(t)[j] = val[i];
1828 break;
1829 }
1830 }
1831 ZSTR_VAL(t)[j++] = '~';
1832
1833 if (options & PCRE2_CASELESS)
1834 ZSTR_VAL(t)[j++] = 'i';
1835
1836 if (options & PCRE2_MULTILINE)
1837 ZSTR_VAL(t)[j++] = 'm';
1838
1839 ZSTR_VAL(t)[j]='\0';
1840 ZSTR_LEN(t) = j;
1841
1842 ZVAL_NEW_STR(pattern, t);
1843 }
1844
1845 private int
magiccheck(struct magic_set * ms,struct magic * m)1846 magiccheck(struct magic_set *ms, struct magic *m)
1847 {
1848 uint64_t l = m->value.q;
1849 uint64_t v;
1850 float fl, fv;
1851 double dl, dv;
1852 int matched;
1853 union VALUETYPE *p = &ms->ms_value;
1854
1855 switch (m->type) {
1856 case FILE_BYTE:
1857 v = p->b;
1858 break;
1859
1860 case FILE_SHORT:
1861 case FILE_BESHORT:
1862 case FILE_LESHORT:
1863 v = p->h;
1864 break;
1865
1866 case FILE_LONG:
1867 case FILE_BELONG:
1868 case FILE_LELONG:
1869 case FILE_MELONG:
1870 case FILE_DATE:
1871 case FILE_BEDATE:
1872 case FILE_LEDATE:
1873 case FILE_MEDATE:
1874 case FILE_LDATE:
1875 case FILE_BELDATE:
1876 case FILE_LELDATE:
1877 case FILE_MELDATE:
1878 v = p->l;
1879 break;
1880
1881 case FILE_QUAD:
1882 case FILE_LEQUAD:
1883 case FILE_BEQUAD:
1884 case FILE_QDATE:
1885 case FILE_BEQDATE:
1886 case FILE_LEQDATE:
1887 case FILE_QLDATE:
1888 case FILE_BEQLDATE:
1889 case FILE_LEQLDATE:
1890 case FILE_QWDATE:
1891 case FILE_BEQWDATE:
1892 case FILE_LEQWDATE:
1893 v = p->q;
1894 break;
1895
1896 case FILE_FLOAT:
1897 case FILE_BEFLOAT:
1898 case FILE_LEFLOAT:
1899 fl = m->value.f;
1900 fv = p->f;
1901 switch (m->reln) {
1902 case 'x':
1903 matched = 1;
1904 break;
1905
1906 case '!':
1907 matched = fv != fl;
1908 break;
1909
1910 case '=':
1911 matched = fv == fl;
1912 break;
1913
1914 case '>':
1915 matched = fv > fl;
1916 break;
1917
1918 case '<':
1919 matched = fv < fl;
1920 break;
1921
1922 default:
1923 file_magerror(ms, "cannot happen with float: invalid relation `%c'",
1924 m->reln);
1925 return -1;
1926 }
1927 return matched;
1928
1929 case FILE_DOUBLE:
1930 case FILE_BEDOUBLE:
1931 case FILE_LEDOUBLE:
1932 dl = m->value.d;
1933 dv = p->d;
1934 switch (m->reln) {
1935 case 'x':
1936 matched = 1;
1937 break;
1938
1939 case '!':
1940 matched = dv != dl;
1941 break;
1942
1943 case '=':
1944 matched = dv == dl;
1945 break;
1946
1947 case '>':
1948 matched = dv > dl;
1949 break;
1950
1951 case '<':
1952 matched = dv < dl;
1953 break;
1954
1955 default:
1956 file_magerror(ms, "cannot happen with double: invalid relation `%c'", m->reln);
1957 return -1;
1958 }
1959 return matched;
1960
1961 case FILE_DEFAULT:
1962 case FILE_CLEAR:
1963 l = 0;
1964 v = 0;
1965 break;
1966
1967 case FILE_STRING:
1968 case FILE_PSTRING:
1969 l = 0;
1970 v = file_strncmp(m->value.s, p->s, (size_t)m->vallen, m->str_flags);
1971 break;
1972
1973 case FILE_BESTRING16:
1974 case FILE_LESTRING16:
1975 l = 0;
1976 v = file_strncmp16(m->value.s, p->s, (size_t)m->vallen, m->str_flags);
1977 break;
1978
1979 case FILE_SEARCH: { /* search ms->search.s for the string m->value.s */
1980 size_t slen;
1981 size_t idx;
1982
1983 if (ms->search.s == NULL)
1984 return 0;
1985
1986 slen = MIN(m->vallen, sizeof(m->value.s));
1987 l = 0;
1988 v = 0;
1989
1990 for (idx = 0; m->str_range == 0 || idx < m->str_range; idx++) {
1991 if (slen + idx > ms->search.s_len)
1992 return 0;
1993
1994 v = file_strncmp(m->value.s, ms->search.s + idx, slen,
1995 m->str_flags);
1996 if (v == 0) { /* found match */
1997 ms->search.offset += idx;
1998 ms->search.rm_len = ms->search.s_len - idx;
1999 break;
2000 }
2001 }
2002 break;
2003 }
2004 case FILE_REGEX: {
2005 zval pattern;
2006 uint32_t options = 0;
2007 pcre_cache_entry *pce;
2008
2009 options |= PCRE2_MULTILINE;
2010
2011 if (m->str_flags & STRING_IGNORE_CASE) {
2012 options |= PCRE2_CASELESS;
2013 }
2014
2015 convert_libmagic_pattern(&pattern, (char *)m->value.s, m->vallen, options);
2016
2017 l = v = 0;
2018 if ((pce = pcre_get_compiled_regex_cache(Z_STR(pattern))) == NULL) {
2019 zval_ptr_dtor(&pattern);
2020 return -1;
2021 } else {
2022 /* pce now contains the compiled regex */
2023 zval retval;
2024 zval subpats;
2025 char *haystack;
2026
2027 ZVAL_NULL(&retval);
2028 ZVAL_NULL(&subpats);
2029
2030 /* Cut the search len from haystack, equals to REG_STARTEND */
2031 haystack = estrndup(ms->search.s, ms->search.s_len);
2032
2033 /* match v = 0, no match v = 1 */
2034 php_pcre_match_impl(pce, haystack, ms->search.s_len, &retval, &subpats, 0, 1, PREG_OFFSET_CAPTURE, 0);
2035 /* Free haystack */
2036 efree(haystack);
2037
2038 if (Z_LVAL(retval) < 0) {
2039 zval_ptr_dtor(&subpats);
2040 zval_ptr_dtor(&pattern);
2041 return -1;
2042 } else if ((Z_LVAL(retval) > 0) && (Z_TYPE(subpats) == IS_ARRAY)) {
2043 /* Need to fetch global match which equals pmatch[0] */
2044 zval *pzval;
2045 HashTable *ht = Z_ARRVAL(subpats);
2046 if ((pzval = zend_hash_index_find(ht, 0)) != NULL && Z_TYPE_P(pzval) == IS_ARRAY) {
2047 /* If everything goes according to the master plan
2048 tmpcopy now contains two elements:
2049 0 = the match
2050 1 = starting position of the match */
2051 zval *match, *offset;
2052 if ((match = zend_hash_index_find(Z_ARRVAL_P(pzval), 0)) &&
2053 (offset = zend_hash_index_find(Z_ARRVAL_P(pzval), 1))) {
2054 if (Z_TYPE_P(match) != IS_STRING && Z_TYPE_P(offset) != IS_LONG) {
2055 goto error_out;
2056 }
2057 ms->search.s += Z_LVAL_P(offset); /* this is where the match starts */
2058 ms->search.offset += Z_LVAL_P(offset); /* this is where the match starts as size_t */
2059 ms->search.rm_len = Z_STRLEN_P(match) /* This is the length of the matched pattern */;
2060 v = 0;
2061 } else {
2062 goto error_out;
2063 }
2064 } else {
2065 error_out:
2066 zval_ptr_dtor(&subpats);
2067 zval_ptr_dtor(&pattern);
2068 return -1;
2069 }
2070 } else {
2071 v = 1;
2072 }
2073 zval_ptr_dtor(&subpats);
2074 zval_ptr_dtor(&pattern);
2075 }
2076 break;
2077 }
2078 case FILE_INDIRECT:
2079 case FILE_USE:
2080 case FILE_NAME:
2081 return 1;
2082 case FILE_DER:
2083 matched = der_cmp(ms, m);
2084 if (matched == -1) {
2085 if ((ms->flags & MAGIC_DEBUG) != 0) {
2086 (void) fprintf(stderr,
2087 "EOF comparing DER entries");
2088 }
2089 return 0;
2090 }
2091 return matched;
2092 default:
2093 file_magerror(ms, "invalid type %d in magiccheck()", m->type);
2094 return -1;
2095 }
2096
2097 v = file_signextend(ms, m, v);
2098
2099 switch (m->reln) {
2100 case 'x':
2101 if ((ms->flags & MAGIC_DEBUG) != 0)
2102 (void) fprintf(stderr, "%" INT64_T_FORMAT
2103 "u == *any* = 1\n", (unsigned long long)v);
2104 matched = 1;
2105 break;
2106
2107 case '!':
2108 matched = v != l;
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);
2113 break;
2114
2115 case '=':
2116 matched = v == l;
2117 if ((ms->flags & MAGIC_DEBUG) != 0)
2118 (void) fprintf(stderr, "%" INT64_T_FORMAT "u == %"
2119 INT64_T_FORMAT "u = %d\n", (unsigned long long)v,
2120 (unsigned long long)l, matched);
2121 break;
2122
2123 case '>':
2124 if (m->flag & UNSIGNED) {
2125 matched = v > l;
2126 if ((ms->flags & MAGIC_DEBUG) != 0)
2127 (void) fprintf(stderr, "%" INT64_T_FORMAT
2128 "u > %" INT64_T_FORMAT "u = %d\n",
2129 (unsigned long long)v,
2130 (unsigned long long)l, matched);
2131 }
2132 else {
2133 matched = (int64_t) v > (int64_t) l;
2134 if ((ms->flags & MAGIC_DEBUG) != 0)
2135 (void) fprintf(stderr, "%" INT64_T_FORMAT
2136 "d > %" INT64_T_FORMAT "d = %d\n",
2137 (long long)v, (long long)l, matched);
2138 }
2139 break;
2140
2141 case '<':
2142 if (m->flag & UNSIGNED) {
2143 matched = v < l;
2144 if ((ms->flags & MAGIC_DEBUG) != 0)
2145 (void) fprintf(stderr, "%" INT64_T_FORMAT
2146 "u < %" INT64_T_FORMAT "u = %d\n",
2147 (unsigned long long)v,
2148 (unsigned long long)l, matched);
2149 }
2150 else {
2151 matched = (int64_t) v < (int64_t) l;
2152 if ((ms->flags & MAGIC_DEBUG) != 0)
2153 (void) fprintf(stderr, "%" INT64_T_FORMAT
2154 "d < %" INT64_T_FORMAT "d = %d\n",
2155 (long long)v, (long long)l, matched);
2156 }
2157 break;
2158
2159 case '&':
2160 matched = (v & l) == l;
2161 if ((ms->flags & MAGIC_DEBUG) != 0)
2162 (void) fprintf(stderr, "((%" INT64_T_FORMAT "x & %"
2163 INT64_T_FORMAT "x) == %" INT64_T_FORMAT
2164 "x) = %d\n", (unsigned long long)v,
2165 (unsigned long long)l, (unsigned long long)l,
2166 matched);
2167 break;
2168
2169 case '^':
2170 matched = (v & l) != l;
2171 if ((ms->flags & MAGIC_DEBUG) != 0)
2172 (void) fprintf(stderr, "((%" INT64_T_FORMAT "x & %"
2173 INT64_T_FORMAT "x) != %" INT64_T_FORMAT
2174 "x) = %d\n", (unsigned long long)v,
2175 (unsigned long long)l, (unsigned long long)l,
2176 matched);
2177 break;
2178
2179 default:
2180 file_magerror(ms, "cannot happen: invalid relation `%c'",
2181 m->reln);
2182 return -1;
2183 }
2184
2185 return matched;
2186 }
2187
2188 private int
handle_annotation(struct magic_set * ms,struct magic * m,const struct buffer * b,int firstline)2189 handle_annotation(struct magic_set *ms, struct magic *m, const struct buffer *b,
2190 int firstline)
2191 {
2192 if ((ms->flags & MAGIC_APPLE) && m->apple[0]) {
2193 if (!firstline && file_printf(ms, "\n- ") == -1)
2194 return -1;
2195 if (file_printf(ms, "%.8s", m->apple) == -1)
2196 return -1;
2197 return 1;
2198 }
2199 if ((ms->flags & MAGIC_EXTENSION) && m->ext[0]) {
2200 if (!firstline && file_printf(ms, "\n- ") == -1)
2201 return -1;
2202 if (file_printf(ms, "%s", m->ext) == -1)
2203 return -1;
2204 return 1;
2205 }
2206 if ((ms->flags & MAGIC_MIME_TYPE) && m->mimetype[0]) {
2207 char buf[1024];
2208 const char *p;
2209 if (!firstline && file_printf(ms, "\n- ") == -1)
2210 return -1;
2211 if (varexpand(buf, sizeof(buf), b, m->mimetype) == -1)
2212 p = m->mimetype;
2213 else
2214 p = buf;
2215 if (file_printf(ms, "%s", p) == -1)
2216 return -1;
2217 return 1;
2218 }
2219 return 0;
2220 }
2221
2222 private int
print_sep(struct magic_set * ms,int firstline)2223 print_sep(struct magic_set *ms, int firstline)
2224 {
2225 // if (ms->flags & MAGIC_NODESC)
2226 // return 0;
2227 if (firstline)
2228 return 0;
2229 /*
2230 * we found another match
2231 * put a newline and '-' to do some simple formatting
2232 */
2233 return file_printf(ms, "\n- ");
2234 }
2235