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