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