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