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