Annotation of src/usr.bin/file/apprentice.c, Revision 1.28
1.28 ! deraadt 1: /* $OpenBSD: apprentice.c,v 1.27 2009/08/27 16:26:42 deraadt Exp $ */
1.1 deraadt 2: /*
1.16 ian 3: * Copyright (c) Ian F. Darwin 1986-1995.
4: * Software written by Ian F. Darwin and others;
5: * maintained 1995-present by Christos Zoulas and others.
6: *
7: * Redistribution and use in source and binary forms, with or without
8: * modification, are permitted provided that the following conditions
9: * are met:
10: * 1. Redistributions of source code must retain the above copyright
11: * notice immediately at the beginning of the file, without modification,
12: * this list of conditions, and the following disclaimer.
13: * 2. Redistributions in binary form must reproduce the above copyright
14: * notice, this list of conditions and the following disclaimer in the
15: * documentation and/or other materials provided with the distribution.
16: *
17: * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20: * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
21: * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27: * SUCH DAMAGE.
1.1 deraadt 28: */
1.19 tedu 29: /*
30: * apprentice - make one pass through /etc/magic, learning its secrets.
31: */
1.1 deraadt 32:
1.27 deraadt 33: #include <sys/param.h>
34: #include <sys/stat.h>
35: #include <sys/types.h>
36:
1.19 tedu 37: #include "file.h"
38: #include "magic.h"
1.26 chl 39: #include "patchlevel.h"
1.1 deraadt 40: #include <stdlib.h>
1.19 tedu 41: #ifdef HAVE_UNISTD_H
42: #include <unistd.h>
43: #endif
1.1 deraadt 44: #include <string.h>
1.25 chl 45: #include <assert.h>
1.1 deraadt 46: #include <ctype.h>
1.19 tedu 47: #include <fcntl.h>
48: #ifdef QUICK
49: #include <sys/mman.h>
50: #endif
1.26 chl 51: #include <dirent.h>
1.1 deraadt 52:
53: #define EATAB {while (isascii((unsigned char) *l) && \
54: isspace((unsigned char) *l)) ++l;}
55: #define LOWCASE(l) (isupper((unsigned char) (l)) ? \
56: tolower((unsigned char) (l)) : (l))
1.19 tedu 57: /*
58: * Work around a bug in headers on Digital Unix.
59: * At least confirmed for: OSF1 V4.0 878
60: */
61: #if defined(__osf__) && defined(__DECC)
62: #ifdef MAP_FAILED
63: #undef MAP_FAILED
64: #endif
65: #endif
66:
67: #ifndef MAP_FAILED
68: #define MAP_FAILED (void *) -1
69: #endif
70:
71: #ifndef MAP_FILE
72: #define MAP_FILE 0
73: #endif
74:
75: #ifndef MAXPATHLEN
76: #define MAXPATHLEN 1024
77: #endif
78:
1.25 chl 79: struct magic_entry {
80: struct magic *mp;
81: uint32_t cont_count;
82: uint32_t max_count;
83: };
84:
85: int file_formats[FILE_NAMES_SIZE];
86: const size_t file_nformats = FILE_NAMES_SIZE;
87: const char *file_names[FILE_NAMES_SIZE];
88: const size_t file_nnames = FILE_NAMES_SIZE;
89:
90: private int getvalue(struct magic_set *ms, struct magic *, const char **, int);
1.19 tedu 91: private int hextoint(int);
1.25 chl 92: private const char *getstr(struct magic_set *, const char *, char *, int,
93: int *, int);
94: private int parse(struct magic_set *, struct magic_entry **, uint32_t *,
95: const char *, size_t, int);
1.26 chl 96: private int parse_mime(struct magic_set *, struct magic_entry **, uint32_t *,
97: const char *);
1.25 chl 98: private void eatsize(const char **);
1.19 tedu 99: private int apprentice_1(struct magic_set *, const char *, int, struct mlist *);
1.25 chl 100: private size_t apprentice_magic_strength(const struct magic *);
101: private int apprentice_sort(const void *, const void *);
1.26 chl 102: private int apprentice_load(struct magic_set *, struct magic **, uint32_t *,
1.19 tedu 103: const char *, int);
104: private void byteswap(struct magic *, uint32_t);
105: private void bs1(struct magic *);
106: private uint16_t swap2(uint16_t);
107: private uint32_t swap4(uint32_t);
1.25 chl 108: private uint64_t swap8(uint64_t);
1.26 chl 109: private void mkdbname(const char *, char **, int);
1.19 tedu 110: private int apprentice_map(struct magic_set *, struct magic **, uint32_t *,
111: const char *);
112: private int apprentice_compile(struct magic_set *, struct magic **, uint32_t *,
113: const char *);
1.25 chl 114: private int check_format_type(const char *, int);
115: private int check_format(struct magic_set *, struct magic *);
1.26 chl 116: private int get_op(char);
1.19 tedu 117:
118: private size_t maxmagic = 0;
119: private size_t magicsize = sizeof(struct magic);
120:
1.26 chl 121: private const char usg_hdr[] = "cont\toffset\ttype\topcode\tmask\tvalue\tdesc";
122: private const char mime_marker[] = "!:mime";
123: private const size_t mime_marker_len = sizeof(mime_marker) - 1;
1.25 chl 124:
1.19 tedu 125: #ifdef COMPILE_ONLY
126:
127: int main(int, char *[]);
128:
129: int
130: main(int argc, char *argv[])
131: {
132: int ret;
1.25 chl 133: struct magic_set *ms;
134: char *progname;
1.19 tedu 135:
136: if ((progname = strrchr(argv[0], '/')) != NULL)
137: progname++;
138: else
139: progname = argv[0];
140:
141: if (argc != 2) {
1.25 chl 142: (void)fprintf(stderr, "Usage: %s file\n", progname);
143: return 1;
1.19 tedu 144: }
145:
1.25 chl 146: if ((ms = magic_open(MAGIC_CHECK)) == NULL) {
147: (void)fprintf(stderr, "%s: %s\n", progname, strerror(errno));
148: return 1;
149: }
150: ret = magic_compile(ms, argv[1]) == -1 ? 1 : 0;
151: if (ret == 1)
152: (void)fprintf(stderr, "%s: %s\n", progname, magic_error(ms));
153: magic_close(ms);
154: return ret;
1.19 tedu 155: }
156: #endif /* COMPILE_ONLY */
157:
1.25 chl 158: static const struct type_tbl_s {
1.26 chl 159: const char name[16];
1.25 chl 160: const size_t len;
161: const int type;
162: const int format;
163: } type_tbl[] = {
164: # define XX(s) s, (sizeof(s) - 1)
1.26 chl 165: # define XX_NULL "", 0
1.25 chl 166: { XX("byte"), FILE_BYTE, FILE_FMT_NUM },
167: { XX("short"), FILE_SHORT, FILE_FMT_NUM },
168: { XX("default"), FILE_DEFAULT, FILE_FMT_STR },
169: { XX("long"), FILE_LONG, FILE_FMT_NUM },
170: { XX("string"), FILE_STRING, FILE_FMT_STR },
171: { XX("date"), FILE_DATE, FILE_FMT_STR },
172: { XX("beshort"), FILE_BESHORT, FILE_FMT_NUM },
173: { XX("belong"), FILE_BELONG, FILE_FMT_NUM },
174: { XX("bedate"), FILE_BEDATE, FILE_FMT_STR },
175: { XX("leshort"), FILE_LESHORT, FILE_FMT_NUM },
176: { XX("lelong"), FILE_LELONG, FILE_FMT_NUM },
177: { XX("ledate"), FILE_LEDATE, FILE_FMT_STR },
178: { XX("pstring"), FILE_PSTRING, FILE_FMT_STR },
179: { XX("ldate"), FILE_LDATE, FILE_FMT_STR },
180: { XX("beldate"), FILE_BELDATE, FILE_FMT_STR },
181: { XX("leldate"), FILE_LELDATE, FILE_FMT_STR },
182: { XX("regex"), FILE_REGEX, FILE_FMT_STR },
183: { XX("bestring16"), FILE_BESTRING16, FILE_FMT_STR },
184: { XX("lestring16"), FILE_LESTRING16, FILE_FMT_STR },
185: { XX("search"), FILE_SEARCH, FILE_FMT_STR },
186: { XX("medate"), FILE_MEDATE, FILE_FMT_STR },
187: { XX("meldate"), FILE_MELDATE, FILE_FMT_STR },
188: { XX("melong"), FILE_MELONG, FILE_FMT_NUM },
189: { XX("quad"), FILE_QUAD, FILE_FMT_QUAD },
190: { XX("lequad"), FILE_LEQUAD, FILE_FMT_QUAD },
191: { XX("bequad"), FILE_BEQUAD, FILE_FMT_QUAD },
192: { XX("qdate"), FILE_QDATE, FILE_FMT_STR },
193: { XX("leqdate"), FILE_LEQDATE, FILE_FMT_STR },
194: { XX("beqdate"), FILE_BEQDATE, FILE_FMT_STR },
195: { XX("qldate"), FILE_QLDATE, FILE_FMT_STR },
196: { XX("leqldate"), FILE_LEQLDATE, FILE_FMT_STR },
197: { XX("beqldate"), FILE_BEQLDATE, FILE_FMT_STR },
1.26 chl 198: { XX("float"), FILE_FLOAT, FILE_FMT_FLOAT },
199: { XX("befloat"), FILE_BEFLOAT, FILE_FMT_FLOAT },
200: { XX("lefloat"), FILE_LEFLOAT, FILE_FMT_FLOAT },
201: { XX("double"), FILE_DOUBLE, FILE_FMT_DOUBLE },
202: { XX("bedouble"), FILE_BEDOUBLE, FILE_FMT_DOUBLE },
203: { XX("ledouble"), FILE_LEDOUBLE, FILE_FMT_DOUBLE },
1.25 chl 204: { XX_NULL, FILE_INVALID, FILE_FMT_NONE },
205: # undef XX
206: # undef XX_NULL
207: };
208:
209: private int
210: get_type(const char *l, const char **t)
211: {
212: const struct type_tbl_s *p;
213:
1.26 chl 214: for (p = type_tbl; p->len; p++) {
1.25 chl 215: if (strncmp(l, p->name, p->len) == 0) {
216: if (t)
217: *t = l + p->len;
218: break;
219: }
220: }
221: return p->type;
222: }
223:
224: private void
225: init_file_tables(void)
226: {
227: static int done = 0;
228: const struct type_tbl_s *p;
229:
230: if (done)
231: return;
232: done++;
233:
1.26 chl 234: for (p = type_tbl; p->len; p++) {
1.25 chl 235: assert(p->type < FILE_NAMES_SIZE);
236: file_names[p->type] = p->name;
237: file_formats[p->type] = p->format;
238: }
239: }
1.19 tedu 240:
241: /*
1.26 chl 242: * Handle one file or directory.
1.19 tedu 243: */
244: private int
245: apprentice_1(struct magic_set *ms, const char *fn, int action,
246: struct mlist *mlist)
247: {
248: struct magic *magic = NULL;
249: uint32_t nmagic = 0;
250: struct mlist *ml;
251: int rv = -1;
252: int mapped;
253:
254: if (magicsize != FILE_MAGICSIZE) {
255: file_error(ms, 0, "magic element size %lu != %lu",
256: (unsigned long)sizeof(*magic),
257: (unsigned long)FILE_MAGICSIZE);
258: return -1;
259: }
1.1 deraadt 260:
1.19 tedu 261: if (action == FILE_COMPILE) {
1.26 chl 262: rv = apprentice_load(ms, &magic, &nmagic, fn, action);
1.19 tedu 263: if (rv != 0)
264: return -1;
265: rv = apprentice_compile(ms, &magic, &nmagic, fn);
266: free(magic);
267: return rv;
268: }
1.25 chl 269:
1.19 tedu 270: #ifndef COMPILE_ONLY
271: if ((rv = apprentice_map(ms, &magic, &nmagic, fn)) == -1) {
272: if (ms->flags & MAGIC_CHECK)
1.25 chl 273: file_magwarn(ms, "using regular magic file `%s'", fn);
1.26 chl 274: rv = apprentice_load(ms, &magic, &nmagic, fn, action);
1.19 tedu 275: if (rv != 0)
276: return -1;
277: }
1.1 deraadt 278:
1.19 tedu 279: mapped = rv;
280:
1.26 chl 281: if (magic == NULL) {
1.19 tedu 282: file_delmagic(magic, mapped, nmagic);
283: return -1;
284: }
1.1 deraadt 285:
1.19 tedu 286: if ((ml = malloc(sizeof(*ml))) == NULL) {
287: file_delmagic(magic, mapped, nmagic);
1.25 chl 288: file_oomem(ms, sizeof(*ml));
1.19 tedu 289: return -1;
290: }
1.1 deraadt 291:
1.19 tedu 292: ml->magic = magic;
293: ml->nmagic = nmagic;
294: ml->mapped = mapped;
295:
296: mlist->prev->next = ml;
297: ml->prev = mlist->prev;
298: ml->next = mlist;
299: mlist->prev = ml;
1.1 deraadt 300:
1.19 tedu 301: return 0;
302: #endif /* COMPILE_ONLY */
303: }
304:
305: protected void
306: file_delmagic(struct magic *p, int type, size_t entries)
307: {
308: if (p == NULL)
309: return;
310: switch (type) {
1.25 chl 311: #ifdef QUICK
1.19 tedu 312: case 2:
313: p--;
314: (void)munmap((void *)p, sizeof(*p) * (entries + 1));
315: break;
1.25 chl 316: #endif
1.19 tedu 317: case 1:
318: p--;
1.25 chl 319: /*FALLTHROUGH*/
1.19 tedu 320: case 0:
321: free(p);
322: break;
323: default:
324: abort();
325: }
326: }
327:
1.26 chl 328: /* const char *fn: list of magic files and directories */
1.19 tedu 329: protected struct mlist *
330: file_apprentice(struct magic_set *ms, const char *fn, int action)
1.2 deraadt 331: {
1.26 chl 332: char *p, *mfn;
1.2 deraadt 333: int file_err, errs = -1;
1.19 tedu 334: struct mlist *mlist;
1.25 chl 335:
336: init_file_tables();
1.2 deraadt 337:
1.19 tedu 338: if (fn == NULL)
339: fn = getenv("MAGIC");
340: if (fn == NULL)
341: fn = MAGIC;
342:
1.25 chl 343: if ((mfn = strdup(fn)) == NULL) {
344: file_oomem(ms, strlen(fn));
1.19 tedu 345: return NULL;
346: }
1.25 chl 347: fn = mfn;
1.19 tedu 348:
349: if ((mlist = malloc(sizeof(*mlist))) == NULL) {
350: free(mfn);
1.25 chl 351: file_oomem(ms, sizeof(*mlist));
1.19 tedu 352: return NULL;
1.2 deraadt 353: }
1.19 tedu 354: mlist->next = mlist->prev = mlist;
1.17 deraadt 355:
1.2 deraadt 356: while (fn) {
1.19 tedu 357: p = strchr(fn, PATHSEP);
1.2 deraadt 358: if (p)
359: *p++ = '\0';
1.19 tedu 360: if (*fn == '\0')
361: break;
362: file_err = apprentice_1(ms, fn, action, mlist);
1.26 chl 363: errs = MAX(errs, file_err);
1.2 deraadt 364: fn = p;
365: }
1.19 tedu 366: if (errs == -1) {
367: free(mfn);
368: free(mlist);
369: mlist = NULL;
370: file_error(ms, 0, "could not find any magic files!");
371: return NULL;
372: }
1.2 deraadt 373: free(mfn);
1.19 tedu 374: return mlist;
1.2 deraadt 375: }
376:
1.19 tedu 377: /*
1.25 chl 378: * Get weight of this magic entry, for sorting purposes.
379: */
380: private size_t
381: apprentice_magic_strength(const struct magic *m)
382: {
383: #define MULT 10
384: size_t val = 2 * MULT; /* baseline strength */
385:
386: switch (m->type) {
387: case FILE_DEFAULT: /* make sure this sorts last */
388: return 0;
389:
390: case FILE_BYTE:
391: val += 1 * MULT;
392: break;
393:
394: case FILE_SHORT:
395: case FILE_LESHORT:
396: case FILE_BESHORT:
397: val += 2 * MULT;
398: break;
399:
400: case FILE_LONG:
401: case FILE_LELONG:
402: case FILE_BELONG:
403: case FILE_MELONG:
404: val += 4 * MULT;
405: break;
406:
407: case FILE_PSTRING:
408: case FILE_STRING:
409: val += m->vallen * MULT;
410: break;
411:
412: case FILE_BESTRING16:
413: case FILE_LESTRING16:
414: val += m->vallen * MULT / 2;
415: break;
416:
417: case FILE_SEARCH:
418: case FILE_REGEX:
1.26 chl 419: val += m->vallen * MAX(MULT / m->vallen, 1);
1.25 chl 420: break;
421:
422: case FILE_DATE:
423: case FILE_LEDATE:
424: case FILE_BEDATE:
425: case FILE_MEDATE:
426: case FILE_LDATE:
427: case FILE_LELDATE:
428: case FILE_BELDATE:
429: case FILE_MELDATE:
1.26 chl 430: case FILE_FLOAT:
431: case FILE_BEFLOAT:
432: case FILE_LEFLOAT:
1.25 chl 433: val += 4 * MULT;
434: break;
435:
436: case FILE_QUAD:
437: case FILE_BEQUAD:
438: case FILE_LEQUAD:
439: case FILE_QDATE:
440: case FILE_LEQDATE:
441: case FILE_BEQDATE:
442: case FILE_QLDATE:
443: case FILE_LEQLDATE:
444: case FILE_BEQLDATE:
1.26 chl 445: case FILE_DOUBLE:
446: case FILE_BEDOUBLE:
447: case FILE_LEDOUBLE:
1.25 chl 448: val += 8 * MULT;
449: break;
450:
451: default:
452: val = 0;
453: (void)fprintf(stderr, "Bad type %d\n", m->type);
454: abort();
455: }
456:
457: switch (m->reln) {
458: case 'x': /* matches anything penalize */
1.26 chl 459: case '!': /* matches almost anything penalize */
1.25 chl 460: val = 0;
461: break;
462:
463: case '=': /* Exact match, prefer */
464: val += MULT;
465: break;
466:
467: case '>':
468: case '<': /* comparison match reduce strength */
469: val -= 2 * MULT;
470: break;
471:
472: case '^':
473: case '&': /* masking bits, we could count them too */
474: val -= MULT;
475: break;
476:
477: default:
478: (void)fprintf(stderr, "Bad relation %c\n", m->reln);
479: abort();
480: }
481:
482: if (val == 0) /* ensure we only return 0 for FILE_DEFAULT */
483: val = 1;
484:
485: return val;
486: }
487:
488: /*
489: * Sort callback for sorting entries by "strength" (basically length)
490: */
491: private int
492: apprentice_sort(const void *a, const void *b)
493: {
494: const struct magic_entry *ma = a;
495: const struct magic_entry *mb = b;
496: size_t sa = apprentice_magic_strength(ma->mp);
497: size_t sb = apprentice_magic_strength(mb->mp);
498: if (sa == sb)
499: return 0;
500: else if (sa > sb)
501: return -1;
502: else
503: return 1;
504: }
505:
1.26 chl 506: private void
507: set_test_type(struct magic *mstart, struct magic *m)
508: {
509: switch (m->type) {
510: case FILE_BYTE:
511: case FILE_SHORT:
512: case FILE_LONG:
513: case FILE_DATE:
514: case FILE_BESHORT:
515: case FILE_BELONG:
516: case FILE_BEDATE:
517: case FILE_LESHORT:
518: case FILE_LELONG:
519: case FILE_LEDATE:
520: case FILE_LDATE:
521: case FILE_BELDATE:
522: case FILE_LELDATE:
523: case FILE_MEDATE:
524: case FILE_MELDATE:
525: case FILE_MELONG:
526: case FILE_QUAD:
527: case FILE_LEQUAD:
528: case FILE_BEQUAD:
529: case FILE_QDATE:
530: case FILE_LEQDATE:
531: case FILE_BEQDATE:
532: case FILE_QLDATE:
533: case FILE_LEQLDATE:
534: case FILE_BEQLDATE:
535: case FILE_FLOAT:
536: case FILE_BEFLOAT:
537: case FILE_LEFLOAT:
538: case FILE_DOUBLE:
539: case FILE_BEDOUBLE:
540: case FILE_LEDOUBLE:
541: case FILE_STRING:
542: case FILE_PSTRING:
543: case FILE_BESTRING16:
544: case FILE_LESTRING16:
545: /* binary test, set flag */
546: mstart->flag |= BINTEST;
547: break;
548: case FILE_REGEX:
549: case FILE_SEARCH:
550: /* binary test if pattern is not text */
551: if (file_looks_utf8(m->value.s, m->vallen, NULL, NULL) == 0)
552: mstart->flag |= BINTEST;
553: break;
554: case FILE_DEFAULT:
555: /* can't deduce anything; we shouldn't see this at the
556: top level anyway */
557: break;
558: case FILE_INVALID:
559: default:
560: /* invalid search type, but no need to complain here */
561: break;
562: }
563: }
564:
1.25 chl 565: /*
1.26 chl 566: * Load and parse one file.
567: */
568: private void
569: load_1(struct magic_set *ms, int action, const char *fn, int *errs,
570: struct magic_entry **marray, uint32_t *marraycount)
571: {
572: char line[BUFSIZ];
573: size_t lineno = 0;
574: FILE *f = fopen(ms->file = fn, "r");
575: if (f == NULL) {
576: if (errno != ENOENT)
577: file_error(ms, errno, "cannot read magic file `%s'",
578: fn);
579: (*errs)++;
580: } else {
581: /* read and parse this file */
582: for (ms->line = 1; fgets(line, sizeof(line), f) != NULL; ms->line++) {
583: size_t len;
584: len = strlen(line);
585: if (len == 0) /* null line, garbage, etc */
586: continue;
587: if (line[len - 1] == '\n') {
588: lineno++;
589: line[len - 1] = '\0'; /* delete newline */
590: }
591: if (line[0] == '\0') /* empty, do not parse */
592: continue;
593: if (line[0] == '#') /* comment, do not parse */
594: continue;
595: if (len > mime_marker_len &&
596: memcmp(line, mime_marker, mime_marker_len) == 0) {
597: /* MIME type */
598: if (parse_mime(ms, marray, marraycount,
599: line + mime_marker_len) != 0)
600: (*errs)++;
601: continue;
602: }
603: if (parse(ms, marray, marraycount, line, lineno, action) != 0)
604: (*errs)++;
605: }
606:
607: (void)fclose(f);
608: }
609: }
610:
611: /*
612: * parse a file or directory of files
613: * const char *fn: name of magic file or directory
1.19 tedu 614: */
615: private int
1.26 chl 616: apprentice_load(struct magic_set *ms, struct magic **magicp, uint32_t *nmagicp,
1.19 tedu 617: const char *fn, int action)
1.1 deraadt 618: {
619: int errs = 0;
1.25 chl 620: struct magic_entry *marray;
1.26 chl 621: uint32_t marraycount, i, mentrycount = 0, starttest;
622: char subfn[MAXPATHLEN];
623: struct stat st;
624: DIR *dir;
625: struct dirent *d;
1.1 deraadt 626:
1.25 chl 627: ms->flags |= MAGIC_CHECK; /* Enable checks for parsed files */
628:
1.19 tedu 629: maxmagic = MAXMAGIS;
1.25 chl 630: if ((marray = calloc(maxmagic, sizeof(*marray))) == NULL) {
631: file_oomem(ms, maxmagic * sizeof(*marray));
1.19 tedu 632: return -1;
633: }
1.25 chl 634: marraycount = 0;
1.19 tedu 635:
636: /* print silly verbose header for USG compat. */
637: if (action == FILE_CHECK)
1.26 chl 638: (void)fprintf(stderr, "%s\n", usg_hdr);
639:
640: /* load directory or file */
641: if (stat(fn, &st) == 0 && S_ISDIR(st.st_mode)) {
642: dir = opendir(fn);
643: if (dir) {
644: while (d = readdir(dir)) {
645: snprintf(subfn, sizeof(subfn), "%s/%s",
646: fn, d->d_name);
647: if (stat(subfn, &st) == 0 && S_ISREG(st.st_mode)) {
648: load_1(ms, action, subfn, &errs,
649: &marray, &marraycount);
650: }
651: }
652: closedir(dir);
653: } else
654: errs++;
655: } else
656: load_1(ms, action, fn, &errs, &marray, &marraycount);
657: if (errs)
658: goto out;
1.19 tedu 659:
1.26 chl 660: /* Set types of tests */
661: for (i = 0; i < marraycount; ) {
662: if (marray[i].mp->cont_level != 0) {
663: i++;
1.25 chl 664: continue;
665: }
1.26 chl 666:
667: starttest = i;
668: do {
669: set_test_type(marray[starttest].mp, marray[i].mp);
670: if (ms->flags & MAGIC_DEBUG) {
671: (void)fprintf(stderr, "%s%s%s: %s\n",
672: marray[i].mp->mimetype,
673: marray[i].mp->mimetype[0] == '\0' ? "" : "; ",
674: marray[i].mp->desc[0] ? marray[i].mp->desc : "(no description)",
675: marray[i].mp->flag & BINTEST ? "binary" : "text");
676: if (marray[i].mp->flag & BINTEST) {
677: #define SYMBOL "text"
678: #define SYMLEN sizeof(SYMBOL)
679: char *p = strstr(marray[i].mp->desc, "text");
680: if (p && (p == marray[i].mp->desc || isspace(p[-1])) &&
681: (p + SYMLEN - marray[i].mp->desc == MAXstring ||
682: (p[SYMLEN] == '\0' || isspace(p[SYMLEN])))) {
683: (void)fprintf(stderr,
684: "*** Possible binary test for text type\n");
685: }
686: #undef SYMBOL
687: #undef SYMLEN
688: }
689: }
690: } while (++i < marraycount && marray[i].mp->cont_level != 0);
1.1 deraadt 691: }
692:
1.26 chl 693: qsort(marray, marraycount, sizeof(*marray), apprentice_sort);
1.25 chl 694:
695: /*
696: * Make sure that any level 0 "default" line is last (if one exists).
697: */
698: for (i = 0; i < marraycount; i++) {
699: if (marray[i].mp->cont_level == 0 &&
700: marray[i].mp->type == FILE_DEFAULT) {
701: while (++i < marraycount)
702: if (marray[i].mp->cont_level == 0)
703: break;
704: if (i != marraycount) {
705: ms->line = marray[i].mp->lineno; /* XXX - Ugh! */
706: file_magwarn(ms,
707: "level 0 \"default\" did not sort last");
708: }
709: break;
710: }
711: }
712:
713: for (i = 0; i < marraycount; i++)
714: mentrycount += marray[i].cont_count;
715:
716: if ((*magicp = malloc(sizeof(**magicp) * mentrycount)) == NULL) {
717: file_oomem(ms, sizeof(**magicp) * mentrycount);
718: errs++;
719: goto out;
720: }
721:
722: mentrycount = 0;
723: for (i = 0; i < marraycount; i++) {
724: (void)memcpy(*magicp + mentrycount, marray[i].mp,
725: marray[i].cont_count * sizeof(**magicp));
726: mentrycount += marray[i].cont_count;
727: }
728: out:
729: for (i = 0; i < marraycount; i++)
730: free(marray[i].mp);
731: free(marray);
1.19 tedu 732: if (errs) {
733: *magicp = NULL;
734: *nmagicp = 0;
1.25 chl 735: return errs;
736: } else {
737: *nmagicp = mentrycount;
738: return 0;
1.19 tedu 739: }
1.25 chl 740:
1.1 deraadt 741: }
742:
743: /*
744: * extend the sign bit if the comparison is to be signed
745: */
1.25 chl 746: protected uint64_t
747: file_signextend(struct magic_set *ms, struct magic *m, uint64_t v)
1.1 deraadt 748: {
1.25 chl 749: if (!(m->flag & UNSIGNED)) {
1.1 deraadt 750: switch(m->type) {
751: /*
752: * Do not remove the casts below. They are
753: * vital. When later compared with the data,
754: * the sign extension must have happened.
755: */
1.19 tedu 756: case FILE_BYTE:
1.1 deraadt 757: v = (char) v;
758: break;
1.19 tedu 759: case FILE_SHORT:
760: case FILE_BESHORT:
761: case FILE_LESHORT:
1.1 deraadt 762: v = (short) v;
763: break;
1.19 tedu 764: case FILE_DATE:
765: case FILE_BEDATE:
766: case FILE_LEDATE:
1.25 chl 767: case FILE_MEDATE:
1.19 tedu 768: case FILE_LDATE:
769: case FILE_BELDATE:
770: case FILE_LELDATE:
1.25 chl 771: case FILE_MELDATE:
1.19 tedu 772: case FILE_LONG:
773: case FILE_BELONG:
774: case FILE_LELONG:
1.25 chl 775: case FILE_MELONG:
1.26 chl 776: case FILE_FLOAT:
777: case FILE_BEFLOAT:
778: case FILE_LEFLOAT:
1.14 itojun 779: v = (int32_t) v;
1.1 deraadt 780: break;
1.25 chl 781: case FILE_QUAD:
782: case FILE_BEQUAD:
783: case FILE_LEQUAD:
784: case FILE_QDATE:
785: case FILE_QLDATE:
786: case FILE_BEQDATE:
787: case FILE_BEQLDATE:
788: case FILE_LEQDATE:
789: case FILE_LEQLDATE:
1.26 chl 790: case FILE_DOUBLE:
791: case FILE_BEDOUBLE:
792: case FILE_LEDOUBLE:
1.25 chl 793: v = (int64_t) v;
794: break;
1.19 tedu 795: case FILE_STRING:
796: case FILE_PSTRING:
1.25 chl 797: case FILE_BESTRING16:
798: case FILE_LESTRING16:
1.19 tedu 799: case FILE_REGEX:
1.25 chl 800: case FILE_SEARCH:
801: case FILE_DEFAULT:
1.1 deraadt 802: break;
803: default:
1.19 tedu 804: if (ms->flags & MAGIC_CHECK)
1.25 chl 805: file_magwarn(ms, "cannot happen: m->type=%d\n",
1.19 tedu 806: m->type);
807: return ~0U;
1.1 deraadt 808: }
1.25 chl 809: }
1.1 deraadt 810: return v;
811: }
812:
1.25 chl 813: private int
1.26 chl 814: string_modifier_check(struct magic_set *ms, struct magic *m)
1.25 chl 815: {
816: if ((ms->flags & MAGIC_CHECK) == 0)
817: return 0;
818:
819: switch (m->type) {
820: case FILE_BESTRING16:
821: case FILE_LESTRING16:
822: if (m->str_flags != 0) {
1.26 chl 823: file_magwarn(ms,
824: "no modifiers allowed for 16-bit strings\n");
1.25 chl 825: return -1;
826: }
827: break;
828: case FILE_STRING:
829: case FILE_PSTRING:
830: if ((m->str_flags & REGEX_OFFSET_START) != 0) {
1.26 chl 831: file_magwarn(ms,
832: "'/%c' only allowed on regex and search\n",
1.25 chl 833: CHAR_REGEX_OFFSET_START);
834: return -1;
835: }
836: break;
837: case FILE_SEARCH:
1.26 chl 838: if (m->str_range == 0) {
839: file_magwarn(ms,
840: "missing range; defaulting to %d\n",
841: STRING_DEFAULT_RANGE);
842: m->str_range = STRING_DEFAULT_RANGE;
843: return -1;
844: }
1.25 chl 845: break;
846: case FILE_REGEX:
847: if ((m->str_flags & STRING_COMPACT_BLANK) != 0) {
848: file_magwarn(ms, "'/%c' not allowed on regex\n",
849: CHAR_COMPACT_BLANK);
850: return -1;
851: }
852: if ((m->str_flags & STRING_COMPACT_OPTIONAL_BLANK) != 0) {
853: file_magwarn(ms, "'/%c' not allowed on regex\n",
854: CHAR_COMPACT_OPTIONAL_BLANK);
855: return -1;
856: }
857: break;
858: default:
859: file_magwarn(ms, "coding error: m->type=%d\n",
860: m->type);
861: return -1;
862: }
863: return 0;
864: }
865:
866: private int
867: get_op(char c)
868: {
869: switch (c) {
870: case '&':
871: return FILE_OPAND;
872: case '|':
873: return FILE_OPOR;
874: case '^':
875: return FILE_OPXOR;
876: case '+':
877: return FILE_OPADD;
878: case '-':
879: return FILE_OPMINUS;
880: case '*':
881: return FILE_OPMULTIPLY;
882: case '/':
883: return FILE_OPDIVIDE;
884: case '%':
885: return FILE_OPMODULO;
886: default:
887: return -1;
888: }
889: }
890:
891: #ifdef ENABLE_CONDITIONALS
892: private int
893: get_cond(const char *l, const char **t)
894: {
1.26 chl 895: static const struct cond_tbl_s {
896: char name[8];
897: size_t len;
898: int cond;
1.25 chl 899: } cond_tbl[] = {
900: { "if", 2, COND_IF },
901: { "elif", 4, COND_ELIF },
902: { "else", 4, COND_ELSE },
1.26 chl 903: { "", 0, COND_NONE },
1.25 chl 904: };
1.26 chl 905: const struct cond_tbl_s *p;
1.25 chl 906:
1.26 chl 907: for (p = cond_tbl; p->len; p++) {
1.25 chl 908: if (strncmp(l, p->name, p->len) == 0 &&
909: isspace((unsigned char)l[p->len])) {
910: if (t)
911: *t = l + p->len;
912: break;
913: }
914: }
915: return p->cond;
916: }
917:
918: private int
919: check_cond(struct magic_set *ms, int cond, uint32_t cont_level)
920: {
921: int last_cond;
922: last_cond = ms->c.li[cont_level].last_cond;
923:
924: switch (cond) {
925: case COND_IF:
926: if (last_cond != COND_NONE && last_cond != COND_ELIF) {
927: if (ms->flags & MAGIC_CHECK)
928: file_magwarn(ms, "syntax error: `if'");
929: return -1;
930: }
931: last_cond = COND_IF;
932: break;
933:
934: case COND_ELIF:
935: if (last_cond != COND_IF && last_cond != COND_ELIF) {
936: if (ms->flags & MAGIC_CHECK)
937: file_magwarn(ms, "syntax error: `elif'");
938: return -1;
939: }
940: last_cond = COND_ELIF;
941: break;
942:
943: case COND_ELSE:
944: if (last_cond != COND_IF && last_cond != COND_ELIF) {
945: if (ms->flags & MAGIC_CHECK)
946: file_magwarn(ms, "syntax error: `else'");
947: return -1;
948: }
949: last_cond = COND_NONE;
950: break;
951:
952: case COND_NONE:
953: last_cond = COND_NONE;
954: break;
955: }
956:
957: ms->c.li[cont_level].last_cond = last_cond;
958: return 0;
959: }
960: #endif /* ENABLE_CONDITIONALS */
961:
1.1 deraadt 962: /*
963: * parse one line from magic file, put into magic[index++] if valid
964: */
1.19 tedu 965: private int
1.25 chl 966: parse(struct magic_set *ms, struct magic_entry **mentryp, uint32_t *nmentryp,
967: const char *line, size_t lineno, int action)
1.1 deraadt 968: {
1.25 chl 969: #ifdef ENABLE_CONDITIONALS
970: static uint32_t last_cont_level = 0;
971: #endif
972: size_t i;
973: struct magic_entry *me;
1.1 deraadt 974: struct magic *m;
1.25 chl 975: const char *l = line;
1.19 tedu 976: char *t;
1.25 chl 977: int op;
978: uint32_t cont_level;
1.19 tedu 979:
1.25 chl 980: cont_level = 0;
1.1 deraadt 981:
982: while (*l == '>') {
983: ++l; /* step over */
1.25 chl 984: cont_level++;
1.1 deraadt 985: }
1.25 chl 986: #ifdef ENABLE_CONDITIONALS
987: if (cont_level == 0 || cont_level > last_cont_level)
988: if (file_check_mem(ms, cont_level) == -1)
989: return -1;
990: last_cont_level = cont_level;
991: #endif
992:
993: #define ALLOC_CHUNK (size_t)10
994: #define ALLOC_INCR (size_t)200
1.1 deraadt 995:
1.25 chl 996: if (cont_level != 0) {
997: if (*nmentryp == 0) {
998: file_error(ms, 0, "No current entry for continuation");
999: return -1;
1000: }
1001: me = &(*mentryp)[*nmentryp - 1];
1002: if (me->cont_count == me->max_count) {
1003: struct magic *nm;
1004: size_t cnt = me->max_count + ALLOC_CHUNK;
1005: if ((nm = realloc(me->mp, sizeof(*nm) * cnt)) == NULL) {
1006: file_oomem(ms, sizeof(*nm) * cnt);
1007: return -1;
1008: }
1009: me->mp = m = nm;
1010: me->max_count = cnt;
1011: }
1012: m = &me->mp[me->cont_count++];
1013: (void)memset(m, 0, sizeof(*m));
1014: m->cont_level = cont_level;
1015: } else {
1016: if (*nmentryp == maxmagic) {
1017: struct magic_entry *mp;
1018:
1019: maxmagic += ALLOC_INCR;
1020: if ((mp = realloc(*mentryp, sizeof(*mp) * maxmagic)) ==
1021: NULL) {
1022: file_oomem(ms, sizeof(*mp) * maxmagic);
1023: return -1;
1024: }
1025: (void)memset(&mp[*nmentryp], 0, sizeof(*mp) *
1026: ALLOC_INCR);
1027: *mentryp = mp;
1028: }
1029: me = &(*mentryp)[*nmentryp];
1030: if (me->mp == NULL) {
1031: if ((m = malloc(sizeof(*m) * ALLOC_CHUNK)) == NULL) {
1032: file_oomem(ms, sizeof(*m) * ALLOC_CHUNK);
1033: return -1;
1034: }
1035: me->mp = m;
1036: me->max_count = ALLOC_CHUNK;
1037: } else
1038: m = me->mp;
1039: (void)memset(m, 0, sizeof(*m));
1040: m->cont_level = 0;
1041: me->cont_count = 1;
1.1 deraadt 1042: }
1.25 chl 1043: m->lineno = lineno;
1044:
1045: if (*l == '&') { /* m->cont_level == 0 checked below. */
1.4 millert 1046: ++l; /* step over */
1.19 tedu 1047: m->flag |= OFFADD;
1.4 millert 1048: }
1.25 chl 1049: if (*l == '(') {
1050: ++l; /* step over */
1051: m->flag |= INDIR;
1052: if (m->flag & OFFADD)
1053: m->flag = (m->flag & ~OFFADD) | INDIROFFADD;
1054:
1055: if (*l == '&') { /* m->cont_level == 0 checked below */
1056: ++l; /* step over */
1057: m->flag |= OFFADD;
1058: }
1059: }
1060: /* Indirect offsets are not valid at level 0. */
1061: if (m->cont_level == 0 && (m->flag & (OFFADD | INDIROFFADD)))
1062: if (ms->flags & MAGIC_CHECK)
1063: file_magwarn(ms, "relative offset at level 0");
1.1 deraadt 1064:
1065: /* get offset, then skip over it */
1.19 tedu 1066: m->offset = (uint32_t)strtoul(l, &t, 0);
1.1 deraadt 1067: if (l == t)
1.19 tedu 1068: if (ms->flags & MAGIC_CHECK)
1.25 chl 1069: file_magwarn(ms, "offset `%s' invalid", l);
1.1 deraadt 1070: l = t;
1071:
1072: if (m->flag & INDIR) {
1.19 tedu 1073: m->in_type = FILE_LONG;
1074: m->in_offset = 0;
1.1 deraadt 1075: /*
1076: * read [.lbs][+-]nnnnn)
1077: */
1078: if (*l == '.') {
1079: l++;
1.19 tedu 1080: switch (*l) {
1.1 deraadt 1081: case 'l':
1.19 tedu 1082: m->in_type = FILE_LELONG;
1083: break;
1084: case 'L':
1085: m->in_type = FILE_BELONG;
1.1 deraadt 1086: break;
1.25 chl 1087: case 'm':
1088: m->in_type = FILE_MELONG;
1089: break;
1.1 deraadt 1090: case 'h':
1091: case 's':
1.19 tedu 1092: m->in_type = FILE_LESHORT;
1093: break;
1094: case 'H':
1095: case 'S':
1096: m->in_type = FILE_BESHORT;
1.1 deraadt 1097: break;
1098: case 'c':
1099: case 'b':
1.19 tedu 1100: case 'C':
1101: case 'B':
1102: m->in_type = FILE_BYTE;
1.1 deraadt 1103: break;
1.26 chl 1104: case 'e':
1105: case 'f':
1106: case 'g':
1107: m->in_type = FILE_LEDOUBLE;
1108: break;
1109: case 'E':
1110: case 'F':
1111: case 'G':
1112: m->in_type = FILE_BEDOUBLE;
1113: break;
1.1 deraadt 1114: default:
1.19 tedu 1115: if (ms->flags & MAGIC_CHECK)
1.25 chl 1116: file_magwarn(ms,
1117: "indirect offset type `%c' invalid",
1.19 tedu 1118: *l);
1.1 deraadt 1119: break;
1120: }
1121: l++;
1122: }
1.25 chl 1123:
1124: m->in_op = 0;
1.19 tedu 1125: if (*l == '~') {
1.25 chl 1126: m->in_op |= FILE_OPINVERSE;
1.19 tedu 1127: l++;
1128: }
1.25 chl 1129: if ((op = get_op(*l)) != -1) {
1130: m->in_op |= op;
1.19 tedu 1131: l++;
1.25 chl 1132: }
1133: if (*l == '(') {
1134: m->in_op |= FILE_OPINDIRECT;
1.19 tedu 1135: l++;
1.1 deraadt 1136: }
1.25 chl 1137: if (isdigit((unsigned char)*l) || *l == '-') {
1138: m->in_offset = (int32_t)strtol(l, &t, 0);
1139: if (l == t)
1140: if (ms->flags & MAGIC_CHECK)
1141: file_magwarn(ms,
1142: "in_offset `%s' invalid", l);
1143: l = t;
1144: }
1145: if (*l++ != ')' ||
1146: ((m->in_op & FILE_OPINDIRECT) && *l++ != ')'))
1.19 tedu 1147: if (ms->flags & MAGIC_CHECK)
1.25 chl 1148: file_magwarn(ms,
1149: "missing ')' in indirect offset");
1.1 deraadt 1150: }
1.25 chl 1151: EATAB;
1.1 deraadt 1152:
1.25 chl 1153: #ifdef ENABLE_CONDITIONALS
1154: m->cond = get_cond(l, &l);
1155: if (check_cond(ms, m->cond, cont_level) == -1)
1156: return -1;
1.1 deraadt 1157:
1158: EATAB;
1.25 chl 1159: #endif
1.1 deraadt 1160:
1161: if (*l == 'u') {
1162: ++l;
1163: m->flag |= UNSIGNED;
1164: }
1165:
1.25 chl 1166: m->type = get_type(l, &l);
1167: if (m->type == FILE_INVALID) {
1.19 tedu 1168: if (ms->flags & MAGIC_CHECK)
1.25 chl 1169: file_magwarn(ms, "type `%s' invalid", l);
1.1 deraadt 1170: return -1;
1171: }
1.25 chl 1172:
1.1 deraadt 1173: /* New-style anding: "0 byte&0x80 =0x80 dynamically linked" */
1.19 tedu 1174: /* New and improved: ~ & | ^ + - * / % -- exciting, isn't it? */
1.25 chl 1175:
1176: m->mask_op = 0;
1.19 tedu 1177: if (*l == '~') {
1.25 chl 1178: if (!IS_STRING(m->type))
1179: m->mask_op |= FILE_OPINVERSE;
1180: else if (ms->flags & MAGIC_CHECK)
1181: file_magwarn(ms, "'~' invalid for string types");
1.1 deraadt 1182: ++l;
1.19 tedu 1183: }
1.26 chl 1184: m->str_range = 0;
1.25 chl 1185: m->str_flags = 0;
1186: m->num_mask = 0;
1187: if ((op = get_op(*l)) != -1) {
1188: if (!IS_STRING(m->type)) {
1189: uint64_t val;
1.19 tedu 1190: ++l;
1191: m->mask_op |= op;
1.25 chl 1192: val = (uint64_t)strtoull(l, &t, 0);
1193: l = t;
1194: m->num_mask = file_signextend(ms, m, val);
1.19 tedu 1195: eatsize(&l);
1.25 chl 1196: }
1197: else if (op == FILE_OPDIVIDE) {
1.26 chl 1198: int have_range = 0;
1.19 tedu 1199: while (!isspace((unsigned char)*++l)) {
1200: switch (*l) {
1.25 chl 1201: case '0': case '1': case '2':
1202: case '3': case '4': case '5':
1203: case '6': case '7': case '8':
1.26 chl 1204: case '9':
1205: if (have_range &&
1206: (ms->flags & MAGIC_CHECK))
1.25 chl 1207: file_magwarn(ms,
1.26 chl 1208: "multiple ranges");
1209: have_range = 1;
1210: m->str_range = strtoul(l, &t, 0);
1211: if (m->str_range == 0)
1212: file_magwarn(ms,
1213: "zero range");
1.25 chl 1214: l = t - 1;
1.19 tedu 1215: break;
1216: case CHAR_COMPACT_BLANK:
1.25 chl 1217: m->str_flags |= STRING_COMPACT_BLANK;
1.19 tedu 1218: break;
1219: case CHAR_COMPACT_OPTIONAL_BLANK:
1.25 chl 1220: m->str_flags |=
1.19 tedu 1221: STRING_COMPACT_OPTIONAL_BLANK;
1222: break;
1.25 chl 1223: case CHAR_IGNORE_LOWERCASE:
1224: m->str_flags |= STRING_IGNORE_LOWERCASE;
1225: break;
1226: case CHAR_IGNORE_UPPERCASE:
1227: m->str_flags |= STRING_IGNORE_UPPERCASE;
1228: break;
1229: case CHAR_REGEX_OFFSET_START:
1230: m->str_flags |= REGEX_OFFSET_START;
1231: break;
1.19 tedu 1232: default:
1233: if (ms->flags & MAGIC_CHECK)
1.25 chl 1234: file_magwarn(ms,
1235: "string extension `%c' invalid",
1.19 tedu 1236: *l);
1237: return -1;
1238: }
1.25 chl 1239: /* allow multiple '/' for readability */
1.26 chl 1240: if (l[1] == '/' &&
1241: !isspace((unsigned char)l[2]))
1.25 chl 1242: l++;
1.19 tedu 1243: }
1.25 chl 1244: if (string_modifier_check(ms, m) == -1)
1245: return -1;
1246: }
1247: else {
1248: if (ms->flags & MAGIC_CHECK)
1249: file_magwarn(ms, "invalid string op: %c", *t);
1250: return -1;
1.19 tedu 1251: }
1252: }
1253: /*
1254: * We used to set mask to all 1's here, instead let's just not do
1255: * anything if mask = 0 (unless you have a better idea)
1256: */
1.1 deraadt 1257: EATAB;
1258:
1259: switch (*l) {
1260: case '>':
1261: case '<':
1262: /* Old-style anding: "0 byte &0x80 dynamically linked" */
1263: case '&':
1264: case '^':
1265: case '=':
1266: m->reln = *l;
1267: ++l;
1.19 tedu 1268: if (*l == '=') {
1269: /* HP compat: ignore &= etc. */
1270: ++l;
1271: }
1.1 deraadt 1272: break;
1273: case '!':
1.25 chl 1274: m->reln = *l;
1275: ++l;
1276: break;
1.1 deraadt 1277: default:
1.25 chl 1278: m->reln = '='; /* the default relation */
1279: if (*l == 'x' && ((isascii((unsigned char)l[1]) &&
1280: isspace((unsigned char)l[1])) || !l[1])) {
1.1 deraadt 1281: m->reln = *l;
1282: ++l;
1283: }
1284: break;
1285: }
1.25 chl 1286: /*
1287: * Grab the value part, except for an 'x' reln.
1288: */
1289: if (m->reln != 'x' && getvalue(ms, m, &l, action))
1.1 deraadt 1290: return -1;
1.25 chl 1291:
1.1 deraadt 1292: /*
1293: * TODO finish this macro and start using it!
1294: * #define offsetcheck {if (offset > HOWMANY-1)
1.19 tedu 1295: * magwarn("offset too big"); }
1.1 deraadt 1296: */
1297:
1298: /*
1.25 chl 1299: * Now get last part - the description
1.1 deraadt 1300: */
1301: EATAB;
1302: if (l[0] == '\b') {
1303: ++l;
1.26 chl 1304: m->flag |= NOSPACE;
1.1 deraadt 1305: } else if ((l[0] == '\\') && (l[1] == 'b')) {
1306: ++l;
1307: ++l;
1.26 chl 1308: m->flag |= NOSPACE;
1309: }
1.25 chl 1310: for (i = 0; (m->desc[i++] = *l++) != '\0' && i < sizeof(m->desc); )
1311: continue;
1312: if (i == sizeof(m->desc)) {
1313: m->desc[sizeof(m->desc) - 1] = '\0';
1314: if (ms->flags & MAGIC_CHECK)
1315: file_magwarn(ms, "description `%s' truncated", m->desc);
1316: }
1.21 pedro 1317:
1.25 chl 1318: /*
1319: * We only do this check while compiling, or if any of the magic
1320: * files were not compiled.
1321: */
1322: if (ms->flags & MAGIC_CHECK) {
1323: if (check_format(ms, m) == -1)
1324: return -1;
1325: }
1.19 tedu 1326: #ifndef COMPILE_ONLY
1327: if (action == FILE_CHECK) {
1328: file_mdump(m);
1.1 deraadt 1329: }
1.19 tedu 1330: #endif
1.26 chl 1331: m->mimetype[0] = '\0'; /* initialise MIME type to none */
1.25 chl 1332: if (m->cont_level == 0)
1333: ++(*nmentryp); /* make room for next */
1334: return 0;
1335: }
1336:
1.26 chl 1337: /*
1338: * parse a MIME annotation line from magic file, put into magic[index - 1]
1339: * if valid
1340: */
1341: private int
1342: parse_mime(struct magic_set *ms, struct magic_entry **mentryp,
1343: uint32_t *nmentryp, const char *line)
1344: {
1345: size_t i;
1346: const char *l = line;
1347: struct magic *m;
1348: struct magic_entry *me;
1349:
1350: if (*nmentryp == 0) {
1351: file_error(ms, 0, "No current entry for MIME type");
1352: return -1;
1353: }
1354:
1355: me = &(*mentryp)[*nmentryp - 1];
1356: m = &me->mp[me->cont_count == 0 ? 0 : me->cont_count - 1];
1357:
1358: if (m->mimetype[0] != '\0') {
1359: file_error(ms, 0, "Current entry already has a MIME type: %s\n"
1360: "Description: %s\nNew type: %s", m->mimetype, m->desc, l);
1361: return -1;
1362: }
1363:
1364: EATAB;
1365: for (i = 0;
1366: *l && ((isascii((unsigned char)*l) && isalnum((unsigned char)*l))
1367: || strchr("-+/.", *l)) && i < sizeof(m->mimetype);
1368: m->mimetype[i++] = *l++)
1369: continue;
1370: if (i == sizeof(m->mimetype)) {
1371: m->desc[sizeof(m->mimetype) - 1] = '\0';
1372: if (ms->flags & MAGIC_CHECK)
1373: file_magwarn(ms, "MIME type `%s' truncated %zu",
1374: m->mimetype, i);
1375: } else
1376: m->mimetype[i] = '\0';
1377:
1378: if (i > 0)
1379: return 0;
1380: else
1381: return -1;
1382: }
1383:
1.25 chl 1384: private int
1385: check_format_type(const char *ptr, int type)
1386: {
1387: int quad = 0;
1388: if (*ptr == '\0') {
1389: /* Missing format string; bad */
1390: return -1;
1391: }
1392:
1393: switch (type) {
1394: case FILE_FMT_QUAD:
1395: quad = 1;
1396: /*FALLTHROUGH*/
1397: case FILE_FMT_NUM:
1398: if (*ptr == '-')
1399: ptr++;
1400: if (*ptr == '.')
1401: ptr++;
1402: while (isdigit((unsigned char)*ptr)) ptr++;
1403: if (*ptr == '.')
1404: ptr++;
1405: while (isdigit((unsigned char)*ptr)) ptr++;
1406: if (quad) {
1407: if (*ptr++ != 'l')
1408: return -1;
1409: if (*ptr++ != 'l')
1410: return -1;
1411: }
1412:
1413: switch (*ptr++) {
1414: case 'l':
1415: switch (*ptr++) {
1416: case 'i':
1417: case 'd':
1418: case 'u':
1419: case 'x':
1420: case 'X':
1421: return 0;
1422: default:
1423: return -1;
1424: }
1425:
1426: case 'h':
1427: switch (*ptr++) {
1428: case 'h':
1429: switch (*ptr++) {
1430: case 'i':
1431: case 'd':
1432: case 'u':
1433: case 'x':
1434: case 'X':
1435: return 0;
1436: default:
1437: return -1;
1438: }
1439: case 'd':
1440: return 0;
1441: default:
1442: return -1;
1443: }
1444:
1445: case 'i':
1446: case 'c':
1447: case 'd':
1448: case 'u':
1449: case 'x':
1450: case 'X':
1451: return 0;
1452:
1453: default:
1454: return -1;
1455: }
1456:
1.26 chl 1457: case FILE_FMT_FLOAT:
1458: case FILE_FMT_DOUBLE:
1459: if (*ptr == '-')
1460: ptr++;
1461: if (*ptr == '.')
1462: ptr++;
1463: while (isdigit((unsigned char)*ptr)) ptr++;
1464: if (*ptr == '.')
1465: ptr++;
1466: while (isdigit((unsigned char)*ptr)) ptr++;
1467:
1468: switch (*ptr++) {
1469: case 'e':
1470: case 'E':
1471: case 'f':
1472: case 'F':
1473: case 'g':
1474: case 'G':
1475: return 0;
1476:
1477: default:
1478: return -1;
1479: }
1480:
1481:
1.25 chl 1482: case FILE_FMT_STR:
1483: if (*ptr == '-')
1484: ptr++;
1485: while (isdigit((unsigned char )*ptr))
1486: ptr++;
1487: if (*ptr == '.') {
1488: ptr++;
1489: while (isdigit((unsigned char )*ptr))
1490: ptr++;
1491: }
1492:
1493: switch (*ptr++) {
1494: case 's':
1495: return 0;
1496: default:
1497: return -1;
1498: }
1499:
1500: default:
1501: /* internal error */
1502: abort();
1503: }
1504: /*NOTREACHED*/
1505: return -1;
1506: }
1507:
1508: /*
1509: * Check that the optional printf format in description matches
1510: * the type of the magic.
1511: */
1512: private int
1513: check_format(struct magic_set *ms, struct magic *m)
1514: {
1515: char *ptr;
1516:
1517: for (ptr = m->desc; *ptr; ptr++)
1518: if (*ptr == '%')
1519: break;
1520: if (*ptr == '\0') {
1521: /* No format string; ok */
1522: return 1;
1523: }
1524:
1525: assert(file_nformats == file_nnames);
1526:
1527: if (m->type >= file_nformats) {
1.26 chl 1528: file_magwarn(ms, "Internal error inconsistency between "
1.25 chl 1529: "m->type and format strings");
1530: return -1;
1531: }
1532: if (file_formats[m->type] == FILE_FMT_NONE) {
1.26 chl 1533: file_magwarn(ms, "No format string for `%s' with description "
1.25 chl 1534: "`%s'", m->desc, file_names[m->type]);
1535: return -1;
1536: }
1537:
1538: ptr++;
1539: if (check_format_type(ptr, file_formats[m->type]) == -1) {
1540: /*
1541: * TODO: this error message is unhelpful if the format
1542: * string is not one character long
1543: */
1.26 chl 1544: file_magwarn(ms, "Printf format `%c' is not valid for type "
1545: "`%s' in description `%s'",
1.25 chl 1546: ptr && *ptr ? *ptr : '?',
1547: file_names[m->type], m->desc);
1548: return -1;
1549: }
1550:
1551: for (; *ptr; ptr++) {
1552: if (*ptr == '%') {
1.26 chl 1553: file_magwarn(ms,
1.25 chl 1554: "Too many format strings (should have at most one) "
1555: "for `%s' with description `%s'",
1556: file_names[m->type], m->desc);
1557: return -1;
1558: }
1559: }
1.1 deraadt 1560: return 0;
1561: }
1562:
1563: /*
1564: * Read a numeric value from a pointer, into the value union of a magic
1565: * pointer, according to the magic type. Update the string pointer to point
1566: * just after the number read. Return 0 for success, non-zero for failure.
1567: */
1.19 tedu 1568: private int
1.25 chl 1569: getvalue(struct magic_set *ms, struct magic *m, const char **p, int action)
1.1 deraadt 1570: {
1571: int slen;
1572:
1.19 tedu 1573: switch (m->type) {
1.25 chl 1574: case FILE_BESTRING16:
1575: case FILE_LESTRING16:
1.19 tedu 1576: case FILE_STRING:
1577: case FILE_PSTRING:
1578: case FILE_REGEX:
1.25 chl 1579: case FILE_SEARCH:
1580: *p = getstr(ms, *p, m->value.s, sizeof(m->value.s), &slen, action);
1.19 tedu 1581: if (*p == NULL) {
1582: if (ms->flags & MAGIC_CHECK)
1.25 chl 1583: file_magwarn(ms, "cannot get string from `%s'",
1.19 tedu 1584: m->value.s);
1585: return -1;
1586: }
1.1 deraadt 1587: m->vallen = slen;
1.26 chl 1588: if (m->type == FILE_PSTRING)
1589: m->vallen++;
1590: return 0;
1591: case FILE_FLOAT:
1592: case FILE_BEFLOAT:
1593: case FILE_LEFLOAT:
1594: if (m->reln != 'x') {
1595: char *ep;
1596: #ifdef HAVE_STRTOF
1597: m->value.f = strtof(*p, &ep);
1598: #else
1599: m->value.f = (float)strtod(*p, &ep);
1600: #endif
1601: *p = ep;
1602: }
1603: return 0;
1604: case FILE_DOUBLE:
1605: case FILE_BEDOUBLE:
1606: case FILE_LEDOUBLE:
1607: if (m->reln != 'x') {
1608: char *ep;
1609: m->value.d = strtod(*p, &ep);
1610: *p = ep;
1611: }
1.19 tedu 1612: return 0;
1613: default:
1.1 deraadt 1614: if (m->reln != 'x') {
1.25 chl 1615: char *ep;
1616: m->value.q = file_signextend(ms, m,
1617: (uint64_t)strtoull(*p, &ep, 0));
1618: *p = ep;
1.1 deraadt 1619: eatsize(p);
1620: }
1.19 tedu 1621: return 0;
1622: }
1.1 deraadt 1623: }
1624:
1625: /*
1626: * Convert a string containing C character escapes. Stop at an unescaped
1627: * space or tab.
1628: * Copy the converted version to "p", returning its length in *slen.
1629: * Return updated scan pointer as function result.
1630: */
1.25 chl 1631: private const char *
1632: getstr(struct magic_set *ms, const char *s, char *p, int plen, int *slen, int action)
1.1 deraadt 1633: {
1.25 chl 1634: const char *origs = s;
1635: char *origp = p;
1.1 deraadt 1636: char *pmax = p + plen - 1;
1.11 mpech 1637: int c;
1638: int val;
1.1 deraadt 1639:
1640: while ((c = *s++) != '\0') {
1641: if (isspace((unsigned char) c))
1642: break;
1643: if (p >= pmax) {
1.19 tedu 1644: file_error(ms, 0, "string too long: `%s'", origs);
1645: return NULL;
1.1 deraadt 1646: }
1.25 chl 1647: if (c == '\\') {
1.1 deraadt 1648: switch(c = *s++) {
1649:
1650: case '\0':
1.25 chl 1651: if (action == FILE_COMPILE)
1652: file_magwarn(ms, "incomplete escape");
1.1 deraadt 1653: goto out;
1654:
1.25 chl 1655: case '\t':
1656: if (action == FILE_COMPILE) {
1657: file_magwarn(ms,
1658: "escaped tab found, use \\t instead");
1659: action++;
1660: }
1661: /*FALLTHROUGH*/
1.1 deraadt 1662: default:
1.25 chl 1663: if (action == FILE_COMPILE) {
1664: if (isprint((unsigned char)c))
1665: file_magwarn(ms,
1666: "no need to escape `%c'", c);
1667: else
1668: file_magwarn(ms,
1669: "unknown escape sequence: \\%03o", c);
1670: }
1671: /*FALLTHROUGH*/
1672: /* space, perhaps force people to use \040? */
1673: case ' ':
1674: #if 0
1675: /*
1676: * Other things people escape, but shouldn't need to,
1677: * so we disallow them
1678: */
1679: case '\'':
1680: case '"':
1681: case '?':
1682: #endif
1683: /* Relations */
1684: case '>':
1685: case '<':
1686: case '&':
1687: case '^':
1688: case '=':
1689: case '!':
1690: /* and baskslash itself */
1691: case '\\':
1.1 deraadt 1692: *p++ = (char) c;
1693: break;
1694:
1.25 chl 1695: case 'a':
1696: *p++ = '\a';
1697: break;
1698:
1699: case 'b':
1700: *p++ = '\b';
1701: break;
1702:
1703: case 'f':
1704: *p++ = '\f';
1705: break;
1706:
1.1 deraadt 1707: case 'n':
1708: *p++ = '\n';
1709: break;
1710:
1711: case 'r':
1712: *p++ = '\r';
1713: break;
1714:
1715: case 't':
1716: *p++ = '\t';
1717: break;
1718:
1719: case 'v':
1720: *p++ = '\v';
1721: break;
1722:
1723: /* \ and up to 3 octal digits */
1724: case '0':
1725: case '1':
1726: case '2':
1727: case '3':
1728: case '4':
1729: case '5':
1730: case '6':
1731: case '7':
1732: val = c - '0';
1733: c = *s++; /* try for 2 */
1.25 chl 1734: if (c >= '0' && c <= '7') {
1735: val = (val << 3) | (c - '0');
1.1 deraadt 1736: c = *s++; /* try for 3 */
1.25 chl 1737: if (c >= '0' && c <= '7')
1738: val = (val << 3) | (c-'0');
1.1 deraadt 1739: else
1740: --s;
1741: }
1742: else
1743: --s;
1744: *p++ = (char)val;
1745: break;
1746:
1.4 millert 1747: /* \x and up to 2 hex digits */
1.1 deraadt 1748: case 'x':
1749: val = 'x'; /* Default if no digits */
1750: c = hextoint(*s++); /* Get next char */
1751: if (c >= 0) {
1752: val = c;
1753: c = hextoint(*s++);
1.4 millert 1754: if (c >= 0)
1.1 deraadt 1755: val = (val << 4) + c;
1.4 millert 1756: else
1.1 deraadt 1757: --s;
1758: } else
1759: --s;
1760: *p++ = (char)val;
1761: break;
1762: }
1763: } else
1764: *p++ = (char)c;
1765: }
1766: out:
1767: *p = '\0';
1768: *slen = p - origp;
1769: return s;
1770: }
1771:
1772:
1773: /* Single hex char to int; -1 if not a hex char. */
1.19 tedu 1774: private int
1775: hextoint(int c)
1776: {
1777: if (!isascii((unsigned char) c))
1778: return -1;
1779: if (isdigit((unsigned char) c))
1780: return c - '0';
1.25 chl 1781: if ((c >= 'a') && (c <= 'f'))
1.19 tedu 1782: return c + 10 - 'a';
1.25 chl 1783: if (( c>= 'A') && (c <= 'F'))
1.19 tedu 1784: return c + 10 - 'A';
1785: return -1;
1.1 deraadt 1786: }
1787:
1788:
1789: /*
1790: * Print a string containing C character escapes.
1791: */
1.19 tedu 1792: protected void
1793: file_showstr(FILE *fp, const char *s, size_t len)
1.1 deraadt 1794: {
1.11 mpech 1795: char c;
1.1 deraadt 1796:
1797: for (;;) {
1798: c = *s++;
1.19 tedu 1799: if (len == ~0U) {
1.1 deraadt 1800: if (c == '\0')
1801: break;
1802: }
1803: else {
1804: if (len-- == 0)
1805: break;
1806: }
1.25 chl 1807: if (c >= 040 && c <= 0176) /* TODO isprint && !iscntrl */
1.1 deraadt 1808: (void) fputc(c, fp);
1809: else {
1810: (void) fputc('\\', fp);
1811: switch (c) {
1.25 chl 1812: case '\a':
1813: (void) fputc('a', fp);
1814: break;
1815:
1816: case '\b':
1817: (void) fputc('b', fp);
1818: break;
1819:
1820: case '\f':
1821: (void) fputc('f', fp);
1822: break;
1823:
1.1 deraadt 1824: case '\n':
1825: (void) fputc('n', fp);
1826: break;
1827:
1828: case '\r':
1829: (void) fputc('r', fp);
1830: break;
1831:
1832: case '\t':
1833: (void) fputc('t', fp);
1834: break;
1835:
1836: case '\v':
1837: (void) fputc('v', fp);
1838: break;
1839:
1840: default:
1841: (void) fprintf(fp, "%.3o", c & 0377);
1842: break;
1843: }
1844: }
1845: }
1846: }
1847:
1848: /*
1849: * eatsize(): Eat the size spec from a number [eg. 10UL]
1850: */
1.19 tedu 1851: private void
1.25 chl 1852: eatsize(const char **p)
1.1 deraadt 1853: {
1.25 chl 1854: const char *l = *p;
1.1 deraadt 1855:
1856: if (LOWCASE(*l) == 'u')
1857: l++;
1858:
1859: switch (LOWCASE(*l)) {
1860: case 'l': /* long */
1861: case 's': /* short */
1862: case 'h': /* short */
1863: case 'b': /* char/byte */
1864: case 'c': /* char/byte */
1865: l++;
1866: /*FALLTHROUGH*/
1867: default:
1868: break;
1869: }
1870:
1871: *p = l;
1.19 tedu 1872: }
1873:
1874: /*
1875: * handle a compiled file.
1876: */
1877: private int
1878: apprentice_map(struct magic_set *ms, struct magic **magicp, uint32_t *nmagicp,
1879: const char *fn)
1880: {
1881: int fd;
1882: struct stat st;
1883: uint32_t *ptr;
1884: uint32_t version;
1885: int needsbyteswap;
1.26 chl 1886: char *dbname = NULL;
1.19 tedu 1887: void *mm = NULL;
1888:
1.26 chl 1889: mkdbname(fn, &dbname, 0);
1.19 tedu 1890: if (dbname == NULL)
1.26 chl 1891: goto error2;
1.19 tedu 1892:
1.25 chl 1893: if ((fd = open(dbname, O_RDONLY|O_BINARY)) == -1)
1.26 chl 1894: goto error2;
1.19 tedu 1895:
1896: if (fstat(fd, &st) == -1) {
1897: file_error(ms, errno, "cannot stat `%s'", dbname);
1.26 chl 1898: goto error1;
1.19 tedu 1899: }
1.26 chl 1900: if (st.st_size < 8) {
1.19 tedu 1901: file_error(ms, 0, "file `%s' is too small", dbname);
1.26 chl 1902: goto error1;
1.19 tedu 1903: }
1904:
1905: #ifdef QUICK
1906: if ((mm = mmap(0, (size_t)st.st_size, PROT_READ|PROT_WRITE,
1907: MAP_PRIVATE|MAP_FILE, fd, (off_t)0)) == MAP_FAILED) {
1908: file_error(ms, errno, "cannot map `%s'", dbname);
1.26 chl 1909: goto error1;
1.19 tedu 1910: }
1911: #define RET 2
1912: #else
1913: if ((mm = malloc((size_t)st.st_size)) == NULL) {
1.25 chl 1914: file_oomem(ms, (size_t)st.st_size);
1.26 chl 1915: goto error1;
1.19 tedu 1916: }
1917: if (read(fd, mm, (size_t)st.st_size) != (size_t)st.st_size) {
1918: file_badread(ms);
1.26 chl 1919: goto error1;
1.19 tedu 1920: }
1921: #define RET 1
1922: #endif
1923: *magicp = mm;
1924: (void)close(fd);
1925: fd = -1;
1926: ptr = (uint32_t *)(void *)*magicp;
1927: if (*ptr != MAGICNO) {
1928: if (swap4(*ptr) != MAGICNO) {
1929: file_error(ms, 0, "bad magic in `%s'");
1.26 chl 1930: goto error1;
1.19 tedu 1931: }
1932: needsbyteswap = 1;
1933: } else
1934: needsbyteswap = 0;
1935: if (needsbyteswap)
1936: version = swap4(ptr[1]);
1937: else
1938: version = ptr[1];
1939: if (version != VERSIONNO) {
1.26 chl 1940: file_error(ms, 0, "File %d.%d supports only %d version magic "
1941: "files. `%s' is version %d", FILE_VERSION_MAJOR, patchlevel,
1942: VERSIONNO, dbname, version);
1943: goto error1;
1944: }
1945: *nmagicp = (uint32_t)(st.st_size / sizeof(struct magic));
1946: if (*nmagicp > 0)
1947: (*nmagicp)--;
1.19 tedu 1948: (*magicp)++;
1949: if (needsbyteswap)
1950: byteswap(*magicp, *nmagicp);
1.26 chl 1951: free(dbname);
1.19 tedu 1952: return RET;
1953:
1.26 chl 1954: error1:
1.19 tedu 1955: if (fd != -1)
1956: (void)close(fd);
1957: if (mm) {
1958: #ifdef QUICK
1959: (void)munmap((void *)mm, (size_t)st.st_size);
1960: #else
1961: free(mm);
1962: #endif
1963: } else {
1964: *magicp = NULL;
1965: *nmagicp = 0;
1966: }
1.26 chl 1967: error2:
1968: free(dbname);
1.19 tedu 1969: return -1;
1970: }
1971:
1972: private const uint32_t ar[] = {
1973: MAGICNO, VERSIONNO
1974: };
1975: /*
1976: * handle an mmaped file.
1977: */
1978: private int
1979: apprentice_compile(struct magic_set *ms, struct magic **magicp,
1980: uint32_t *nmagicp, const char *fn)
1981: {
1982: int fd;
1.26 chl 1983: char *dbname;
1984: int rv = -1;
1985:
1986: mkdbname(fn, &dbname, 1);
1.19 tedu 1987:
1988: if (dbname == NULL)
1.26 chl 1989: goto out;
1.19 tedu 1990:
1.25 chl 1991: if ((fd = open(dbname, O_WRONLY|O_CREAT|O_TRUNC|O_BINARY, 0644)) == -1) {
1.19 tedu 1992: file_error(ms, errno, "cannot open `%s'", dbname);
1.26 chl 1993: goto out;
1.19 tedu 1994: }
1995:
1996: if (write(fd, ar, sizeof(ar)) != (ssize_t)sizeof(ar)) {
1997: file_error(ms, errno, "error writing `%s'", dbname);
1.26 chl 1998: goto out;
1.19 tedu 1999: }
2000:
2001: if (lseek(fd, (off_t)sizeof(struct magic), SEEK_SET)
2002: != sizeof(struct magic)) {
2003: file_error(ms, errno, "error seeking `%s'", dbname);
1.26 chl 2004: goto out;
1.19 tedu 2005: }
2006:
2007: if (write(fd, *magicp, (sizeof(struct magic) * *nmagicp))
2008: != (ssize_t)(sizeof(struct magic) * *nmagicp)) {
2009: file_error(ms, errno, "error writing `%s'", dbname);
1.26 chl 2010: goto out;
1.19 tedu 2011: }
2012:
2013: (void)close(fd);
1.26 chl 2014: rv = 0;
2015: out:
2016: free(dbname);
2017: return rv;
1.19 tedu 2018: }
2019:
2020: private const char ext[] = ".mgc";
2021: /*
2022: * make a dbname
2023: */
1.26 chl 2024: private void
2025: mkdbname(const char *fn, char **buf, int strip)
1.19 tedu 2026: {
1.25 chl 2027: if (strip) {
2028: const char *p;
2029: if ((p = strrchr(fn, '/')) != NULL)
2030: fn = ++p;
2031: }
2032:
1.26 chl 2033: (void)asprintf(buf, "%s%s", fn, ext);
2034: if (*buf && strlen(*buf) > MAXPATHLEN) {
2035: free(*buf);
2036: *buf = NULL;
2037: }
1.19 tedu 2038: }
2039:
2040: /*
2041: * Byteswap an mmap'ed file if needed
2042: */
2043: private void
2044: byteswap(struct magic *magic, uint32_t nmagic)
2045: {
2046: uint32_t i;
2047: for (i = 0; i < nmagic; i++)
2048: bs1(&magic[i]);
2049: }
2050:
2051: /*
2052: * swap a short
2053: */
2054: private uint16_t
2055: swap2(uint16_t sv)
2056: {
2057: uint16_t rv;
2058: uint8_t *s = (uint8_t *)(void *)&sv;
2059: uint8_t *d = (uint8_t *)(void *)&rv;
2060: d[0] = s[1];
2061: d[1] = s[0];
2062: return rv;
2063: }
2064:
2065: /*
2066: * swap an int
2067: */
2068: private uint32_t
2069: swap4(uint32_t sv)
2070: {
2071: uint32_t rv;
2072: uint8_t *s = (uint8_t *)(void *)&sv;
2073: uint8_t *d = (uint8_t *)(void *)&rv;
2074: d[0] = s[3];
2075: d[1] = s[2];
2076: d[2] = s[1];
2077: d[3] = s[0];
2078: return rv;
2079: }
2080:
2081: /*
1.25 chl 2082: * swap a quad
2083: */
2084: private uint64_t
2085: swap8(uint64_t sv)
2086: {
2087: uint32_t rv;
2088: uint8_t *s = (uint8_t *)(void *)&sv;
2089: uint8_t *d = (uint8_t *)(void *)&rv;
1.26 chl 2090: #if 0
1.25 chl 2091: d[0] = s[3];
2092: d[1] = s[2];
2093: d[2] = s[1];
2094: d[3] = s[0];
2095: d[4] = s[7];
2096: d[5] = s[6];
2097: d[6] = s[5];
2098: d[7] = s[4];
1.26 chl 2099: #else
2100: d[0] = s[7];
2101: d[1] = s[6];
2102: d[2] = s[5];
2103: d[3] = s[4];
2104: d[4] = s[3];
2105: d[5] = s[2];
2106: d[6] = s[1];
2107: d[7] = s[0];
2108: #endif
1.25 chl 2109: return rv;
2110: }
2111:
2112: /*
1.19 tedu 2113: * byteswap a single magic entry
2114: */
2115: private void
2116: bs1(struct magic *m)
2117: {
2118: m->cont_level = swap2(m->cont_level);
2119: m->offset = swap4((uint32_t)m->offset);
2120: m->in_offset = swap4((uint32_t)m->in_offset);
1.25 chl 2121: m->lineno = swap4((uint32_t)m->lineno);
2122: if (IS_STRING(m->type)) {
1.26 chl 2123: m->str_range = swap4(m->str_range);
1.25 chl 2124: m->str_flags = swap4(m->str_flags);
2125: }
2126: else {
2127: m->value.q = swap8(m->value.q);
2128: m->num_mask = swap8(m->num_mask);
2129: }
1.1 deraadt 2130: }