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