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