1/* 2 * Copyright (c) Ian F. Darwin 1986-1995. 3 * Software written by Ian F. Darwin and others; 4 * maintained 1995-present by Christos Zoulas and others. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: --- 18 unchanged lines hidden (view full) --- 27 */ 28/* 29 * apprentice - make one pass through /etc/magic, learning its secrets. 30 */ 31 32#include "file.h" 33 34#ifndef lint |
35FILE_RCSID("@(#)$File: apprentice.c,v 1.227 2014/11/28 02:46:39 christos Exp $") |
36#endif /* lint */ 37 38#include "magic.h" 39#include <stdlib.h> 40#ifdef HAVE_UNISTD_H 41#include <unistd.h> 42#endif 43#ifdef HAVE_STDDEF_H --- 37 unchanged lines hidden (view full) --- 81 82#ifndef MAP_FILE 83#define MAP_FILE 0 84#endif 85 86#define ALLOC_CHUNK (size_t)10 87#define ALLOC_INCR (size_t)200 88 |
89#define MAP_TYPE_MMAP 0 90#define MAP_TYPE_MALLOC 1 91#define MAP_TYPE_USER 2 92 |
93struct magic_entry { 94 struct magic *mp; 95 uint32_t cont_count; 96 uint32_t max_count; 97}; 98 99struct magic_entry_set { 100 struct magic_entry *me; 101 uint32_t count; 102 uint32_t max; 103}; 104 105struct magic_map { 106 void *p; 107 size_t len; |
108 int type; |
109 struct magic *magic[MAGIC_SETS]; 110 uint32_t nmagic[MAGIC_SETS]; 111}; 112 113int file_formats[FILE_NAMES_SIZE]; 114const size_t file_nformats = FILE_NAMES_SIZE; 115const char *file_names[FILE_NAMES_SIZE]; 116const size_t file_nnames = FILE_NAMES_SIZE; --- 14 unchanged lines hidden (view full) --- 131private struct mlist *mlist_alloc(void); 132private void mlist_free(struct mlist *); 133private void byteswap(struct magic *, uint32_t); 134private void bs1(struct magic *); 135private uint16_t swap2(uint16_t); 136private uint32_t swap4(uint32_t); 137private uint64_t swap8(uint64_t); 138private char *mkdbname(struct magic_set *, const char *, int); |
139private struct magic_map *apprentice_buf(struct magic_set *, struct magic *, 140 size_t); |
141private struct magic_map *apprentice_map(struct magic_set *, const char *); |
142private int check_buffer(struct magic_set *, struct magic_map *, const char *); |
143private void apprentice_unmap(struct magic_map *); 144private int apprentice_compile(struct magic_set *, struct magic_map *, 145 const char *); 146private int check_format_type(const char *, int); 147private int check_format(struct magic_set *, struct magic *); 148private int get_op(char); 149private int parse_mime(struct magic_set *, struct magic_entry *, const char *); 150private int parse_strength(struct magic_set *, struct magic_entry *, const char *); --- 248 unchanged lines hidden (view full) --- 399 assert(p - type_tbl == FILE_NAMES_SIZE); 400} 401 402private int 403add_mlist(struct mlist *mlp, struct magic_map *map, size_t idx) 404{ 405 struct mlist *ml; 406 |
407 mlp->map = idx == 0 ? map : NULL; |
408 if ((ml = CAST(struct mlist *, malloc(sizeof(*ml)))) == NULL) 409 return -1; 410 |
411 ml->map = NULL; |
412 ml->magic = map->magic[idx]; 413 ml->nmagic = map->nmagic[idx]; 414 415 mlp->prev->next = ml; 416 ml->prev = mlp->prev; 417 ml->next = mlp; 418 mlp->prev = ml; 419 return 0; 420} 421 422/* 423 * Handle one file or directory. 424 */ 425private int 426apprentice_1(struct magic_set *ms, const char *fn, int action) 427{ |
428 struct magic_map *map; 429#ifndef COMPILE_ONLY |
430 struct mlist *ml; |
431 size_t i; |
432#endif |
433 434 if (magicsize != FILE_MAGICSIZE) { 435 file_error(ms, 0, "magic element size %lu != %lu", 436 (unsigned long)sizeof(*map->magic[0]), 437 (unsigned long)FILE_MAGICSIZE); 438 return -1; 439 } 440 --- 12 unchanged lines hidden (view full) --- 453 map = apprentice_load(ms, fn, action); 454 if (map == NULL) 455 return -1; 456 } 457 458 for (i = 0; i < MAGIC_SETS; i++) { 459 if (add_mlist(ms->mlist[i], map, i) == -1) { 460 file_oomem(ms, sizeof(*ml)); |
461 goto fail; |
462 } 463 } 464 465 if (action == FILE_LIST) { 466 for (i = 0; i < MAGIC_SETS; i++) { |
467 printf("Set %" SIZE_T_FORMAT "u:\nBinary patterns:\n", 468 i); |
469 apprentice_list(ms->mlist[i], BINTEST); 470 printf("Text patterns:\n"); 471 apprentice_list(ms->mlist[i], TEXTTEST); 472 } 473 } |
474 return 0; |
475fail: 476 for (i = 0; i < MAGIC_SETS; i++) { 477 mlist_free(ms->mlist[i]); 478 ms->mlist[i] = NULL; 479 } 480 return -1; 481#else 482 return 0; 483#endif /* COMPILE_ONLY */ |
484} 485 486protected void 487file_ms_free(struct magic_set *ms) 488{ 489 size_t i; 490 if (ms == NULL) 491 return; --- 27 unchanged lines hidden (view full) --- 519 goto free; 520 521 ms->event_flags = 0; 522 ms->error = -1; 523 for (i = 0; i < MAGIC_SETS; i++) 524 ms->mlist[i] = NULL; 525 ms->file = "unknown"; 526 ms->line = 0; |
527 ms->indir_max = FILE_INDIR_MAX; 528 ms->name_max = FILE_NAME_MAX; 529 ms->elf_shnum_max = FILE_ELF_SHNUM_MAX; 530 ms->elf_phnum_max = FILE_ELF_PHNUM_MAX; |
531 return ms; 532free: 533 free(ms); 534 return NULL; 535} 536 537private void 538apprentice_unmap(struct magic_map *map) 539{ 540 if (map == NULL) 541 return; |
542 543 switch (map->type) { |
544#ifdef QUICK |
545 case MAP_TYPE_MMAP: 546 if (map->p) |
547 (void)munmap(map->p, map->len); |
548 break; |
549#endif |
550 case MAP_TYPE_MALLOC: |
551 free(map->p); |
552 break; 553 case MAP_TYPE_USER: 554 break; 555 default: 556 abort(); |
557 } 558 free(map); 559} 560 561private struct mlist * 562mlist_alloc(void) 563{ 564 struct mlist *mlist; 565 if ((mlist = CAST(struct mlist *, calloc(1, sizeof(*mlist)))) == NULL) { 566 return NULL; 567 } 568 mlist->next = mlist->prev = mlist; 569 return mlist; 570} 571 572private void 573mlist_free(struct mlist *mlist) 574{ |
575 struct mlist *ml, *next; |
576 577 if (mlist == NULL) 578 return; 579 |
580 ml = mlist->next; 581 for (ml = mlist->next; (next = ml->next) != NULL; ml = next) { |
582 if (ml->map) 583 apprentice_unmap(ml->map); 584 free(ml); |
585 if (ml == mlist) 586 break; |
587 } |
588} 589 |
590#ifndef COMPILE_ONLY 591/* void **bufs: an array of compiled magic files */ 592protected int 593buffer_apprentice(struct magic_set *ms, struct magic **bufs, 594 size_t *sizes, size_t nbufs) 595{ 596 size_t i, j; 597 struct mlist *ml; 598 struct magic_map *map; 599 600 if (nbufs == 0) 601 return -1; 602 603 if (ms->mlist[0] != NULL) 604 file_reset(ms); 605 606 init_file_tables(); 607 608 for (i = 0; i < MAGIC_SETS; i++) { 609 mlist_free(ms->mlist[i]); 610 if ((ms->mlist[i] = mlist_alloc()) == NULL) { 611 file_oomem(ms, sizeof(*ms->mlist[i])); 612 goto fail; 613 } 614 } 615 616 for (i = 0; i < nbufs; i++) { 617 map = apprentice_buf(ms, bufs[i], sizes[i]); 618 if (map == NULL) 619 goto fail; 620 621 for (j = 0; j < MAGIC_SETS; j++) { 622 if (add_mlist(ms->mlist[j], map, j) == -1) { 623 file_oomem(ms, sizeof(*ml)); 624 goto fail; 625 } 626 } 627 } 628 629 return 0; 630fail: 631 for (i = 0; i < MAGIC_SETS; i++) { 632 mlist_free(ms->mlist[i]); 633 ms->mlist[i] = NULL; 634 } 635 return -1; 636} 637#endif 638 |
639/* const char *fn: list of magic files and directories */ 640protected int 641file_apprentice(struct magic_set *ms, const char *fn, int action) 642{ 643 char *p, *mfn; 644 int file_err, errs = -1; 645 size_t i; 646 --- 9 unchanged lines hidden (view full) --- 656 file_oomem(ms, strlen(fn)); 657 return -1; 658 } 659 660 for (i = 0; i < MAGIC_SETS; i++) { 661 mlist_free(ms->mlist[i]); 662 if ((ms->mlist[i] = mlist_alloc()) == NULL) { 663 file_oomem(ms, sizeof(*ms->mlist[i])); |
664 while (i-- > 0) { 665 mlist_free(ms->mlist[i]); 666 ms->mlist[i] = NULL; |
667 } 668 free(mfn); 669 return -1; 670 } 671 } 672 fn = mfn; 673 674 while (fn) { --- 706 unchanged lines hidden (view full) --- 1381 if (!(m->flag & UNSIGNED)) { 1382 switch(m->type) { 1383 /* 1384 * Do not remove the casts below. They are 1385 * vital. When later compared with the data, 1386 * the sign extension must have happened. 1387 */ 1388 case FILE_BYTE: |
1389 v = (signed char) v; |
1390 break; 1391 case FILE_SHORT: 1392 case FILE_BESHORT: 1393 case FILE_LESHORT: 1394 v = (short) v; 1395 break; 1396 case FILE_DATE: 1397 case FILE_BEDATE: --- 735 unchanged lines hidden (view full) --- 2133 return 0; 2134out: 2135 m->factor_op = FILE_FACTOR_OP_NONE; 2136 m->factor = 0; 2137 return -1; 2138} 2139 2140private int |
2141goodchar(unsigned char x, const char *extra) 2142{ 2143 return (isascii(x) && isalnum(x)) || strchr(extra, x); 2144} 2145 2146private int |
2147parse_extra(struct magic_set *ms, struct magic_entry *me, const char *line, |
2148 off_t off, size_t len, const char *name, const char *extra, int nt) |
2149{ 2150 size_t i; 2151 const char *l = line; 2152 struct magic *m = &me->mp[me->cont_count == 0 ? 0 : me->cont_count - 1]; 2153 char *buf = (char *)m + off; 2154 2155 if (buf[0] != '\0') { 2156 len = nt ? strlen(buf) : len; --- 4 unchanged lines hidden (view full) --- 2161 2162 if (*m->desc == '\0') { 2163 file_magwarn(ms, "Current entry does not yet have a " 2164 "description for adding a %s type", name); 2165 return -1; 2166 } 2167 2168 EATAB; |
2169 for (i = 0; *l && i < len && goodchar(*l, extra); buf[i++] = *l++) |
2170 continue; 2171 2172 if (i == len && *l) { 2173 if (nt) 2174 buf[len - 1] = '\0'; 2175 if (ms->flags & MAGIC_CHECK) 2176 file_magwarn(ms, "%s type `%s' truncated %" 2177 SIZE_T_FORMAT "u", name, line, i); 2178 } else { |
2179 if (!isspace((unsigned char)*l) && !goodchar(*l, extra)) 2180 file_magwarn(ms, "%s type `%s' has bad char '%c'", 2181 name, line, *l); |
2182 if (nt) 2183 buf[i] = '\0'; 2184 } 2185 2186 if (i > 0) 2187 return 0; |
2188 2189 file_magerror(ms, "Bad magic entry '%s'", line); 2190 return -1; |
2191} 2192 2193/* 2194 * Parse an Apple CREATOR/TYPE annotation from magic file and put it into 2195 * magic[index - 1] 2196 */ 2197private int 2198parse_apple(struct magic_set *ms, struct magic_entry *me, const char *line) 2199{ 2200 struct magic *m = &me->mp[0]; 2201 2202 return parse_extra(ms, me, line, offsetof(struct magic, apple), |
2203 sizeof(m->apple), "APPLE", "!+-./", 0); |
2204} 2205 2206/* 2207 * parse a MIME annotation line from magic file, put into magic[index - 1] 2208 * if valid 2209 */ 2210private int 2211parse_mime(struct magic_set *ms, struct magic_entry *me, const char *line) 2212{ 2213 struct magic *m = &me->mp[0]; 2214 2215 return parse_extra(ms, me, line, offsetof(struct magic, mimetype), |
2216 sizeof(m->mimetype), "MIME", "+-/.", 1); |
2217} 2218 2219private int 2220check_format_type(const char *ptr, int type) 2221{ 2222 int quad = 0, h; 2223 if (*ptr == '\0') { 2224 /* Missing format string; bad */ --- 544 unchanged lines hidden (view full) --- 2769 default: 2770 break; 2771 } 2772 2773 *p = l; 2774} 2775 2776/* |
2777 * handle a buffer containing a compiled file. 2778 */ 2779private struct magic_map * 2780apprentice_buf(struct magic_set *ms, struct magic *buf, size_t len) 2781{ 2782 struct magic_map *map; 2783 2784 if ((map = CAST(struct magic_map *, calloc(1, sizeof(*map)))) == NULL) { 2785 file_oomem(ms, sizeof(*map)); 2786 return NULL; 2787 } 2788 map->len = len; 2789 map->p = buf; 2790 map->type = MAP_TYPE_USER; 2791 if (check_buffer(ms, map, "buffer") != 0) { 2792 apprentice_unmap(map); 2793 return NULL; 2794 } 2795 return map; 2796} 2797 2798/* |
2799 * handle a compiled file. 2800 */ 2801 2802private struct magic_map * 2803apprentice_map(struct magic_set *ms, const char *fn) 2804{ 2805 int fd; 2806 struct stat st; |
2807 char *dbname = NULL; 2808 struct magic_map *map; |
2809 2810 fd = -1; 2811 if ((map = CAST(struct magic_map *, calloc(1, sizeof(*map)))) == NULL) { 2812 file_oomem(ms, sizeof(*map)); 2813 goto error; 2814 } 2815 2816 dbname = mkdbname(ms, fn, 0); --- 15 unchanged lines hidden (view full) --- 2832 2833 map->len = (size_t)st.st_size; 2834#ifdef QUICK 2835 if ((map->p = mmap(0, (size_t)st.st_size, PROT_READ|PROT_WRITE, 2836 MAP_PRIVATE|MAP_FILE, fd, (off_t)0)) == MAP_FAILED) { 2837 file_error(ms, errno, "cannot map `%s'", dbname); 2838 goto error; 2839 } |
2840 map->type = MAP_TYPE_MMAP; |
2841#else 2842 if ((map->p = CAST(void *, malloc(map->len))) == NULL) { 2843 file_oomem(ms, map->len); 2844 goto error; 2845 } 2846 if (read(fd, map->p, map->len) != (ssize_t)map->len) { 2847 file_badread(ms); 2848 goto error; 2849 } |
2850 map->type = MAP_TYPE_MALLOC; |
2851#define RET 1 2852#endif 2853 (void)close(fd); 2854 fd = -1; |
2855 2856 if (check_buffer(ms, map, dbname) != 0) 2857 goto error; 2858 2859 free(dbname); 2860 return map; 2861 2862error: 2863 if (fd != -1) 2864 (void)close(fd); 2865 apprentice_unmap(map); 2866 free(dbname); 2867 return NULL; 2868} 2869 2870private int 2871check_buffer(struct magic_set *ms, struct magic_map *map, const char *dbname) 2872{ 2873 uint32_t *ptr; 2874 uint32_t entries, nentries; 2875 uint32_t version; 2876 int i, needsbyteswap; 2877 |
2878 ptr = CAST(uint32_t *, map->p); 2879 if (*ptr != MAGICNO) { 2880 if (swap4(*ptr) != MAGICNO) { 2881 file_error(ms, 0, "bad magic in `%s'", dbname); |
2882 return -1; |
2883 } 2884 needsbyteswap = 1; 2885 } else 2886 needsbyteswap = 0; 2887 if (needsbyteswap) 2888 version = swap4(ptr[1]); 2889 else 2890 version = ptr[1]; 2891 if (version != VERSIONNO) { 2892 file_error(ms, 0, "File %s supports only version %d magic " 2893 "files. `%s' is version %d", VERSION, 2894 VERSIONNO, dbname, version); |
2895 return -1; |
2896 } |
2897 entries = (uint32_t)(map->len / sizeof(struct magic)); 2898 if ((entries * sizeof(struct magic)) != map->len) { 2899 file_error(ms, 0, "Size of `%s' %" SIZE_T_FORMAT "u is not " |
2900 "a multiple of %" SIZE_T_FORMAT "u", |
2901 dbname, map->len, sizeof(struct magic)); 2902 return -1; |
2903 } 2904 map->magic[0] = CAST(struct magic *, map->p) + 1; 2905 nentries = 0; 2906 for (i = 0; i < MAGIC_SETS; i++) { 2907 if (needsbyteswap) 2908 map->nmagic[i] = swap4(ptr[i + 2]); 2909 else 2910 map->nmagic[i] = ptr[i + 2]; 2911 if (i != MAGIC_SETS - 1) 2912 map->magic[i + 1] = map->magic[i] + map->nmagic[i]; 2913 nentries += map->nmagic[i]; 2914 } 2915 if (entries != nentries + 1) { 2916 file_error(ms, 0, "Inconsistent entries in `%s' %u != %u", 2917 dbname, entries, nentries + 1); |
2918 return -1; |
2919 } 2920 if (needsbyteswap) 2921 for (i = 0; i < MAGIC_SETS; i++) 2922 byteswap(map->magic[i], map->nmagic[i]); |
2923 return 0; |
2924} 2925 2926/* 2927 * handle an mmaped file. 2928 */ 2929private int 2930apprentice_compile(struct magic_set *ms, struct magic_map *map, const char *fn) 2931{ --- 261 unchanged lines hidden --- |