Annotation of src/usr.bin/file/magic-test.c, Revision 1.18
1.18 ! nicm 1: /* $OpenBSD: magic-test.c,v 1.17 2016/04/30 21:10:28 nicm Exp $ */
1.1 nicm 2:
3: /*
4: * Copyright (c) 2015 Nicholas Marriott <nicm@openbsd.org>
5: *
6: * Permission to use, copy, modify, and distribute this software for any
7: * purpose with or without fee is hereby granted, provided that the above
8: * copyright notice and this permission notice appear in all copies.
9: *
10: * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11: * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12: * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13: * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14: * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
15: * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
16: * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17: */
18:
19: #include <sys/types.h>
20:
21: #include <ctype.h>
22: #include <errno.h>
23: #include <fcntl.h>
24: #include <limits.h>
25: #include <stdarg.h>
26: #include <stdio.h>
27: #include <stdint.h>
28: #include <stdlib.h>
29: #include <string.h>
30: #include <unistd.h>
31: #include <vis.h>
32:
33: #include "magic.h"
34: #include "xmalloc.h"
35:
36: static int
37: magic_one_eq(char a, char b, int cflag)
38: {
39: if (a == b)
40: return (1);
1.4 nicm 41: if (cflag && islower((u_char)b) && tolower((u_char)a) == (u_char)b)
1.1 nicm 42: return (1);
43: return (0);
44: }
45:
46: static int
47: magic_test_eq(const char *ap, size_t asize, const char *bp, size_t bsize,
48: int cflag, int bflag, int Bflag)
49: {
50: size_t aoff, boff, aspaces, bspaces;
51:
52: aoff = boff = 0;
53: while (aoff != asize && boff != bsize) {
54: if (Bflag && isspace((u_char)ap[aoff])) {
55: aspaces = 0;
56: while (aoff != asize && isspace((u_char)ap[aoff])) {
57: aspaces++;
58: aoff++;
59: }
60: bspaces = 0;
61: while (boff != bsize && isspace((u_char)bp[boff])) {
62: bspaces++;
63: boff++;
64: }
65: if (bspaces >= aspaces)
66: continue;
67: return (1);
68: }
69: if (magic_one_eq(ap[aoff], bp[boff], cflag)) {
70: aoff++;
71: boff++;
72: continue;
73: }
74: if (bflag && isspace((u_char)bp[boff])) {
75: boff++;
76: continue;
77: }
78: if (ap[aoff] < bp[boff])
79: return (-1);
80: return (1);
81: }
82: return (0);
83: }
84:
85: static int
86: magic_copy_from(struct magic_state *ms, ssize_t offset, void *dst, size_t size)
87: {
88: if (offset < 0)
89: offset = ms->offset;
90: if (offset + size > ms->size)
91: return (-1);
92: memcpy(dst, ms->base + offset, size);
93: return (0);
94: }
95:
96: static void
97: magic_add_result(struct magic_state *ms, struct magic_line *ml,
98: const char *fmt, ...)
99: {
100: va_list ap;
101: int separate;
102: char *s, *tmp, *add;
103:
104: va_start(ap, fmt);
105: if (ml->stringify) {
106: if (vasprintf(&s, fmt, ap) == -1) {
107: va_end(ap);
108: return;
109: }
110: va_end(ap);
111: if (asprintf(&tmp, ml->result, s) == -1) {
112: free(s);
113: return;
114: }
115: free(s);
116: } else {
117: if (vasprintf(&tmp, ml->result, ap) == -1) {
118: va_end(ap);
119: return;
120: }
121: va_end(ap);
122: }
123:
124: separate = 1;
125: if (tmp[0] == '\\' && tmp[1] == 'b') {
126: separate = 0;
127: add = tmp + 2;
128: } else
129: add = tmp;
130:
131: if (separate && *ms->out != '\0')
132: strlcat(ms->out, " ", sizeof ms->out);
133: strlcat(ms->out, add, sizeof ms->out);
134:
135: free(tmp);
136: }
137:
138: static void
139: magic_add_string(struct magic_state *ms, struct magic_line *ml,
1.2 deraadt 140: const char *s, size_t slen)
1.1 nicm 141: {
142: char *out;
143: size_t outlen, offset;
144:
145: outlen = MAGIC_STRING_SIZE;
146: if (outlen > slen)
147: outlen = slen;
148: for (offset = 0; offset < outlen; offset++) {
149: if (s[offset] == '\0' || !isprint((u_char)s[offset])) {
150: outlen = offset;
151: break;
152: }
153: }
154: out = xreallocarray(NULL, 4, outlen + 1);
155: strvisx(out, s, outlen, VIS_TAB|VIS_NL|VIS_CSTYLE|VIS_OCTAL);
156: magic_add_result(ms, ml, "%s", out);
157: free(out);
158: }
159:
160: static int
161: magic_test_signed(struct magic_line *ml, int64_t value, int64_t wanted)
162: {
163: switch (ml->test_operator) {
164: case 'x':
165: return (1);
166: case '<':
167: return (value < wanted);
168: case '[':
169: return (value <= wanted);
170: case '>':
171: return (value > wanted);
172: case ']':
173: return (value >= wanted);
174: case '=':
175: return (value == wanted);
176: case '&':
177: return ((value & wanted) == wanted);
178: case '^':
179: return ((~value & wanted) == wanted);
180: }
181: return (-1);
182: }
183:
184: static int
185: magic_test_unsigned(struct magic_line *ml, uint64_t value, uint64_t wanted)
186: {
187: switch (ml->test_operator) {
188: case 'x':
189: return (1);
190: case '<':
191: return (value < wanted);
192: case '[':
193: return (value <= wanted);
194: case '>':
195: return (value > wanted);
196: case ']':
197: return (value >= wanted);
198: case '=':
199: return (value == wanted);
200: case '&':
201: return ((value & wanted) == wanted);
202: case '^':
203: return ((~value & wanted) == wanted);
204: }
205: return (-1);
206: }
207:
208: static int
1.7 nicm 209: magic_test_double(struct magic_line *ml, double value, double wanted)
210: {
211: switch (ml->test_operator) {
212: case 'x':
213: return (1);
214: case '=':
215: return (value == wanted);
216: }
217: return (-1);
218: }
219:
220: static int
1.1 nicm 221: magic_test_type_none(__unused struct magic_line *ml,
222: __unused struct magic_state *ms)
223: {
224: return (0);
225: }
226:
227: static int
228: magic_test_type_byte(struct magic_line *ml, struct magic_state *ms)
229: {
230: int8_t value;
231: int result;
232:
233: if (magic_copy_from(ms, -1, &value, sizeof value) != 0)
234: return (0);
235:
236: if (ml->type_operator == '&')
237: value &= (int8_t)ml->type_operand;
1.8 nicm 238: else if (ml->type_operator == '-')
239: value -= (int8_t)ml->type_operand;
240: else if (ml->type_operator == '+')
241: value += (int8_t)ml->type_operand;
242: else if (ml->type_operator == '/')
243: value /= (int8_t)ml->type_operand;
244: else if (ml->type_operator == '%')
245: value %= (int8_t)ml->type_operand;
246: else if (ml->type_operator == '*')
247: value *= (int8_t)ml->type_operand;
1.1 nicm 248: else if (ml->type_operator != ' ')
249: return (-1);
250:
251: result = magic_test_signed(ml, value, (int8_t)ml->test_signed);
252: if (result == !ml->test_not && ml->result != NULL) {
253: magic_add_result(ms, ml, "%c", (int)value);
254: ms->offset += sizeof value;
255: }
256: return (result);
257: }
258:
259: static int
260: magic_test_type_short(struct magic_line *ml, struct magic_state *ms)
261: {
262: int16_t value;
263: int result;
264:
265: if (magic_copy_from(ms, -1, &value, sizeof value) != 0)
266: return (0);
267: if (ml->type == MAGIC_TYPE_BESHORT)
1.3 brynet 268: value = be16toh(value);
1.1 nicm 269: if (ml->type == MAGIC_TYPE_LESHORT)
1.3 brynet 270: value = le16toh(value);
1.1 nicm 271:
272: if (ml->type_operator == '&')
273: value &= (int16_t)ml->type_operand;
1.8 nicm 274: else if (ml->type_operator == '-')
275: value -= (int16_t)ml->type_operand;
276: else if (ml->type_operator == '+')
277: value += (int16_t)ml->type_operand;
278: else if (ml->type_operator == '/')
279: value /= (int16_t)ml->type_operand;
280: else if (ml->type_operator == '%')
281: value %= (int16_t)ml->type_operand;
282: else if (ml->type_operator == '*')
283: value *= (int16_t)ml->type_operand;
1.1 nicm 284: else if (ml->type_operator != ' ')
285: return (-1);
286:
287: result = magic_test_signed(ml, value, (int16_t)ml->test_signed);
288: if (result == !ml->test_not && ml->result != NULL) {
289: magic_add_result(ms, ml, "%hd", (int)value);
290: ms->offset += sizeof value;
291: }
292: return (result);
293: }
294:
295: static int
296: magic_test_type_long(struct magic_line *ml, struct magic_state *ms)
297: {
298: int32_t value;
299: int result;
300:
301: if (magic_copy_from(ms, -1, &value, sizeof value) != 0)
302: return (0);
303: if (ml->type == MAGIC_TYPE_BELONG)
1.3 brynet 304: value = be32toh(value);
1.1 nicm 305: if (ml->type == MAGIC_TYPE_LELONG)
1.3 brynet 306: value = le32toh(value);
1.1 nicm 307:
308: if (ml->type_operator == '&')
309: value &= (int32_t)ml->type_operand;
1.8 nicm 310: else if (ml->type_operator == '-')
311: value -= (int32_t)ml->type_operand;
312: else if (ml->type_operator == '+')
313: value += (int32_t)ml->type_operand;
314: else if (ml->type_operator == '/')
315: value /= (int32_t)ml->type_operand;
316: else if (ml->type_operator == '%')
317: value %= (int32_t)ml->type_operand;
318: else if (ml->type_operator == '*')
319: value *= (int32_t)ml->type_operand;
1.1 nicm 320: else if (ml->type_operator != ' ')
321: return (-1);
322:
323: result = magic_test_signed(ml, value, (int32_t)ml->test_signed);
324: if (result == !ml->test_not && ml->result != NULL) {
325: magic_add_result(ms, ml, "%d", (int)value);
326: ms->offset += sizeof value;
327: }
328: return (result);
329: }
330:
331: static int
332: magic_test_type_quad(struct magic_line *ml, struct magic_state *ms)
333: {
334: int64_t value;
335: int result;
336:
337: if (magic_copy_from(ms, -1, &value, sizeof value) != 0)
338: return (0);
339: if (ml->type == MAGIC_TYPE_BEQUAD)
1.3 brynet 340: value = be64toh(value);
1.1 nicm 341: if (ml->type == MAGIC_TYPE_LEQUAD)
1.3 brynet 342: value = le64toh(value);
1.1 nicm 343:
344: if (ml->type_operator == '&')
345: value &= (int64_t)ml->type_operand;
1.8 nicm 346: else if (ml->type_operator == '-')
347: value -= (int64_t)ml->type_operand;
348: else if (ml->type_operator == '+')
349: value += (int64_t)ml->type_operand;
350: else if (ml->type_operator == '/')
351: value /= (int64_t)ml->type_operand;
352: else if (ml->type_operator == '%')
353: value %= (int64_t)ml->type_operand;
354: else if (ml->type_operator == '*')
355: value *= (int64_t)ml->type_operand;
1.1 nicm 356: else if (ml->type_operator != ' ')
357: return (-1);
358:
359: result = magic_test_signed(ml, value, (int64_t)ml->test_signed);
360: if (result == !ml->test_not && ml->result != NULL) {
361: magic_add_result(ms, ml, "%lld", (long long)value);
362: ms->offset += sizeof value;
363: }
364: return (result);
365: }
366:
367: static int
368: magic_test_type_ubyte(struct magic_line *ml, struct magic_state *ms)
369: {
370: uint8_t value;
371: int result;
372:
373: if (magic_copy_from(ms, -1, &value, sizeof value) != 0)
374: return (0);
375:
376: if (ml->type_operator == '&')
377: value &= (uint8_t)ml->type_operand;
1.8 nicm 378: else if (ml->type_operator == '-')
379: value -= (uint8_t)ml->type_operand;
380: else if (ml->type_operator == '+')
381: value += (uint8_t)ml->type_operand;
382: else if (ml->type_operator == '/')
383: value /= (uint8_t)ml->type_operand;
384: else if (ml->type_operator == '%')
385: value %= (uint8_t)ml->type_operand;
386: else if (ml->type_operator == '*')
387: value *= (uint8_t)ml->type_operand;
1.1 nicm 388: else if (ml->type_operator != ' ')
389: return (-1);
390:
391: result = magic_test_unsigned(ml, value, (uint8_t)ml->test_unsigned);
392: if (result == !ml->test_not && ml->result != NULL) {
393: magic_add_result(ms, ml, "%c", (unsigned int)value);
394: ms->offset += sizeof value;
395: }
396: return (result);
397: }
398:
399: static int
400: magic_test_type_ushort(struct magic_line *ml, struct magic_state *ms)
401: {
402: uint16_t value;
403: int result;
404:
405: if (magic_copy_from(ms, -1, &value, sizeof value) != 0)
406: return (0);
407: if (ml->type == MAGIC_TYPE_UBESHORT)
1.3 brynet 408: value = be16toh(value);
1.1 nicm 409: if (ml->type == MAGIC_TYPE_ULESHORT)
1.3 brynet 410: value = le16toh(value);
1.1 nicm 411:
412: if (ml->type_operator == '&')
413: value &= (uint16_t)ml->type_operand;
1.8 nicm 414: else if (ml->type_operator == '-')
415: value -= (uint16_t)ml->type_operand;
416: else if (ml->type_operator == '+')
417: value += (uint16_t)ml->type_operand;
418: else if (ml->type_operator == '/')
419: value /= (uint16_t)ml->type_operand;
420: else if (ml->type_operator == '%')
421: value %= (uint16_t)ml->type_operand;
422: else if (ml->type_operator == '*')
423: value *= (uint16_t)ml->type_operand;
1.1 nicm 424: else if (ml->type_operator != ' ')
425: return (-1);
426:
427: result = magic_test_unsigned(ml, value, (uint16_t)ml->test_unsigned);
428: if (result == !ml->test_not && ml->result != NULL) {
429: magic_add_result(ms, ml, "%hu", (unsigned int)value);
430: ms->offset += sizeof value;
431: }
432: return (result);
433: }
434:
435: static int
436: magic_test_type_ulong(struct magic_line *ml, struct magic_state *ms)
437: {
438: uint32_t value;
439: int result;
440:
441: if (magic_copy_from(ms, -1, &value, sizeof value) != 0)
442: return (0);
443: if (ml->type == MAGIC_TYPE_UBELONG)
1.3 brynet 444: value = be32toh(value);
1.1 nicm 445: if (ml->type == MAGIC_TYPE_ULELONG)
1.3 brynet 446: value = le32toh(value);
1.1 nicm 447:
448: if (ml->type_operator == '&')
449: value &= (uint32_t)ml->type_operand;
1.8 nicm 450: else if (ml->type_operator == '-')
451: value -= (uint32_t)ml->type_operand;
452: else if (ml->type_operator == '+')
453: value += (uint32_t)ml->type_operand;
454: else if (ml->type_operator == '/')
455: value /= (uint32_t)ml->type_operand;
456: else if (ml->type_operator == '%')
457: value %= (uint32_t)ml->type_operand;
458: else if (ml->type_operator == '*')
459: value *= (uint32_t)ml->type_operand;
1.1 nicm 460: else if (ml->type_operator != ' ')
461: return (-1);
462:
463: result = magic_test_unsigned(ml, value, (uint32_t)ml->test_unsigned);
464: if (result == !ml->test_not && ml->result != NULL) {
465: magic_add_result(ms, ml, "%u", (unsigned int)value);
466: ms->offset += sizeof value;
467: }
468: return (result);
469: }
470:
471: static int
472: magic_test_type_uquad(struct magic_line *ml, struct magic_state *ms)
473: {
474: uint64_t value;
475: int result;
476:
477: if (magic_copy_from(ms, -1, &value, sizeof value) != 0)
478: return (0);
479: if (ml->type == MAGIC_TYPE_UBEQUAD)
1.3 brynet 480: value = be64toh(value);
1.1 nicm 481: if (ml->type == MAGIC_TYPE_ULEQUAD)
1.3 brynet 482: value = le64toh(value);
1.1 nicm 483:
484: if (ml->type_operator == '&')
485: value &= (uint64_t)ml->type_operand;
1.8 nicm 486: else if (ml->type_operator == '-')
487: value -= (uint64_t)ml->type_operand;
488: else if (ml->type_operator == '+')
489: value += (uint64_t)ml->type_operand;
490: else if (ml->type_operator == '/')
491: value /= (uint64_t)ml->type_operand;
492: else if (ml->type_operator == '%')
493: value %= (uint64_t)ml->type_operand;
494: else if (ml->type_operator == '*')
495: value *= (uint64_t)ml->type_operand;
1.1 nicm 496: else if (ml->type_operator != ' ')
497: return (-1);
498:
499: result = magic_test_unsigned(ml, value, (uint64_t)ml->test_unsigned);
500: if (result == !ml->test_not && ml->result != NULL) {
501: magic_add_result(ms, ml, "%llu", (unsigned long long)value);
502: ms->offset += sizeof value;
503: }
504: return (result);
505: }
506:
507: static int
508: magic_test_type_float(struct magic_line *ml, struct magic_state *ms)
509: {
510: uint32_t value0;
1.16 nicm 511: float value;
1.7 nicm 512: int result;
1.1 nicm 513:
514: if (magic_copy_from(ms, -1, &value0, sizeof value0) != 0)
515: return (0);
516: if (ml->type == MAGIC_TYPE_BEFLOAT)
1.3 brynet 517: value0 = be32toh(value0);
1.1 nicm 518: if (ml->type == MAGIC_TYPE_LEFLOAT)
1.3 brynet 519: value0 = le32toh(value0);
1.1 nicm 520: memcpy(&value, &value0, sizeof value);
521:
522: if (ml->type_operator != ' ')
523: return (-1);
524:
1.7 nicm 525: result = magic_test_double(ml, value, (float)ml->test_double);
526: if (result == !ml->test_not && ml->result != NULL) {
527: magic_add_result(ms, ml, "%g", value);
528: ms->offset += sizeof value0;
529: }
1.1 nicm 530: return (1);
531: }
532:
533: static int
534: magic_test_type_double(struct magic_line *ml, struct magic_state *ms)
535: {
536: uint64_t value0;
537: double value;
1.7 nicm 538: int result;
1.1 nicm 539:
540: if (magic_copy_from(ms, -1, &value0, sizeof value0) != 0)
541: return (0);
542: if (ml->type == MAGIC_TYPE_BEDOUBLE)
1.3 brynet 543: value0 = be64toh(value0);
1.1 nicm 544: if (ml->type == MAGIC_TYPE_LEDOUBLE)
1.3 brynet 545: value0 = le64toh(value0);
1.1 nicm 546: memcpy(&value, &value0, sizeof value);
547:
548: if (ml->type_operator != ' ')
549: return (-1);
550:
1.7 nicm 551: result = magic_test_double(ml, value, (double)ml->test_double);
552: if (result == !ml->test_not && ml->result != NULL) {
553: magic_add_result(ms, ml, "%g", value);
554: ms->offset += sizeof value0;
555: }
1.1 nicm 556: return (1);
557: }
558:
559: static int
560: magic_test_type_string(struct magic_line *ml, struct magic_state *ms)
561: {
562: const char *s, *cp;
563: size_t slen;
564: int result, cflag = 0, bflag = 0, Bflag = 0;
565:
566: cp = &ml->type_string[(sizeof "string") - 1];
567: if (*cp != '\0') {
568: if (*cp != '/')
569: return (-1);
570: cp++;
571: for (; *cp != '\0'; cp++) {
572: switch (*cp) {
573: case 'B':
1.11 nicm 574: case 'W':
1.1 nicm 575: Bflag = 1;
576: break;
577: case 'b':
1.11 nicm 578: case 'w':
1.1 nicm 579: bflag = 1;
580: break;
581: case 'c':
582: cflag = 1;
583: break;
1.11 nicm 584: case 't':
585: break;
1.1 nicm 586: default:
587: return (-1);
588: }
589: }
590: }
591:
592: s = ms->base + ms->offset;
593: slen = ms->size - ms->offset;
594: if (slen < ml->test_string_size)
595: return (0);
596:
597: result = magic_test_eq(s, slen, ml->test_string, ml->test_string_size,
598: cflag, bflag, Bflag);
599: switch (ml->test_operator) {
600: case 'x':
601: result = 1;
602: break;
603: case '<':
604: result = result < 0;
605: break;
606: case '>':
607: result = result > 0;
608: break;
609: case '=':
1.10 nicm 610: slen = ml->test_string_size; /* only print what was found */
1.1 nicm 611: result = result == 0;
612: break;
613: default:
614: result = -1;
615: break;
616: }
617: if (result == !ml->test_not) {
618: if (ml->result != NULL)
619: magic_add_string(ms, ml, s, slen);
620: if (result && ml->test_operator == '=')
621: ms->offset = s - ms->base + ml->test_string_size;
622: }
623: return (result);
624: }
625:
626: static int
627: magic_test_type_pstring(struct magic_line *ml, struct magic_state *ms)
628: {
1.9 nicm 629: const char *s, *cp;
1.1 nicm 630: size_t slen;
631: int result;
1.9 nicm 632:
633: cp = &ml->type_string[(sizeof "pstring") - 1];
634: if (*cp != '\0') {
635: if (*cp != '/')
636: return (-1);
637: cp++;
638: for (; *cp != '\0'; cp++) {
639: switch (*cp) {
640: default:
641: return (-1);
642: }
643: }
644: }
1.1 nicm 645:
646: s = ms->base + ms->offset;
647: if (ms->size - ms->offset < 1)
648: return (-1);
649: slen = *(u_char *)s;
650: if (slen > ms->size - ms->offset)
651: return (-1);
652: s++;
653:
654: if (slen < ml->test_string_size)
655: result = -1;
656: else if (slen > ml->test_string_size)
657: result = 1;
658: else
659: result = memcmp(s, ml->test_string, ml->test_string_size);
660: switch (ml->test_operator) {
661: case 'x':
662: result = 1;
663: break;
664: case '<':
665: result = result < 0;
666: break;
667: case '>':
668: result = result > 0;
669: break;
670: case '=':
671: result = result == 0;
672: break;
673: default:
674: result = -1;
675: break;
676: }
677: if (result == !ml->test_not) {
678: if (ml->result != NULL)
679: magic_add_string(ms, ml, s, slen);
1.12 nicm 680: if (result && ml->test_operator == '=')
1.1 nicm 681: ms->offset += slen + 1;
682: }
683: return (result);
684: }
685:
686: static int
687: magic_test_type_date(struct magic_line *ml, struct magic_state *ms)
688: {
689: int32_t value;
690: int result;
691: time_t t;
692: char s[64];
693:
694: if (magic_copy_from(ms, -1, &value, sizeof value) != 0)
695: return (0);
696: if (ml->type == MAGIC_TYPE_BEDATE ||
697: ml->type == MAGIC_TYPE_BELDATE)
1.3 brynet 698: value = be32toh(value);
1.1 nicm 699: if (ml->type == MAGIC_TYPE_LEDATE ||
700: ml->type == MAGIC_TYPE_LELDATE)
1.3 brynet 701: value = le32toh(value);
1.1 nicm 702:
703: if (ml->type_operator == '&')
704: value &= (int32_t)ml->type_operand;
1.13 nicm 705: else if (ml->type_operator == '-')
706: value -= (int32_t)ml->type_operand;
707: else if (ml->type_operator == '+')
708: value += (int32_t)ml->type_operand;
1.1 nicm 709: else if (ml->type_operator != ' ')
710: return (-1);
711:
712: result = magic_test_signed(ml, value, (int32_t)ml->test_signed);
713: if (result == !ml->test_not && ml->result != NULL) {
714: t = value;
715: switch (ml->type) {
716: case MAGIC_TYPE_LDATE:
717: case MAGIC_TYPE_LELDATE:
718: case MAGIC_TYPE_BELDATE:
719: ctime_r(&t, s);
720: break;
721: default:
1.6 nicm 722: asctime_r(gmtime(&t), s);
1.1 nicm 723: break;
724: }
725: s[strcspn(s, "\n")] = '\0';
726: magic_add_result(ms, ml, "%s", s);
727: ms->offset += sizeof value;
728: }
729: return (result);
730: }
731:
732: static int
733: magic_test_type_qdate(struct magic_line *ml, struct magic_state *ms)
734: {
735: int64_t value;
736: int result;
737: time_t t;
738: char s[64];
739:
740: if (magic_copy_from(ms, -1, &value, sizeof value) != 0)
741: return (0);
742: if (ml->type == MAGIC_TYPE_BEQDATE ||
743: ml->type == MAGIC_TYPE_BEQLDATE)
1.3 brynet 744: value = be64toh(value);
1.1 nicm 745: if (ml->type == MAGIC_TYPE_LEQDATE ||
746: ml->type == MAGIC_TYPE_LEQLDATE)
1.3 brynet 747: value = le64toh(value);
1.1 nicm 748:
749: if (ml->type_operator == '&')
750: value &= (int64_t)ml->type_operand;
1.13 nicm 751: else if (ml->type_operator == '-')
752: value -= (int64_t)ml->type_operand;
753: else if (ml->type_operator == '+')
754: value += (int64_t)ml->type_operand;
1.1 nicm 755: else if (ml->type_operator != ' ')
756: return (-1);
757:
758: result = magic_test_signed(ml, value, (int64_t)ml->test_signed);
759: if (result == !ml->test_not && ml->result != NULL) {
760: t = value;
761: switch (ml->type) {
762: case MAGIC_TYPE_QLDATE:
763: case MAGIC_TYPE_LEQLDATE:
764: case MAGIC_TYPE_BEQLDATE:
765: ctime_r(&t, s);
766: break;
767: default:
1.6 nicm 768: asctime_r(gmtime(&t), s);
1.1 nicm 769: break;
770: }
771: s[strcspn(s, "\n")] = '\0';
772: magic_add_result(ms, ml, "%s", s);
773: ms->offset += sizeof value;
774: }
775: return (result);
776: }
777:
778: static int
779: magic_test_type_udate(struct magic_line *ml, struct magic_state *ms)
780: {
781: uint32_t value;
782: int result;
783: time_t t;
784: char s[64];
785:
786: if (magic_copy_from(ms, -1, &value, sizeof value) != 0)
787: return (0);
788: if (ml->type == MAGIC_TYPE_BEDATE ||
789: ml->type == MAGIC_TYPE_BELDATE)
1.3 brynet 790: value = be32toh(value);
1.1 nicm 791: if (ml->type == MAGIC_TYPE_LEDATE ||
792: ml->type == MAGIC_TYPE_LELDATE)
1.3 brynet 793: value = le32toh(value);
1.1 nicm 794:
795: if (ml->type_operator == '&')
796: value &= (uint32_t)ml->type_operand;
1.13 nicm 797: else if (ml->type_operator == '-')
798: value -= (uint32_t)ml->type_operand;
799: else if (ml->type_operator == '+')
800: value += (uint32_t)ml->type_operand;
1.1 nicm 801: else if (ml->type_operator != ' ')
802: return (-1);
803:
804: result = magic_test_unsigned(ml, value, (uint32_t)ml->test_unsigned);
805: if (result == !ml->test_not && ml->result != NULL) {
806: t = value;
807: switch (ml->type) {
808: case MAGIC_TYPE_LDATE:
809: case MAGIC_TYPE_LELDATE:
810: case MAGIC_TYPE_BELDATE:
811: ctime_r(&t, s);
812: break;
813: default:
814: asctime_r(gmtime(&t), s);
815: break;
816: }
817: s[strcspn(s, "\n")] = '\0';
818: magic_add_result(ms, ml, "%s", s);
819: ms->offset += sizeof value;
820: }
821: return (result);
822: }
823:
824: static int
825: magic_test_type_uqdate(struct magic_line *ml, struct magic_state *ms)
826: {
827: uint64_t value;
828: int result;
829: time_t t;
830: char s[64];
831:
832: if (magic_copy_from(ms, -1, &value, sizeof value) != 0)
833: return (0);
834: if (ml->type == MAGIC_TYPE_UBEQDATE ||
835: ml->type == MAGIC_TYPE_UBEQLDATE)
1.3 brynet 836: value = be64toh(value);
1.1 nicm 837: if (ml->type == MAGIC_TYPE_ULEQDATE ||
838: ml->type == MAGIC_TYPE_ULEQLDATE)
1.3 brynet 839: value = le64toh(value);
1.1 nicm 840:
841: if (ml->type_operator == '&')
842: value &= (uint64_t)ml->type_operand;
1.13 nicm 843: else if (ml->type_operator == '-')
844: value -= (uint64_t)ml->type_operand;
845: else if (ml->type_operator == '+')
846: value += (uint64_t)ml->type_operand;
1.1 nicm 847: else if (ml->type_operator != ' ')
848: return (-1);
849:
850: result = magic_test_unsigned(ml, value, (uint64_t)ml->test_unsigned);
851: if (result == !ml->test_not && ml->result != NULL) {
852: t = value;
853: switch (ml->type) {
854: case MAGIC_TYPE_UQLDATE:
855: case MAGIC_TYPE_ULEQLDATE:
856: case MAGIC_TYPE_UBEQLDATE:
857: ctime_r(&t, s);
858: break;
859: default:
860: asctime_r(gmtime(&t), s);
861: break;
862: }
863: s[strcspn(s, "\n")] = '\0';
864: magic_add_result(ms, ml, "%s", s);
865: ms->offset += sizeof value;
866: }
867: return (result);
868: }
869:
870: static int
871: magic_test_type_bestring16(__unused struct magic_line *ml,
872: __unused struct magic_state *ms)
873: {
874: return (-2);
875: }
876:
877: static int
878: magic_test_type_lestring16(__unused struct magic_line *ml,
879: __unused struct magic_state *ms)
880: {
881: return (-2);
882: }
883:
884: static int
885: magic_test_type_melong(__unused struct magic_line *ml,
886: __unused struct magic_state *ms)
887: {
888: return (-2);
889: }
890:
891: static int
892: magic_test_type_medate(__unused struct magic_line *ml,
893: __unused struct magic_state *ms)
894: {
895: return (-2);
896: }
897:
898: static int
899: magic_test_type_meldate(__unused struct magic_line *ml,
900: __unused struct magic_state *ms)
901: {
902: return (-2);
903: }
904:
905: static int
906: magic_test_type_regex(struct magic_line *ml, struct magic_state *ms)
907: {
908: const char *cp;
909: regex_t re;
910: regmatch_t m;
911: int result, flags = 0, sflag = 0;
912:
913: cp = &ml->type_string[(sizeof "regex") - 1];
914: if (*cp != '\0') {
915: if (*cp != '/')
916: return (-1);
917: cp++;
918: for (; *cp != '\0'; cp++) {
919: switch (*cp) {
920: case 's':
921: sflag = 1;
922: break;
923: case 'c':
924: flags |= REG_ICASE;
925: break;
926: default:
927: return (-1);
928: }
929: }
930: }
931:
932: if (regcomp(&re, ml->test_string, REG_EXTENDED) != 0)
933: return (-1);
934: m.rm_so = ms->offset;
935: m.rm_eo = ms->size;
936:
937: result = (regexec(&re, ms->base, 1, &m, REG_STARTEND) == 0);
1.12 nicm 938: if (result == !ml->test_not) {
1.17 nicm 939: if (ml->result != NULL) {
940: magic_add_string(ms, ml, ms->base + m.rm_so,
941: m.rm_eo - m.rm_so);
942: }
1.1 nicm 943: if (result) {
944: if (sflag)
945: ms->offset = m.rm_so;
946: else
947: ms->offset = m.rm_eo;
948: }
949: }
950: regfree(&re);
951: return (result);
952: }
953:
954: static int
955: magic_test_type_search(struct magic_line *ml, struct magic_state *ms)
956: {
957: const char *cp, *endptr, *start, *found;
958: size_t size, end, i;
959: uint64_t range;
960: int result, n, cflag = 0, bflag = 0, Bflag = 0;
961:
962: cp = &ml->type_string[(sizeof "search") - 1];
963: if (*cp != '\0') {
964: if (*cp != '/')
965: return (-1);
966: cp++;
967:
968: endptr = magic_strtoull(cp, &range);
969: if (endptr == NULL || (*endptr != '/' && *endptr != '\0'))
970: return (-1);
971:
972: if (*endptr == '/') {
973: for (cp = endptr + 1; *cp != '\0'; cp++) {
974: switch (*cp) {
975: case 'B':
1.11 nicm 976: case 'W':
1.1 nicm 977: Bflag = 1;
978: break;
979: case 'b':
1.11 nicm 980: case 'w':
1.1 nicm 981: bflag = 1;
982: break;
983: case 'c':
984: cflag = 1;
1.11 nicm 985: break;
986: case 't':
1.1 nicm 987: break;
988: default:
989: return (-1);
990: }
991: }
992: }
993: } else
994: range = UINT64_MAX;
995: if (range > (uint64_t)ms->size - ms->offset)
996: range = ms->size - ms->offset;
997: size = ml->test_string_size;
998:
999: /* Want to search every starting position from up to range + size. */
1000: end = range + size;
1001: if (end > ms->size - ms->offset) {
1002: if (size > ms->size - ms->offset)
1003: end = 0;
1004: else
1005: end = ms->size - ms->offset - size;
1006: }
1007:
1008: /*
1009: * < and > and the flags are only in /etc/magic with search/1 so don't
1010: * support them with anything else.
1011: */
1012: start = ms->base + ms->offset;
1013: if (end == 0)
1014: found = NULL;
1015: else if (ml->test_operator == 'x')
1016: found = start;
1017: else if (range == 1) {
1018: n = magic_test_eq(start, ms->size - ms->offset, ml->test_string,
1019: size, cflag, bflag, Bflag);
1020: if (n == -1 && ml->test_operator == '<')
1021: found = start;
1022: else if (n == 1 && ml->test_operator == '>')
1023: found = start;
1024: else if (n == 0 && ml->test_operator == '=')
1025: found = start;
1026: else
1027: found = NULL;
1028: } else {
1029: if (ml->test_operator != '=')
1030: return (-2);
1031: for (i = 0; i < end; i++) {
1032: n = magic_test_eq(start + i, ms->size - ms->offset - i,
1033: ml->test_string, size, cflag, bflag, Bflag);
1034: if (n == 0) {
1035: found = start + i;
1036: break;
1037: }
1038: }
1039: if (i == end)
1040: found = NULL;
1041: }
1042: result = (found != NULL);
1043:
1.12 nicm 1044: if (result == !ml->test_not) {
1045: if (ml->result != NULL)
1046: magic_add_string(ms, ml, found, ms->size - ms->offset);
1047: if (result && found != NULL && ml->test_operator == '=')
1048: ms->offset = (found + size) - ms->base;
1.1 nicm 1049: }
1050: return (result);
1051: }
1052:
1053: static int
1054: magic_test_type_default(__unused struct magic_line *ml,
1055: __unused struct magic_state *ms)
1056: {
1.18 ! nicm 1057: return (!ms->matched);
1.1 nicm 1058: }
1059:
1060: static int (*magic_test_functions[])(struct magic_line *,
1061: struct magic_state *) = {
1062: magic_test_type_none,
1063: magic_test_type_byte,
1064: magic_test_type_short,
1065: magic_test_type_long,
1066: magic_test_type_quad,
1067: magic_test_type_ubyte,
1068: magic_test_type_ushort,
1069: magic_test_type_ulong,
1070: magic_test_type_uquad,
1071: magic_test_type_float,
1072: magic_test_type_double,
1073: magic_test_type_string,
1074: magic_test_type_pstring,
1075: magic_test_type_date,
1076: magic_test_type_qdate,
1077: magic_test_type_date,
1078: magic_test_type_qdate,
1079: magic_test_type_udate,
1080: magic_test_type_uqdate,
1081: magic_test_type_udate,
1082: magic_test_type_qdate,
1083: magic_test_type_short,
1084: magic_test_type_long,
1085: magic_test_type_quad,
1086: magic_test_type_ushort,
1087: magic_test_type_ulong,
1088: magic_test_type_uquad,
1089: magic_test_type_float,
1090: magic_test_type_double,
1091: magic_test_type_date,
1092: magic_test_type_qdate,
1093: magic_test_type_date,
1094: magic_test_type_qdate,
1095: magic_test_type_udate,
1096: magic_test_type_uqdate,
1097: magic_test_type_udate,
1098: magic_test_type_uqdate,
1099: magic_test_type_bestring16,
1100: magic_test_type_short,
1101: magic_test_type_long,
1102: magic_test_type_quad,
1103: magic_test_type_ushort,
1104: magic_test_type_ulong,
1105: magic_test_type_uquad,
1106: magic_test_type_float,
1107: magic_test_type_double,
1108: magic_test_type_date,
1109: magic_test_type_qdate,
1110: magic_test_type_date,
1111: magic_test_type_qdate,
1112: magic_test_type_udate,
1113: magic_test_type_uqdate,
1114: magic_test_type_udate,
1115: magic_test_type_uqdate,
1116: magic_test_type_lestring16,
1117: magic_test_type_melong,
1118: magic_test_type_medate,
1119: magic_test_type_meldate,
1120: magic_test_type_regex,
1121: magic_test_type_search,
1122: magic_test_type_default,
1123: };
1124:
1125: static int
1126: magic_test_line(struct magic_line *ml, struct magic_state *ms)
1127: {
1128: struct magic_line *child;
1129: int64_t offset, wanted, next;
1130: int result;
1131: uint8_t b;
1132: uint16_t s;
1133: uint32_t l;
1134:
1135: if (ml->indirect_type == ' ')
1136: wanted = ml->offset;
1137: else {
1138: wanted = ml->indirect_offset;
1139: if (ml->indirect_relative) {
1.14 nicm 1140: if (wanted < 0 && (size_t)-wanted > ms->offset)
1.1 nicm 1141: return (0);
1142: if (wanted > 0 && ms->offset + wanted > ms->size)
1143: return (0);
1144: next = ms->offset + ml->indirect_offset;
1145: } else
1146: next = wanted;
1147:
1148: switch (ml->indirect_type) {
1149: case 'b':
1150: case 'B':
1151: if (magic_copy_from(ms, next, &b, sizeof b) != 0)
1152: return (0);
1153: wanted = b;
1154: break;
1155: case 's':
1156: if (magic_copy_from(ms, next, &s, sizeof s) != 0)
1157: return (0);
1.3 brynet 1158: wanted = le16toh(s);
1.1 nicm 1159: break;
1160: case 'S':
1161: if (magic_copy_from(ms, next, &s, sizeof s) != 0)
1162: return (0);
1.3 brynet 1163: wanted = be16toh(s);
1.1 nicm 1164: break;
1165: case 'l':
1166: if (magic_copy_from(ms, next, &l, sizeof l) != 0)
1167: return (0);
1.3 brynet 1168: wanted = le16toh(l);
1.1 nicm 1169: break;
1170: case 'L':
1171: if (magic_copy_from(ms, next, &l, sizeof l) != 0)
1172: return (0);
1.3 brynet 1173: wanted = be16toh(l);
1.1 nicm 1174: break;
1175: }
1176:
1177: switch (ml->indirect_operator) {
1178: case '+':
1179: wanted += ml->indirect_operand;
1180: break;
1181: case '-':
1182: wanted -= ml->indirect_operand;
1183: break;
1184: case '*':
1185: wanted *= ml->indirect_operand;
1186: break;
1187: }
1188: }
1189:
1190: if (ml->offset_relative) {
1.14 nicm 1191: if (wanted < 0 && (size_t)-wanted > ms->offset)
1.1 nicm 1192: return (0);
1193: if (wanted > 0 && ms->offset + wanted > ms->size)
1194: return (0);
1195: offset = ms->offset + wanted;
1196: } else
1197: offset = wanted;
1.14 nicm 1198: if (offset < 0 || (size_t)offset > ms->size)
1.1 nicm 1199: return (0);
1200: ms->offset = offset;
1201:
1202: result = magic_test_functions[ml->type](ml, ms);
1203: if (result == -1) {
1204: magic_warn(ml, "test %s/%c failed", ml->type_string,
1205: ml->test_operator);
1206: return (0);
1207: }
1208: if (result == -2) {
1209: magic_warn(ml, "test %s/%c not implemented", ml->type_string,
1210: ml->test_operator);
1211: return (0);
1212: }
1213: if (result == ml->test_not)
1214: return (0);
1215: if (ml->mimetype != NULL)
1216: ms->mimetype = ml->mimetype;
1217:
1.15 nicm 1218: magic_warn(ml, "test %s/%c matched at offset %lld (now %zu): '%s'",
1219: ml->type_string, ml->test_operator, offset, ms->offset,
1.1 nicm 1220: ml->result == NULL ? "" : ml->result);
1221:
1.18 ! nicm 1222: ms->matched = 0;
1.1 nicm 1223: offset = ms->offset;
1224: TAILQ_FOREACH(child, &ml->children, entry) {
1225: ms->offset = offset;
1226: magic_test_line(child, ms);
1227: }
1.18 ! nicm 1228:
! 1229: ms->matched = 1;
1.5 nicm 1230: return (ml->result != NULL);
1.1 nicm 1231: }
1232:
1233: const char *
1234: magic_test(struct magic *m, const void *base, size_t size, int flags)
1235: {
1236: struct magic_line *ml;
1237: static struct magic_state ms;
1238:
1239: memset(&ms, 0, sizeof ms);
1240:
1241: ms.base = base;
1242: ms.size = size;
1243:
1244: ms.text = !!(flags & MAGIC_TEST_TEXT);
1245:
1246: RB_FOREACH(ml, magic_tree, &m->tree) {
1247: ms.offset = 0;
1248: if (ml->text == ms.text && magic_test_line(ml, &ms))
1249: break;
1250: }
1251:
1252: if (*ms.out != '\0') {
1253: if (flags & MAGIC_TEST_MIME) {
1254: if (ms.mimetype)
1255: return (xstrdup(ms.mimetype));
1256: return (NULL);
1257: }
1258: return (xstrdup(ms.out));
1259: }
1260: return (NULL);
1261: }