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