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