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