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