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