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