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