168349Sobrien/* 2133359Sobrien * Copyright (c) Ian F. Darwin 1986-1995. 3133359Sobrien * Software written by Ian F. Darwin and others; 4133359Sobrien * maintained 1995-present by Christos Zoulas and others. 5133359Sobrien * 6133359Sobrien * Redistribution and use in source and binary forms, with or without 7133359Sobrien * modification, are permitted provided that the following conditions 8133359Sobrien * are met: 9133359Sobrien * 1. Redistributions of source code must retain the above copyright 10133359Sobrien * notice immediately at the beginning of the file, without modification, 11133359Sobrien * this list of conditions, and the following disclaimer. 12133359Sobrien * 2. Redistributions in binary form must reproduce the above copyright 13133359Sobrien * notice, this list of conditions and the following disclaimer in the 14133359Sobrien * documentation and/or other materials provided with the distribution. 15133359Sobrien * 16133359Sobrien * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 17133359Sobrien * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18133359Sobrien * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19133359Sobrien * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR 20133359Sobrien * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21133359Sobrien * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22133359Sobrien * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23133359Sobrien * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24133359Sobrien * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25133359Sobrien * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26133359Sobrien * SUCH DAMAGE. 27133359Sobrien */ 28133359Sobrien/* 2968349Sobrien * apprentice - make one pass through /etc/magic, learning its secrets. 3068349Sobrien */ 3168349Sobrien 3280588Sobrien#include "file.h" 33191736Sobrien 34191736Sobrien#ifndef lint 35330569SgordonFILE_RCSID("@(#)$File: apprentice.c,v 1.262 2017/08/28 13:39:18 christos Exp $") 36191736Sobrien#endif /* lint */ 37191736Sobrien 38133359Sobrien#include "magic.h" 3968349Sobrien#include <stdlib.h> 4084685Sobrien#ifdef HAVE_UNISTD_H 4184685Sobrien#include <unistd.h> 4284685Sobrien#endif 43267843Sdelphij#ifdef HAVE_STDDEF_H 44267843Sdelphij#include <stddef.h> 45267843Sdelphij#endif 4668349Sobrien#include <string.h> 47169942Sobrien#include <assert.h> 4868349Sobrien#include <ctype.h> 49103373Sobrien#include <fcntl.h> 5074784Sobrien#ifdef QUICK 5174784Sobrien#include <sys/mman.h> 5274784Sobrien#endif 53186690Sobrien#include <dirent.h> 54267843Sdelphij#if defined(HAVE_LIMITS_H) 55267843Sdelphij#include <limits.h> 56267843Sdelphij#endif 5768349Sobrien 58267843Sdelphij#ifndef SSIZE_MAX 59267843Sdelphij#define MAXMAGIC_SIZE ((ssize_t)0x7fffffff) 60267843Sdelphij#else 61267843Sdelphij#define MAXMAGIC_SIZE SSIZE_MAX 62267843Sdelphij#endif 63267843Sdelphij 6468349Sobrien#define EATAB {while (isascii((unsigned char) *l) && \ 6568349Sobrien isspace((unsigned char) *l)) ++l;} 6668349Sobrien#define LOWCASE(l) (isupper((unsigned char) (l)) ? \ 6768349Sobrien tolower((unsigned char) (l)) : (l)) 6875937Sobrien/* 6975937Sobrien * Work around a bug in headers on Digital Unix. 7075937Sobrien * At least confirmed for: OSF1 V4.0 878 7175937Sobrien */ 7275937Sobrien#if defined(__osf__) && defined(__DECC) 7375937Sobrien#ifdef MAP_FAILED 7475937Sobrien#undef MAP_FAILED 7575937Sobrien#endif 7675937Sobrien#endif 7768349Sobrien 7875937Sobrien#ifndef MAP_FAILED 7975937Sobrien#define MAP_FAILED (void *) -1 8075937Sobrien#endif 8168349Sobrien 8275937Sobrien#ifndef MAP_FILE 8375937Sobrien#define MAP_FILE 0 8475937Sobrien#endif 8575937Sobrien 86267843Sdelphij#define ALLOC_CHUNK (size_t)10 87267843Sdelphij#define ALLOC_INCR (size_t)200 88267843Sdelphij 89330569Sgordon#define MAP_TYPE_USER 0 90276415Sdelphij#define MAP_TYPE_MALLOC 1 91330569Sgordon#define MAP_TYPE_MMAP 2 92276415Sdelphij 93159764Sobrienstruct magic_entry { 94159764Sobrien struct magic *mp; 95159764Sobrien uint32_t cont_count; 96159764Sobrien uint32_t max_count; 97159764Sobrien}; 98159764Sobrien 99267843Sdelphijstruct magic_entry_set { 100267843Sdelphij struct magic_entry *me; 101267843Sdelphij uint32_t count; 102267843Sdelphij uint32_t max; 103267843Sdelphij}; 104267843Sdelphij 105267843Sdelphijstruct magic_map { 106267843Sdelphij void *p; 107267843Sdelphij size_t len; 108276415Sdelphij int type; 109267843Sdelphij struct magic *magic[MAGIC_SETS]; 110267843Sdelphij uint32_t nmagic[MAGIC_SETS]; 111267843Sdelphij}; 112267843Sdelphij 113169962Sobrienint file_formats[FILE_NAMES_SIZE]; 114169962Sobrienconst size_t file_nformats = FILE_NAMES_SIZE; 115169962Sobrienconst char *file_names[FILE_NAMES_SIZE]; 116169962Sobrienconst size_t file_nnames = FILE_NAMES_SIZE; 117169942Sobrien 118169962Sobrienprivate int getvalue(struct magic_set *ms, struct magic *, const char **, int); 119133359Sobrienprivate int hextoint(int); 120192348Sdelphijprivate const char *getstr(struct magic_set *, struct magic *, const char *, 121192348Sdelphij int); 122267843Sdelphijprivate int parse(struct magic_set *, struct magic_entry *, const char *, 123267843Sdelphij size_t, int); 124159764Sobrienprivate void eatsize(const char **); 125267843Sdelphijprivate int apprentice_1(struct magic_set *, const char *, int); 126159764Sobrienprivate size_t apprentice_magic_strength(const struct magic *); 127159764Sobrienprivate int apprentice_sort(const void *, const void *); 128226048Sobrienprivate void apprentice_list(struct mlist *, int ); 129267843Sdelphijprivate struct magic_map *apprentice_load(struct magic_set *, 130133359Sobrien const char *, int); 131267843Sdelphijprivate struct mlist *mlist_alloc(void); 132267843Sdelphijprivate void mlist_free(struct mlist *); 133133359Sobrienprivate void byteswap(struct magic *, uint32_t); 134133359Sobrienprivate void bs1(struct magic *); 135133359Sobrienprivate uint16_t swap2(uint16_t); 136133359Sobrienprivate uint32_t swap4(uint32_t); 137169942Sobrienprivate uint64_t swap8(uint64_t); 138191736Sobrienprivate char *mkdbname(struct magic_set *, const char *, int); 139276415Sdelphijprivate struct magic_map *apprentice_buf(struct magic_set *, struct magic *, 140276415Sdelphij size_t); 141267843Sdelphijprivate struct magic_map *apprentice_map(struct magic_set *, const char *); 142276415Sdelphijprivate int check_buffer(struct magic_set *, struct magic_map *, const char *); 143267843Sdelphijprivate void apprentice_unmap(struct magic_map *); 144267843Sdelphijprivate int apprentice_compile(struct magic_set *, struct magic_map *, 145133359Sobrien const char *); 146330569Sgordonprivate int check_format_type(const char *, int, const char **); 147139368Sobrienprivate int check_format(struct magic_set *, struct magic *); 148175296Sobrienprivate int get_op(char); 149186690Sobrienprivate int parse_mime(struct magic_set *, struct magic_entry *, const char *); 150191736Sobrienprivate int parse_strength(struct magic_set *, struct magic_entry *, const char *); 151191736Sobrienprivate int parse_apple(struct magic_set *, struct magic_entry *, const char *); 152284778Sdelphijprivate int parse_ext(struct magic_set *, struct magic_entry *, const char *); 15368349Sobrien 154186690Sobrien 155133359Sobrienprivate size_t magicsize = sizeof(struct magic); 15668349Sobrien 157186690Sobrienprivate const char usg_hdr[] = "cont\toffset\ttype\topcode\tmask\tvalue\tdesc"; 158159764Sobrien 159186690Sobrienprivate struct { 160186690Sobrien const char *name; 161186690Sobrien size_t len; 162186690Sobrien int (*fun)(struct magic_set *, struct magic_entry *, const char *); 163186690Sobrien} bang[] = { 164186690Sobrien#define DECLARE_FIELD(name) { # name, sizeof(# name) - 1, parse_ ## name } 165186690Sobrien DECLARE_FIELD(mime), 166191736Sobrien DECLARE_FIELD(apple), 167284778Sdelphij DECLARE_FIELD(ext), 168186690Sobrien DECLARE_FIELD(strength), 169186690Sobrien#undef DECLARE_FIELD 170186690Sobrien { NULL, 0, NULL } 171186690Sobrien}; 172186690Sobrien 17380588Sobrien#ifdef COMPILE_ONLY 17474784Sobrien 175103373Sobrienint main(int, char *[]); 17680588Sobrien 17780588Sobrienint 178103373Sobrienmain(int argc, char *argv[]) 17980588Sobrien{ 18080588Sobrien int ret; 181133359Sobrien struct magic_set *ms; 182133359Sobrien char *progname; 18380588Sobrien 18480588Sobrien if ((progname = strrchr(argv[0], '/')) != NULL) 18580588Sobrien progname++; 18680588Sobrien else 18780588Sobrien progname = argv[0]; 18880588Sobrien 18980588Sobrien if (argc != 2) { 190133359Sobrien (void)fprintf(stderr, "Usage: %s file\n", progname); 191133359Sobrien return 1; 19280588Sobrien } 19380588Sobrien 194133359Sobrien if ((ms = magic_open(MAGIC_CHECK)) == NULL) { 195133359Sobrien (void)fprintf(stderr, "%s: %s\n", progname, strerror(errno)); 196133359Sobrien return 1; 197133359Sobrien } 198133359Sobrien ret = magic_compile(ms, argv[1]) == -1 ? 1 : 0; 199133359Sobrien if (ret == 1) 200133359Sobrien (void)fprintf(stderr, "%s: %s\n", progname, magic_error(ms)); 201133359Sobrien magic_close(ms); 202133359Sobrien return ret; 20380588Sobrien} 20480588Sobrien#endif /* COMPILE_ONLY */ 20580588Sobrien 206267843Sdelphijstruct type_tbl_s { 207186690Sobrien const char name[16]; 208169962Sobrien const size_t len; 209169962Sobrien const int type; 210169962Sobrien const int format; 211267843Sdelphij}; 212267843Sdelphij 213267843Sdelphij/* 214267843Sdelphij * XXX - the actual Single UNIX Specification says that "long" means "long", 215267843Sdelphij * as in the C data type, but we treat it as meaning "4-byte integer". 216267843Sdelphij * Given that the OS X version of file 5.04 did the same, I guess that passes 217267843Sdelphij * the actual test; having "long" be dependent on how big a "long" is on 218267843Sdelphij * the machine running "file" is silly. 219267843Sdelphij */ 220267843Sdelphijstatic const struct type_tbl_s type_tbl[] = { 221169962Sobrien# define XX(s) s, (sizeof(s) - 1) 222186690Sobrien# define XX_NULL "", 0 223267843Sdelphij { XX("invalid"), FILE_INVALID, FILE_FMT_NONE }, 224169962Sobrien { XX("byte"), FILE_BYTE, FILE_FMT_NUM }, 225169962Sobrien { XX("short"), FILE_SHORT, FILE_FMT_NUM }, 226267843Sdelphij { XX("default"), FILE_DEFAULT, FILE_FMT_NONE }, 227169962Sobrien { XX("long"), FILE_LONG, FILE_FMT_NUM }, 228169962Sobrien { XX("string"), FILE_STRING, FILE_FMT_STR }, 229169962Sobrien { XX("date"), FILE_DATE, FILE_FMT_STR }, 230169962Sobrien { XX("beshort"), FILE_BESHORT, FILE_FMT_NUM }, 231169962Sobrien { XX("belong"), FILE_BELONG, FILE_FMT_NUM }, 232169962Sobrien { XX("bedate"), FILE_BEDATE, FILE_FMT_STR }, 233169962Sobrien { XX("leshort"), FILE_LESHORT, FILE_FMT_NUM }, 234169962Sobrien { XX("lelong"), FILE_LELONG, FILE_FMT_NUM }, 235169962Sobrien { XX("ledate"), FILE_LEDATE, FILE_FMT_STR }, 236169962Sobrien { XX("pstring"), FILE_PSTRING, FILE_FMT_STR }, 237169962Sobrien { XX("ldate"), FILE_LDATE, FILE_FMT_STR }, 238169962Sobrien { XX("beldate"), FILE_BELDATE, FILE_FMT_STR }, 239169962Sobrien { XX("leldate"), FILE_LELDATE, FILE_FMT_STR }, 240169962Sobrien { XX("regex"), FILE_REGEX, FILE_FMT_STR }, 241169962Sobrien { XX("bestring16"), FILE_BESTRING16, FILE_FMT_STR }, 242169962Sobrien { XX("lestring16"), FILE_LESTRING16, FILE_FMT_STR }, 243169962Sobrien { XX("search"), FILE_SEARCH, FILE_FMT_STR }, 244169962Sobrien { XX("medate"), FILE_MEDATE, FILE_FMT_STR }, 245169962Sobrien { XX("meldate"), FILE_MELDATE, FILE_FMT_STR }, 246169962Sobrien { XX("melong"), FILE_MELONG, FILE_FMT_NUM }, 247169962Sobrien { XX("quad"), FILE_QUAD, FILE_FMT_QUAD }, 248169962Sobrien { XX("lequad"), FILE_LEQUAD, FILE_FMT_QUAD }, 249169962Sobrien { XX("bequad"), FILE_BEQUAD, FILE_FMT_QUAD }, 250169962Sobrien { XX("qdate"), FILE_QDATE, FILE_FMT_STR }, 251169962Sobrien { XX("leqdate"), FILE_LEQDATE, FILE_FMT_STR }, 252169962Sobrien { XX("beqdate"), FILE_BEQDATE, FILE_FMT_STR }, 253169962Sobrien { XX("qldate"), FILE_QLDATE, FILE_FMT_STR }, 254169962Sobrien { XX("leqldate"), FILE_LEQLDATE, FILE_FMT_STR }, 255169962Sobrien { XX("beqldate"), FILE_BEQLDATE, FILE_FMT_STR }, 256175296Sobrien { XX("float"), FILE_FLOAT, FILE_FMT_FLOAT }, 257175296Sobrien { XX("befloat"), FILE_BEFLOAT, FILE_FMT_FLOAT }, 258175296Sobrien { XX("lefloat"), FILE_LEFLOAT, FILE_FMT_FLOAT }, 259175296Sobrien { XX("double"), FILE_DOUBLE, FILE_FMT_DOUBLE }, 260175296Sobrien { XX("bedouble"), FILE_BEDOUBLE, FILE_FMT_DOUBLE }, 261175296Sobrien { XX("ledouble"), FILE_LEDOUBLE, FILE_FMT_DOUBLE }, 262191736Sobrien { XX("leid3"), FILE_LEID3, FILE_FMT_NUM }, 263191736Sobrien { XX("beid3"), FILE_BEID3, FILE_FMT_NUM }, 264267843Sdelphij { XX("indirect"), FILE_INDIRECT, FILE_FMT_NUM }, 265267843Sdelphij { XX("qwdate"), FILE_QWDATE, FILE_FMT_STR }, 266267843Sdelphij { XX("leqwdate"), FILE_LEQWDATE, FILE_FMT_STR }, 267267843Sdelphij { XX("beqwdate"), FILE_BEQWDATE, FILE_FMT_STR }, 268267843Sdelphij { XX("name"), FILE_NAME, FILE_FMT_NONE }, 269267843Sdelphij { XX("use"), FILE_USE, FILE_FMT_NONE }, 270267843Sdelphij { XX("clear"), FILE_CLEAR, FILE_FMT_NONE }, 271330569Sgordon { XX("der"), FILE_DER, FILE_FMT_STR }, 272169962Sobrien { XX_NULL, FILE_INVALID, FILE_FMT_NONE }, 273267843Sdelphij}; 274267843Sdelphij 275267843Sdelphij/* 276267843Sdelphij * These are not types, and cannot be preceded by "u" to make them 277267843Sdelphij * unsigned. 278267843Sdelphij */ 279267843Sdelphijstatic const struct type_tbl_s special_tbl[] = { 280330569Sgordon { XX("der"), FILE_DER, FILE_FMT_STR }, 281267843Sdelphij { XX("name"), FILE_NAME, FILE_FMT_STR }, 282267843Sdelphij { XX("use"), FILE_USE, FILE_FMT_STR }, 283267843Sdelphij { XX_NULL, FILE_INVALID, FILE_FMT_NONE }, 284267843Sdelphij}; 285169962Sobrien# undef XX 286169962Sobrien# undef XX_NULL 28780588Sobrien 288169962Sobrienprivate int 289267843Sdelphijget_type(const struct type_tbl_s *tbl, const char *l, const char **t) 290169962Sobrien{ 291169962Sobrien const struct type_tbl_s *p; 292169962Sobrien 293267843Sdelphij for (p = tbl; p->len; p++) { 294169962Sobrien if (strncmp(l, p->name, p->len) == 0) { 295169962Sobrien if (t) 296169962Sobrien *t = l + p->len; 297169962Sobrien break; 298169962Sobrien } 299169962Sobrien } 300169962Sobrien return p->type; 301169962Sobrien} 302169962Sobrien 303267843Sdelphijprivate int 304267843Sdelphijget_standard_integer_type(const char *l, const char **t) 305267843Sdelphij{ 306267843Sdelphij int type; 307267843Sdelphij 308267843Sdelphij if (isalpha((unsigned char)l[1])) { 309267843Sdelphij switch (l[1]) { 310267843Sdelphij case 'C': 311267843Sdelphij /* "dC" and "uC" */ 312267843Sdelphij type = FILE_BYTE; 313267843Sdelphij break; 314267843Sdelphij case 'S': 315267843Sdelphij /* "dS" and "uS" */ 316267843Sdelphij type = FILE_SHORT; 317267843Sdelphij break; 318267843Sdelphij case 'I': 319267843Sdelphij case 'L': 320267843Sdelphij /* 321267843Sdelphij * "dI", "dL", "uI", and "uL". 322267843Sdelphij * 323267843Sdelphij * XXX - the actual Single UNIX Specification says 324267843Sdelphij * that "L" means "long", as in the C data type, 325267843Sdelphij * but we treat it as meaning "4-byte integer". 326267843Sdelphij * Given that the OS X version of file 5.04 did 327267843Sdelphij * the same, I guess that passes the actual SUS 328267843Sdelphij * validation suite; having "dL" be dependent on 329267843Sdelphij * how big a "long" is on the machine running 330267843Sdelphij * "file" is silly. 331267843Sdelphij */ 332267843Sdelphij type = FILE_LONG; 333267843Sdelphij break; 334267843Sdelphij case 'Q': 335267843Sdelphij /* "dQ" and "uQ" */ 336267843Sdelphij type = FILE_QUAD; 337267843Sdelphij break; 338267843Sdelphij default: 339267843Sdelphij /* "d{anything else}", "u{anything else}" */ 340267843Sdelphij return FILE_INVALID; 341267843Sdelphij } 342267843Sdelphij l += 2; 343267843Sdelphij } else if (isdigit((unsigned char)l[1])) { 344267843Sdelphij /* 345267843Sdelphij * "d{num}" and "u{num}"; we only support {num} values 346267843Sdelphij * of 1, 2, 4, and 8 - the Single UNIX Specification 347267843Sdelphij * doesn't say anything about whether arbitrary 348267843Sdelphij * values should be supported, but both the Solaris 10 349267843Sdelphij * and OS X Mountain Lion versions of file passed the 350267843Sdelphij * Single UNIX Specification validation suite, and 351267843Sdelphij * neither of them support values bigger than 8 or 352267843Sdelphij * non-power-of-2 values. 353267843Sdelphij */ 354267843Sdelphij if (isdigit((unsigned char)l[2])) { 355267843Sdelphij /* Multi-digit, so > 9 */ 356267843Sdelphij return FILE_INVALID; 357267843Sdelphij } 358267843Sdelphij switch (l[1]) { 359267843Sdelphij case '1': 360267843Sdelphij type = FILE_BYTE; 361267843Sdelphij break; 362267843Sdelphij case '2': 363267843Sdelphij type = FILE_SHORT; 364267843Sdelphij break; 365267843Sdelphij case '4': 366267843Sdelphij type = FILE_LONG; 367267843Sdelphij break; 368267843Sdelphij case '8': 369267843Sdelphij type = FILE_QUAD; 370267843Sdelphij break; 371267843Sdelphij default: 372267843Sdelphij /* XXX - what about 3, 5, 6, or 7? */ 373267843Sdelphij return FILE_INVALID; 374267843Sdelphij } 375267843Sdelphij l += 2; 376267843Sdelphij } else { 377267843Sdelphij /* 378267843Sdelphij * "d" or "u" by itself. 379267843Sdelphij */ 380267843Sdelphij type = FILE_LONG; 381267843Sdelphij ++l; 382267843Sdelphij } 383267843Sdelphij if (t) 384267843Sdelphij *t = l; 385267843Sdelphij return type; 386267843Sdelphij} 387267843Sdelphij 388169962Sobrienprivate void 389169962Sobrieninit_file_tables(void) 390169962Sobrien{ 391169962Sobrien static int done = 0; 392169962Sobrien const struct type_tbl_s *p; 393169962Sobrien 394169962Sobrien if (done) 395169962Sobrien return; 396169962Sobrien done++; 397169962Sobrien 398186690Sobrien for (p = type_tbl; p->len; p++) { 399169962Sobrien assert(p->type < FILE_NAMES_SIZE); 400169962Sobrien file_names[p->type] = p->name; 401169962Sobrien file_formats[p->type] = p->format; 402169962Sobrien } 403267843Sdelphij assert(p - type_tbl == FILE_NAMES_SIZE); 404169962Sobrien} 405169962Sobrien 406267843Sdelphijprivate int 407267843Sdelphijadd_mlist(struct mlist *mlp, struct magic_map *map, size_t idx) 408267843Sdelphij{ 409267843Sdelphij struct mlist *ml; 410267843Sdelphij 411330569Sgordon mlp->map = NULL; 412267843Sdelphij if ((ml = CAST(struct mlist *, malloc(sizeof(*ml)))) == NULL) 413267843Sdelphij return -1; 414267843Sdelphij 415330569Sgordon ml->map = idx == 0 ? map : NULL; 416267843Sdelphij ml->magic = map->magic[idx]; 417267843Sdelphij ml->nmagic = map->nmagic[idx]; 418267843Sdelphij 419267843Sdelphij mlp->prev->next = ml; 420267843Sdelphij ml->prev = mlp->prev; 421267843Sdelphij ml->next = mlp; 422267843Sdelphij mlp->prev = ml; 423267843Sdelphij return 0; 424267843Sdelphij} 425267843Sdelphij 42674784Sobrien/* 427186690Sobrien * Handle one file or directory. 42874784Sobrien */ 429133359Sobrienprivate int 430267843Sdelphijapprentice_1(struct magic_set *ms, const char *fn, int action) 43174784Sobrien{ 432276415Sdelphij struct magic_map *map; 433267897Sdelphij#ifndef COMPILE_ONLY 43474784Sobrien struct mlist *ml; 435267843Sdelphij size_t i; 436276415Sdelphij#endif 43774784Sobrien 438133359Sobrien if (magicsize != FILE_MAGICSIZE) { 439133359Sobrien file_error(ms, 0, "magic element size %lu != %lu", 440267843Sdelphij (unsigned long)sizeof(*map->magic[0]), 441133359Sobrien (unsigned long)FILE_MAGICSIZE); 442133359Sobrien return -1; 44374784Sobrien } 444133359Sobrien 445133359Sobrien if (action == FILE_COMPILE) { 446267843Sdelphij map = apprentice_load(ms, fn, action); 447267843Sdelphij if (map == NULL) 448133359Sobrien return -1; 449267843Sdelphij return apprentice_compile(ms, map, fn); 450133359Sobrien } 451159764Sobrien 45280588Sobrien#ifndef COMPILE_ONLY 453267843Sdelphij map = apprentice_map(ms, fn); 454330569Sgordon if (map == (struct magic_map *)-1) 455330569Sgordon return -1; 456267843Sdelphij if (map == NULL) { 457133359Sobrien if (ms->flags & MAGIC_CHECK) 458139368Sobrien file_magwarn(ms, "using regular magic file `%s'", fn); 459267843Sdelphij map = apprentice_load(ms, fn, action); 460267843Sdelphij if (map == NULL) 461133359Sobrien return -1; 462133359Sobrien } 46374784Sobrien 464267843Sdelphij for (i = 0; i < MAGIC_SETS; i++) { 465267843Sdelphij if (add_mlist(ms->mlist[i], map, i) == -1) { 466267843Sdelphij file_oomem(ms, sizeof(*ml)); 467330569Sgordon return -1; 468267843Sdelphij } 469133359Sobrien } 470133359Sobrien 471226048Sobrien if (action == FILE_LIST) { 472267843Sdelphij for (i = 0; i < MAGIC_SETS; i++) { 473276415Sdelphij printf("Set %" SIZE_T_FORMAT "u:\nBinary patterns:\n", 474276415Sdelphij i); 475267843Sdelphij apprentice_list(ms->mlist[i], BINTEST); 476267843Sdelphij printf("Text patterns:\n"); 477267843Sdelphij apprentice_list(ms->mlist[i], TEXTTEST); 478267843Sdelphij } 479226048Sobrien } 480276415Sdelphij return 0; 481276415Sdelphij#else 482276415Sdelphij return 0; 483267897Sdelphij#endif /* COMPILE_ONLY */ 48474784Sobrien} 48574784Sobrien 486133359Sobrienprotected void 487267843Sdelphijfile_ms_free(struct magic_set *ms) 488133359Sobrien{ 489267843Sdelphij size_t i; 490267843Sdelphij if (ms == NULL) 491133359Sobrien return; 492267843Sdelphij for (i = 0; i < MAGIC_SETS; i++) 493267843Sdelphij mlist_free(ms->mlist[i]); 494267843Sdelphij free(ms->o.pbuf); 495267843Sdelphij free(ms->o.buf); 496267843Sdelphij free(ms->c.li); 497267843Sdelphij free(ms); 498267843Sdelphij} 499267843Sdelphij 500267843Sdelphijprotected struct magic_set * 501267843Sdelphijfile_ms_alloc(int flags) 502267843Sdelphij{ 503267843Sdelphij struct magic_set *ms; 504267843Sdelphij size_t i, len; 505267843Sdelphij 506267843Sdelphij if ((ms = CAST(struct magic_set *, calloc((size_t)1, 507267843Sdelphij sizeof(struct magic_set)))) == NULL) 508267843Sdelphij return NULL; 509267843Sdelphij 510267843Sdelphij if (magic_setflags(ms, flags) == -1) { 511267843Sdelphij errno = EINVAL; 512267843Sdelphij goto free; 513267843Sdelphij } 514267843Sdelphij 515267843Sdelphij ms->o.buf = ms->o.pbuf = NULL; 516267843Sdelphij len = (ms->c.len = 10) * sizeof(*ms->c.li); 517267843Sdelphij 518267843Sdelphij if ((ms->c.li = CAST(struct level_info *, malloc(len))) == NULL) 519267843Sdelphij goto free; 520267843Sdelphij 521267843Sdelphij ms->event_flags = 0; 522267843Sdelphij ms->error = -1; 523267843Sdelphij for (i = 0; i < MAGIC_SETS; i++) 524267843Sdelphij ms->mlist[i] = NULL; 525267843Sdelphij ms->file = "unknown"; 526267843Sdelphij ms->line = 0; 527276415Sdelphij ms->indir_max = FILE_INDIR_MAX; 528276415Sdelphij ms->name_max = FILE_NAME_MAX; 529276415Sdelphij ms->elf_shnum_max = FILE_ELF_SHNUM_MAX; 530276415Sdelphij ms->elf_phnum_max = FILE_ELF_PHNUM_MAX; 531277592Sdelphij ms->elf_notes_max = FILE_ELF_NOTES_MAX; 532290152Sdelphij ms->regex_max = FILE_REGEX_MAX; 533330569Sgordon ms->bytes_max = FILE_BYTES_MAX; 534267843Sdelphij return ms; 535267843Sdelphijfree: 536267843Sdelphij free(ms); 537267843Sdelphij return NULL; 538267843Sdelphij} 539267843Sdelphij 540267843Sdelphijprivate void 541267843Sdelphijapprentice_unmap(struct magic_map *map) 542267843Sdelphij{ 543290152Sdelphij size_t i; 544267843Sdelphij if (map == NULL) 545267843Sdelphij return; 546276415Sdelphij 547276415Sdelphij switch (map->type) { 548330569Sgordon case MAP_TYPE_USER: 549330569Sgordon break; 550330569Sgordon case MAP_TYPE_MALLOC: 551330569Sgordon for (i = 0; i < MAGIC_SETS; i++) { 552330569Sgordon void *b = map->magic[i]; 553330569Sgordon void *p = map->p; 554330569Sgordon if (CAST(char *, b) >= CAST(char *, p) && 555330569Sgordon CAST(char *, b) <= CAST(char *, p) + map->len) 556330569Sgordon continue; 557330569Sgordon free(map->magic[i]); 558330569Sgordon } 559330569Sgordon free(map->p); 560330569Sgordon break; 561175296Sobrien#ifdef QUICK 562276415Sdelphij case MAP_TYPE_MMAP: 563330569Sgordon if (map->p && map->p != MAP_FAILED) 564267843Sdelphij (void)munmap(map->p, map->len); 565276415Sdelphij break; 566175296Sobrien#endif 567276415Sdelphij default: 568276415Sdelphij abort(); 569133359Sobrien } 570267843Sdelphij free(map); 571133359Sobrien} 57274784Sobrien 573267843Sdelphijprivate struct mlist * 574267843Sdelphijmlist_alloc(void) 575267843Sdelphij{ 576267843Sdelphij struct mlist *mlist; 577267843Sdelphij if ((mlist = CAST(struct mlist *, calloc(1, sizeof(*mlist)))) == NULL) { 578267843Sdelphij return NULL; 579267843Sdelphij } 580267843Sdelphij mlist->next = mlist->prev = mlist; 581267843Sdelphij return mlist; 582267843Sdelphij} 583267843Sdelphij 584267843Sdelphijprivate void 585267843Sdelphijmlist_free(struct mlist *mlist) 586267843Sdelphij{ 587276415Sdelphij struct mlist *ml, *next; 588267843Sdelphij 589267843Sdelphij if (mlist == NULL) 590267843Sdelphij return; 591267843Sdelphij 592276415Sdelphij ml = mlist->next; 593276415Sdelphij for (ml = mlist->next; (next = ml->next) != NULL; ml = next) { 594267843Sdelphij if (ml->map) 595330569Sgordon apprentice_unmap(CAST(struct magic_map *, ml->map)); 596267843Sdelphij free(ml); 597276415Sdelphij if (ml == mlist) 598276415Sdelphij break; 599267843Sdelphij } 600267843Sdelphij} 601267843Sdelphij 602276415Sdelphij#ifndef COMPILE_ONLY 603276415Sdelphij/* void **bufs: an array of compiled magic files */ 604276415Sdelphijprotected int 605276415Sdelphijbuffer_apprentice(struct magic_set *ms, struct magic **bufs, 606276415Sdelphij size_t *sizes, size_t nbufs) 607276415Sdelphij{ 608276415Sdelphij size_t i, j; 609276415Sdelphij struct mlist *ml; 610276415Sdelphij struct magic_map *map; 611276415Sdelphij 612276415Sdelphij if (nbufs == 0) 613276415Sdelphij return -1; 614276415Sdelphij 615330569Sgordon (void)file_reset(ms, 0); 616276415Sdelphij 617276415Sdelphij init_file_tables(); 618276415Sdelphij 619276415Sdelphij for (i = 0; i < MAGIC_SETS; i++) { 620276415Sdelphij mlist_free(ms->mlist[i]); 621276415Sdelphij if ((ms->mlist[i] = mlist_alloc()) == NULL) { 622276415Sdelphij file_oomem(ms, sizeof(*ms->mlist[i])); 623276415Sdelphij goto fail; 624276415Sdelphij } 625276415Sdelphij } 626276415Sdelphij 627276415Sdelphij for (i = 0; i < nbufs; i++) { 628276415Sdelphij map = apprentice_buf(ms, bufs[i], sizes[i]); 629276415Sdelphij if (map == NULL) 630276415Sdelphij goto fail; 631276415Sdelphij 632276415Sdelphij for (j = 0; j < MAGIC_SETS; j++) { 633276415Sdelphij if (add_mlist(ms->mlist[j], map, j) == -1) { 634276415Sdelphij file_oomem(ms, sizeof(*ml)); 635276415Sdelphij goto fail; 636276415Sdelphij } 637276415Sdelphij } 638276415Sdelphij } 639276415Sdelphij 640276415Sdelphij return 0; 641276415Sdelphijfail: 642276415Sdelphij for (i = 0; i < MAGIC_SETS; i++) { 643276415Sdelphij mlist_free(ms->mlist[i]); 644276415Sdelphij ms->mlist[i] = NULL; 645276415Sdelphij } 646276415Sdelphij return -1; 647276415Sdelphij} 648276415Sdelphij#endif 649276415Sdelphij 650186690Sobrien/* const char *fn: list of magic files and directories */ 651267843Sdelphijprotected int 652133359Sobrienfile_apprentice(struct magic_set *ms, const char *fn, int action) 65368349Sobrien{ 654186690Sobrien char *p, *mfn; 65568349Sobrien int file_err, errs = -1; 656267843Sdelphij size_t i; 65768349Sobrien 658330569Sgordon (void)file_reset(ms, 0); 659267843Sdelphij 660226048Sobrien if ((fn = magic_getpath(fn, action)) == NULL) 661267843Sdelphij return -1; 662226048Sobrien 663169962Sobrien init_file_tables(); 664169962Sobrien 665169962Sobrien if ((mfn = strdup(fn)) == NULL) { 666169942Sobrien file_oomem(ms, strlen(fn)); 667267843Sdelphij return -1; 66868349Sobrien } 669133359Sobrien 670267843Sdelphij for (i = 0; i < MAGIC_SETS; i++) { 671267843Sdelphij mlist_free(ms->mlist[i]); 672267843Sdelphij if ((ms->mlist[i] = mlist_alloc()) == NULL) { 673267843Sdelphij file_oomem(ms, sizeof(*ms->mlist[i])); 674276415Sdelphij while (i-- > 0) { 675276415Sdelphij mlist_free(ms->mlist[i]); 676276415Sdelphij ms->mlist[i] = NULL; 677267843Sdelphij } 678267843Sdelphij free(mfn); 679267843Sdelphij return -1; 680267843Sdelphij } 681133359Sobrien } 682267843Sdelphij fn = mfn; 683133359Sobrien 68468349Sobrien while (fn) { 68568349Sobrien p = strchr(fn, PATHSEP); 68668349Sobrien if (p) 68768349Sobrien *p++ = '\0'; 688133359Sobrien if (*fn == '\0') 689133359Sobrien break; 690267843Sdelphij file_err = apprentice_1(ms, fn, action); 691186690Sobrien errs = MAX(errs, file_err); 69268349Sobrien fn = p; 69368349Sobrien } 694267843Sdelphij 695267843Sdelphij free(mfn); 696267843Sdelphij 697133359Sobrien if (errs == -1) { 698267843Sdelphij for (i = 0; i < MAGIC_SETS; i++) { 699267843Sdelphij mlist_free(ms->mlist[i]); 700267843Sdelphij ms->mlist[i] = NULL; 701267843Sdelphij } 702267843Sdelphij file_error(ms, 0, "could not find any valid magic files!"); 703267843Sdelphij return -1; 704133359Sobrien } 705267843Sdelphij 706267843Sdelphij#if 0 707267843Sdelphij /* 708267843Sdelphij * Always leave the database loaded 709267843Sdelphij */ 710267843Sdelphij if (action == FILE_LOAD) 711267843Sdelphij return 0; 712267843Sdelphij 713267843Sdelphij for (i = 0; i < MAGIC_SETS; i++) { 714267843Sdelphij mlist_free(ms->mlist[i]); 715267843Sdelphij ms->mlist[i] = NULL; 716267843Sdelphij } 717267843Sdelphij#endif 718267843Sdelphij 719267843Sdelphij switch (action) { 720267843Sdelphij case FILE_LOAD: 721267843Sdelphij case FILE_COMPILE: 722267843Sdelphij case FILE_CHECK: 723267843Sdelphij case FILE_LIST: 724267843Sdelphij return 0; 725267843Sdelphij default: 726267843Sdelphij file_error(ms, 0, "Invalid action %d", action); 727267843Sdelphij return -1; 728267843Sdelphij } 72968349Sobrien} 73068349Sobrien 731169942Sobrien/* 732267843Sdelphij * Compute the real length of a magic expression, for the purposes 733267843Sdelphij * of determining how "strong" a magic expression is (approximating 734267843Sdelphij * how specific its matches are): 735267843Sdelphij * - magic characters count 0 unless escaped. 736267843Sdelphij * - [] expressions count 1 737267843Sdelphij * - {} expressions count 0 738267843Sdelphij * - regular characters or escaped magic characters count 1 739267843Sdelphij * - 0 length expressions count as one 740267843Sdelphij */ 741267843Sdelphijprivate size_t 742267843Sdelphijnonmagic(const char *str) 743267843Sdelphij{ 744267843Sdelphij const char *p; 745267843Sdelphij size_t rv = 0; 746267843Sdelphij 747267843Sdelphij for (p = str; *p; p++) 748267843Sdelphij switch (*p) { 749267843Sdelphij case '\\': /* Escaped anything counts 1 */ 750267843Sdelphij if (!*++p) 751267843Sdelphij p--; 752267843Sdelphij rv++; 753267843Sdelphij continue; 754267843Sdelphij case '?': /* Magic characters count 0 */ 755267843Sdelphij case '*': 756267843Sdelphij case '.': 757267843Sdelphij case '+': 758267843Sdelphij case '^': 759267843Sdelphij case '$': 760267843Sdelphij continue; 761267843Sdelphij case '[': /* Bracketed expressions count 1 the ']' */ 762267843Sdelphij while (*p && *p != ']') 763267843Sdelphij p++; 764267843Sdelphij p--; 765267843Sdelphij continue; 766267843Sdelphij case '{': /* Braced expressions count 0 */ 767267843Sdelphij while (*p && *p != '}') 768267843Sdelphij p++; 769267843Sdelphij if (!*p) 770267843Sdelphij p--; 771267843Sdelphij continue; 772267843Sdelphij default: /* Anything else counts 1 */ 773267843Sdelphij rv++; 774267843Sdelphij continue; 775267843Sdelphij } 776267843Sdelphij 777267843Sdelphij return rv == 0 ? 1 : rv; /* Return at least 1 */ 778267843Sdelphij} 779267843Sdelphij 780330569Sgordon 781330569Sgordonprivate size_t 782330569Sgordontypesize(int type) 783330569Sgordon{ 784330569Sgordon switch (type) { 785330569Sgordon case FILE_BYTE: 786330569Sgordon return 1; 787330569Sgordon 788330569Sgordon case FILE_SHORT: 789330569Sgordon case FILE_LESHORT: 790330569Sgordon case FILE_BESHORT: 791330569Sgordon return 2; 792330569Sgordon 793330569Sgordon case FILE_LONG: 794330569Sgordon case FILE_LELONG: 795330569Sgordon case FILE_BELONG: 796330569Sgordon case FILE_MELONG: 797330569Sgordon return 4; 798330569Sgordon 799330569Sgordon case FILE_DATE: 800330569Sgordon case FILE_LEDATE: 801330569Sgordon case FILE_BEDATE: 802330569Sgordon case FILE_MEDATE: 803330569Sgordon case FILE_LDATE: 804330569Sgordon case FILE_LELDATE: 805330569Sgordon case FILE_BELDATE: 806330569Sgordon case FILE_MELDATE: 807330569Sgordon case FILE_FLOAT: 808330569Sgordon case FILE_BEFLOAT: 809330569Sgordon case FILE_LEFLOAT: 810330569Sgordon return 4; 811330569Sgordon 812330569Sgordon case FILE_QUAD: 813330569Sgordon case FILE_BEQUAD: 814330569Sgordon case FILE_LEQUAD: 815330569Sgordon case FILE_QDATE: 816330569Sgordon case FILE_LEQDATE: 817330569Sgordon case FILE_BEQDATE: 818330569Sgordon case FILE_QLDATE: 819330569Sgordon case FILE_LEQLDATE: 820330569Sgordon case FILE_BEQLDATE: 821330569Sgordon case FILE_QWDATE: 822330569Sgordon case FILE_LEQWDATE: 823330569Sgordon case FILE_BEQWDATE: 824330569Sgordon case FILE_DOUBLE: 825330569Sgordon case FILE_BEDOUBLE: 826330569Sgordon case FILE_LEDOUBLE: 827330569Sgordon return 8; 828330569Sgordon default: 829330569Sgordon return (size_t)~0; 830330569Sgordon } 831330569Sgordon} 832330569Sgordon 833267843Sdelphij/* 834169942Sobrien * Get weight of this magic entry, for sorting purposes. 835169942Sobrien */ 836159764Sobrienprivate size_t 837159764Sobrienapprentice_magic_strength(const struct magic *m) 838159764Sobrien{ 839169942Sobrien#define MULT 10 840330569Sgordon size_t ts, v, val = 2 * MULT; /* baseline strength */ 841169942Sobrien 842159764Sobrien switch (m->type) { 843169962Sobrien case FILE_DEFAULT: /* make sure this sorts last */ 844186690Sobrien if (m->factor_op != FILE_FACTOR_OP_NONE) 845186690Sobrien abort(); 846169962Sobrien return 0; 847169962Sobrien 848159764Sobrien case FILE_BYTE: 849159764Sobrien case FILE_SHORT: 850159764Sobrien case FILE_LESHORT: 851159764Sobrien case FILE_BESHORT: 852159764Sobrien case FILE_LONG: 853159764Sobrien case FILE_LELONG: 854159764Sobrien case FILE_BELONG: 855159764Sobrien case FILE_MELONG: 856159764Sobrien case FILE_DATE: 857159764Sobrien case FILE_LEDATE: 858159764Sobrien case FILE_BEDATE: 859159764Sobrien case FILE_MEDATE: 860159764Sobrien case FILE_LDATE: 861159764Sobrien case FILE_LELDATE: 862159764Sobrien case FILE_BELDATE: 863159764Sobrien case FILE_MELDATE: 864175296Sobrien case FILE_FLOAT: 865175296Sobrien case FILE_BEFLOAT: 866175296Sobrien case FILE_LEFLOAT: 867169942Sobrien case FILE_QUAD: 868169942Sobrien case FILE_BEQUAD: 869169942Sobrien case FILE_LEQUAD: 870169942Sobrien case FILE_QDATE: 871169942Sobrien case FILE_LEQDATE: 872169942Sobrien case FILE_BEQDATE: 873169942Sobrien case FILE_QLDATE: 874169942Sobrien case FILE_LEQLDATE: 875169942Sobrien case FILE_BEQLDATE: 876267843Sdelphij case FILE_QWDATE: 877267843Sdelphij case FILE_LEQWDATE: 878267843Sdelphij case FILE_BEQWDATE: 879175296Sobrien case FILE_DOUBLE: 880175296Sobrien case FILE_BEDOUBLE: 881175296Sobrien case FILE_LEDOUBLE: 882330569Sgordon ts = typesize(m->type); 883330569Sgordon if (ts == (size_t)~0) 884330569Sgordon abort(); 885330569Sgordon val += ts * MULT; 886169942Sobrien break; 887169942Sobrien 888330569Sgordon case FILE_PSTRING: 889330569Sgordon case FILE_STRING: 890330569Sgordon val += m->vallen * MULT; 891330569Sgordon break; 892330569Sgordon 893330569Sgordon case FILE_BESTRING16: 894330569Sgordon case FILE_LESTRING16: 895330569Sgordon val += m->vallen * MULT / 2; 896330569Sgordon break; 897330569Sgordon 898330569Sgordon case FILE_SEARCH: 899330569Sgordon val += m->vallen * MAX(MULT / m->vallen, 1); 900330569Sgordon break; 901330569Sgordon 902330569Sgordon case FILE_REGEX: 903330569Sgordon v = nonmagic(m->value.s); 904330569Sgordon val += v * MAX(MULT / v, 1); 905330569Sgordon break; 906330569Sgordon 907267843Sdelphij case FILE_INDIRECT: 908267843Sdelphij case FILE_NAME: 909267843Sdelphij case FILE_USE: 910267843Sdelphij break; 911267843Sdelphij 912330569Sgordon case FILE_DER: 913330569Sgordon val += MULT; 914330569Sgordon break; 915330569Sgordon 916159764Sobrien default: 917169942Sobrien (void)fprintf(stderr, "Bad type %d\n", m->type); 918169942Sobrien abort(); 919159764Sobrien } 920169942Sobrien 921169942Sobrien switch (m->reln) { 922169942Sobrien case 'x': /* matches anything penalize */ 923186690Sobrien case '!': /* matches almost anything penalize */ 924169942Sobrien val = 0; 925169942Sobrien break; 926169942Sobrien 927169942Sobrien case '=': /* Exact match, prefer */ 928169942Sobrien val += MULT; 929169942Sobrien break; 930169942Sobrien 931169942Sobrien case '>': 932169942Sobrien case '<': /* comparison match reduce strength */ 933169942Sobrien val -= 2 * MULT; 934169942Sobrien break; 935169942Sobrien 936169942Sobrien case '^': 937169942Sobrien case '&': /* masking bits, we could count them too */ 938169942Sobrien val -= MULT; 939169942Sobrien break; 940169942Sobrien 941169942Sobrien default: 942169942Sobrien (void)fprintf(stderr, "Bad relation %c\n", m->reln); 943169942Sobrien abort(); 944169942Sobrien } 945169962Sobrien 946169962Sobrien if (val == 0) /* ensure we only return 0 for FILE_DEFAULT */ 947169962Sobrien val = 1; 948169962Sobrien 949186690Sobrien switch (m->factor_op) { 950186690Sobrien case FILE_FACTOR_OP_NONE: 951186690Sobrien break; 952186690Sobrien case FILE_FACTOR_OP_PLUS: 953186690Sobrien val += m->factor; 954186690Sobrien break; 955186690Sobrien case FILE_FACTOR_OP_MINUS: 956186690Sobrien val -= m->factor; 957186690Sobrien break; 958186690Sobrien case FILE_FACTOR_OP_TIMES: 959186690Sobrien val *= m->factor; 960186690Sobrien break; 961186690Sobrien case FILE_FACTOR_OP_DIV: 962186690Sobrien val /= m->factor; 963186690Sobrien break; 964186690Sobrien default: 965186690Sobrien abort(); 966186690Sobrien } 967186690Sobrien 968186690Sobrien /* 969186690Sobrien * Magic entries with no description get a bonus because they depend 970186690Sobrien * on subsequent magic entries to print something. 971186690Sobrien */ 972186690Sobrien if (m->desc[0] == '\0') 973186690Sobrien val++; 974169942Sobrien return val; 975159764Sobrien} 976159764Sobrien 977169942Sobrien/* 978169942Sobrien * Sort callback for sorting entries by "strength" (basically length) 979169942Sobrien */ 980159764Sobrienprivate int 981159764Sobrienapprentice_sort(const void *a, const void *b) 982159764Sobrien{ 983186690Sobrien const struct magic_entry *ma = CAST(const struct magic_entry *, a); 984186690Sobrien const struct magic_entry *mb = CAST(const struct magic_entry *, b); 985159764Sobrien size_t sa = apprentice_magic_strength(ma->mp); 986159764Sobrien size_t sb = apprentice_magic_strength(mb->mp); 987159764Sobrien if (sa == sb) 988159764Sobrien return 0; 989159764Sobrien else if (sa > sb) 990159764Sobrien return -1; 991159764Sobrien else 992159764Sobrien return 1; 993159764Sobrien} 994159764Sobrien 995226048Sobrien/* 996226048Sobrien * Shows sorted patterns list in the order which is used for the matching 997226048Sobrien */ 998186690Sobrienprivate void 999226048Sobrienapprentice_list(struct mlist *mlist, int mode) 1000226048Sobrien{ 1001226048Sobrien uint32_t magindex = 0; 1002226048Sobrien struct mlist *ml; 1003226048Sobrien for (ml = mlist->next; ml != mlist; ml = ml->next) { 1004226048Sobrien for (magindex = 0; magindex < ml->nmagic; magindex++) { 1005226048Sobrien struct magic *m = &ml->magic[magindex]; 1006226048Sobrien if ((m->flag & mode) != mode) { 1007226048Sobrien /* Skip sub-tests */ 1008226048Sobrien while (magindex + 1 < ml->nmagic && 1009226048Sobrien ml->magic[magindex + 1].cont_level != 0) 1010226048Sobrien ++magindex; 1011226048Sobrien continue; /* Skip to next top-level test*/ 1012226048Sobrien } 1013226048Sobrien 1014226048Sobrien /* 1015226048Sobrien * Try to iterate over the tree until we find item with 1016226048Sobrien * description/mimetype. 1017226048Sobrien */ 1018226048Sobrien while (magindex + 1 < ml->nmagic && 1019226048Sobrien ml->magic[magindex + 1].cont_level != 0 && 1020226048Sobrien *ml->magic[magindex].desc == '\0' && 1021226048Sobrien *ml->magic[magindex].mimetype == '\0') 1022226048Sobrien magindex++; 1023226048Sobrien 1024284778Sdelphij printf("Strength = %3" SIZE_T_FORMAT "u@%u: %s [%s]\n", 1025226048Sobrien apprentice_magic_strength(m), 1026284778Sdelphij ml->magic[magindex].lineno, 1027226048Sobrien ml->magic[magindex].desc, 1028226048Sobrien ml->magic[magindex].mimetype); 1029226048Sobrien } 1030226048Sobrien } 1031226048Sobrien} 1032226048Sobrien 1033226048Sobrienprivate void 1034186690Sobrienset_test_type(struct magic *mstart, struct magic *m) 1035186690Sobrien{ 1036186690Sobrien switch (m->type) { 1037186690Sobrien case FILE_BYTE: 1038186690Sobrien case FILE_SHORT: 1039186690Sobrien case FILE_LONG: 1040186690Sobrien case FILE_DATE: 1041186690Sobrien case FILE_BESHORT: 1042186690Sobrien case FILE_BELONG: 1043186690Sobrien case FILE_BEDATE: 1044186690Sobrien case FILE_LESHORT: 1045186690Sobrien case FILE_LELONG: 1046186690Sobrien case FILE_LEDATE: 1047186690Sobrien case FILE_LDATE: 1048186690Sobrien case FILE_BELDATE: 1049186690Sobrien case FILE_LELDATE: 1050186690Sobrien case FILE_MEDATE: 1051186690Sobrien case FILE_MELDATE: 1052186690Sobrien case FILE_MELONG: 1053186690Sobrien case FILE_QUAD: 1054186690Sobrien case FILE_LEQUAD: 1055186690Sobrien case FILE_BEQUAD: 1056186690Sobrien case FILE_QDATE: 1057186690Sobrien case FILE_LEQDATE: 1058186690Sobrien case FILE_BEQDATE: 1059186690Sobrien case FILE_QLDATE: 1060186690Sobrien case FILE_LEQLDATE: 1061186690Sobrien case FILE_BEQLDATE: 1062267843Sdelphij case FILE_QWDATE: 1063267843Sdelphij case FILE_LEQWDATE: 1064267843Sdelphij case FILE_BEQWDATE: 1065186690Sobrien case FILE_FLOAT: 1066186690Sobrien case FILE_BEFLOAT: 1067186690Sobrien case FILE_LEFLOAT: 1068186690Sobrien case FILE_DOUBLE: 1069186690Sobrien case FILE_BEDOUBLE: 1070186690Sobrien case FILE_LEDOUBLE: 1071330569Sgordon case FILE_DER: 1072226048Sobrien mstart->flag |= BINTEST; 1073226048Sobrien break; 1074186690Sobrien case FILE_STRING: 1075186690Sobrien case FILE_PSTRING: 1076186690Sobrien case FILE_BESTRING16: 1077186690Sobrien case FILE_LESTRING16: 1078226048Sobrien /* Allow text overrides */ 1079226048Sobrien if (mstart->str_flags & STRING_TEXTTEST) 1080226048Sobrien mstart->flag |= TEXTTEST; 1081226048Sobrien else 1082226048Sobrien mstart->flag |= BINTEST; 1083186690Sobrien break; 1084186690Sobrien case FILE_REGEX: 1085186690Sobrien case FILE_SEARCH: 1086226048Sobrien /* Check for override */ 1087226048Sobrien if (mstart->str_flags & STRING_BINTEST) 1088226048Sobrien mstart->flag |= BINTEST; 1089226048Sobrien if (mstart->str_flags & STRING_TEXTTEST) 1090226048Sobrien mstart->flag |= TEXTTEST; 1091226048Sobrien 1092226048Sobrien if (mstart->flag & (TEXTTEST|BINTEST)) 1093226048Sobrien break; 1094226048Sobrien 1095186690Sobrien /* binary test if pattern is not text */ 1096191736Sobrien if (file_looks_utf8(m->value.us, (size_t)m->vallen, NULL, 1097191736Sobrien NULL) <= 0) 1098186690Sobrien mstart->flag |= BINTEST; 1099226048Sobrien else 1100226048Sobrien mstart->flag |= TEXTTEST; 1101186690Sobrien break; 1102186690Sobrien case FILE_DEFAULT: 1103186690Sobrien /* can't deduce anything; we shouldn't see this at the 1104186690Sobrien top level anyway */ 1105186690Sobrien break; 1106186690Sobrien case FILE_INVALID: 1107186690Sobrien default: 1108186690Sobrien /* invalid search type, but no need to complain here */ 1109186690Sobrien break; 1110186690Sobrien } 1111186690Sobrien} 1112186690Sobrien 1113267843Sdelphijprivate int 1114267843Sdelphijaddentry(struct magic_set *ms, struct magic_entry *me, 1115267843Sdelphij struct magic_entry_set *mset) 1116267843Sdelphij{ 1117267843Sdelphij size_t i = me->mp->type == FILE_NAME ? 1 : 0; 1118267843Sdelphij if (mset[i].count == mset[i].max) { 1119267843Sdelphij struct magic_entry *mp; 1120267843Sdelphij 1121267843Sdelphij mset[i].max += ALLOC_INCR; 1122267843Sdelphij if ((mp = CAST(struct magic_entry *, 1123267843Sdelphij realloc(mset[i].me, sizeof(*mp) * mset[i].max))) == 1124267843Sdelphij NULL) { 1125267843Sdelphij file_oomem(ms, sizeof(*mp) * mset[i].max); 1126267843Sdelphij return -1; 1127267843Sdelphij } 1128267843Sdelphij (void)memset(&mp[mset[i].count], 0, sizeof(*mp) * 1129267843Sdelphij ALLOC_INCR); 1130267843Sdelphij mset[i].me = mp; 1131267843Sdelphij } 1132267843Sdelphij mset[i].me[mset[i].count++] = *me; 1133267843Sdelphij memset(me, 0, sizeof(*me)); 1134267843Sdelphij return 0; 1135267843Sdelphij} 1136267843Sdelphij 113774784Sobrien/* 1138186690Sobrien * Load and parse one file. 113974784Sobrien */ 1140186690Sobrienprivate void 1141186690Sobrienload_1(struct magic_set *ms, int action, const char *fn, int *errs, 1142267843Sdelphij struct magic_entry_set *mset) 1143186690Sobrien{ 1144226048Sobrien size_t lineno = 0, llen = 0; 1145226048Sobrien char *line = NULL; 1146226048Sobrien ssize_t len; 1147267843Sdelphij struct magic_entry me; 1148226048Sobrien 1149186690Sobrien FILE *f = fopen(ms->file = fn, "r"); 1150186690Sobrien if (f == NULL) { 1151186690Sobrien if (errno != ENOENT) 1152186690Sobrien file_error(ms, errno, "cannot read magic file `%s'", 1153186690Sobrien fn); 1154186690Sobrien (*errs)++; 1155226048Sobrien return; 1156226048Sobrien } 1157226048Sobrien 1158267843Sdelphij memset(&me, 0, sizeof(me)); 1159226048Sobrien /* read and parse this file */ 1160226048Sobrien for (ms->line = 1; (len = getline(&line, &llen, f)) != -1; 1161226048Sobrien ms->line++) { 1162226048Sobrien if (len == 0) /* null line, garbage, etc */ 1163226048Sobrien continue; 1164226048Sobrien if (line[len - 1] == '\n') { 1165226048Sobrien lineno++; 1166226048Sobrien line[len - 1] = '\0'; /* delete newline */ 1167226048Sobrien } 1168226048Sobrien switch (line[0]) { 1169226048Sobrien case '\0': /* empty, do not parse */ 1170226048Sobrien case '#': /* comment, do not parse */ 1171226048Sobrien continue; 1172226048Sobrien case '!': 1173226048Sobrien if (line[1] == ':') { 1174186690Sobrien size_t i; 1175186690Sobrien 1176186690Sobrien for (i = 0; bang[i].name != NULL; i++) { 1177226048Sobrien if ((size_t)(len - 2) > bang[i].len && 1178186690Sobrien memcmp(bang[i].name, line + 2, 1179186690Sobrien bang[i].len) == 0) 1180186690Sobrien break; 1181186690Sobrien } 1182186690Sobrien if (bang[i].name == NULL) { 1183186690Sobrien file_error(ms, 0, 1184186690Sobrien "Unknown !: entry `%s'", line); 1185186690Sobrien (*errs)++; 1186186690Sobrien continue; 1187186690Sobrien } 1188267843Sdelphij if (me.mp == NULL) { 1189186690Sobrien file_error(ms, 0, 1190186690Sobrien "No current entry for :!%s type", 1191186690Sobrien bang[i].name); 1192186690Sobrien (*errs)++; 1193186690Sobrien continue; 1194186690Sobrien } 1195267843Sdelphij if ((*bang[i].fun)(ms, &me, 1196186690Sobrien line + bang[i].len + 2) != 0) { 1197186690Sobrien (*errs)++; 1198186690Sobrien continue; 1199186690Sobrien } 1200186690Sobrien continue; 1201186690Sobrien } 1202226048Sobrien /*FALLTHROUGH*/ 1203226048Sobrien default: 1204267843Sdelphij again: 1205267843Sdelphij switch (parse(ms, &me, line, lineno, action)) { 1206267843Sdelphij case 0: 1207267843Sdelphij continue; 1208267843Sdelphij case 1: 1209267843Sdelphij (void)addentry(ms, &me, mset); 1210267843Sdelphij goto again; 1211267843Sdelphij default: 1212186690Sobrien (*errs)++; 1213267843Sdelphij break; 1214267843Sdelphij } 1215186690Sobrien } 1216186690Sobrien } 1217267843Sdelphij if (me.mp) 1218267843Sdelphij (void)addentry(ms, &me, mset); 1219234250Sobrien free(line); 1220226048Sobrien (void)fclose(f); 1221186690Sobrien} 1222186690Sobrien 1223186690Sobrien/* 1224186690Sobrien * parse a file or directory of files 1225186690Sobrien * const char *fn: name of magic file or directory 1226186690Sobrien */ 1227133359Sobrienprivate int 1228226048Sobriencmpstrp(const void *p1, const void *p2) 1229226048Sobrien{ 1230226048Sobrien return strcmp(*(char *const *)p1, *(char *const *)p2); 1231226048Sobrien} 1232226048Sobrien 1233267843Sdelphij 1234267843Sdelphijprivate uint32_t 1235267843Sdelphijset_text_binary(struct magic_set *ms, struct magic_entry *me, uint32_t nme, 1236267843Sdelphij uint32_t starttest) 1237267843Sdelphij{ 1238267843Sdelphij static const char text[] = "text"; 1239267843Sdelphij static const char binary[] = "binary"; 1240267843Sdelphij static const size_t len = sizeof(text); 1241267843Sdelphij 1242267843Sdelphij uint32_t i = starttest; 1243267843Sdelphij 1244267843Sdelphij do { 1245267843Sdelphij set_test_type(me[starttest].mp, me[i].mp); 1246267843Sdelphij if ((ms->flags & MAGIC_DEBUG) == 0) 1247267843Sdelphij continue; 1248267843Sdelphij (void)fprintf(stderr, "%s%s%s: %s\n", 1249267843Sdelphij me[i].mp->mimetype, 1250267843Sdelphij me[i].mp->mimetype[0] == '\0' ? "" : "; ", 1251267843Sdelphij me[i].mp->desc[0] ? me[i].mp->desc : "(no description)", 1252267843Sdelphij me[i].mp->flag & BINTEST ? binary : text); 1253267843Sdelphij if (me[i].mp->flag & BINTEST) { 1254267843Sdelphij char *p = strstr(me[i].mp->desc, text); 1255267843Sdelphij if (p && (p == me[i].mp->desc || 1256267843Sdelphij isspace((unsigned char)p[-1])) && 1257267843Sdelphij (p + len - me[i].mp->desc == MAXstring 1258267843Sdelphij || (p[len] == '\0' || 1259267843Sdelphij isspace((unsigned char)p[len])))) 1260267843Sdelphij (void)fprintf(stderr, "*** Possible " 1261267843Sdelphij "binary test for text type\n"); 1262267843Sdelphij } 1263267843Sdelphij } while (++i < nme && me[i].mp->cont_level != 0); 1264267843Sdelphij return i; 1265267843Sdelphij} 1266267843Sdelphij 1267267843Sdelphijprivate void 1268267843Sdelphijset_last_default(struct magic_set *ms, struct magic_entry *me, uint32_t nme) 1269267843Sdelphij{ 1270267843Sdelphij uint32_t i; 1271267843Sdelphij for (i = 0; i < nme; i++) { 1272267843Sdelphij if (me[i].mp->cont_level == 0 && 1273267843Sdelphij me[i].mp->type == FILE_DEFAULT) { 1274267843Sdelphij while (++i < nme) 1275267843Sdelphij if (me[i].mp->cont_level == 0) 1276267843Sdelphij break; 1277267843Sdelphij if (i != nme) { 1278267843Sdelphij /* XXX - Ugh! */ 1279267843Sdelphij ms->line = me[i].mp->lineno; 1280267843Sdelphij file_magwarn(ms, 1281267843Sdelphij "level 0 \"default\" did not sort last"); 1282267843Sdelphij } 1283267843Sdelphij return; 1284267843Sdelphij } 1285267843Sdelphij } 1286267843Sdelphij} 1287267843Sdelphij 1288226048Sobrienprivate int 1289267843Sdelphijcoalesce_entries(struct magic_set *ms, struct magic_entry *me, uint32_t nme, 1290267843Sdelphij struct magic **ma, uint32_t *nma) 129168349Sobrien{ 1292267843Sdelphij uint32_t i, mentrycount = 0; 1293267843Sdelphij size_t slen; 1294267843Sdelphij 1295267843Sdelphij for (i = 0; i < nme; i++) 1296267843Sdelphij mentrycount += me[i].cont_count; 1297267843Sdelphij 1298267843Sdelphij slen = sizeof(**ma) * mentrycount; 1299267843Sdelphij if ((*ma = CAST(struct magic *, malloc(slen))) == NULL) { 1300267843Sdelphij file_oomem(ms, slen); 1301267843Sdelphij return -1; 1302267843Sdelphij } 1303267843Sdelphij 1304267843Sdelphij mentrycount = 0; 1305267843Sdelphij for (i = 0; i < nme; i++) { 1306267843Sdelphij (void)memcpy(*ma + mentrycount, me[i].mp, 1307267843Sdelphij me[i].cont_count * sizeof(**ma)); 1308267843Sdelphij mentrycount += me[i].cont_count; 1309267843Sdelphij } 1310267843Sdelphij *nma = mentrycount; 1311267843Sdelphij return 0; 1312267843Sdelphij} 1313267843Sdelphij 1314267843Sdelphijprivate void 1315267843Sdelphijmagic_entry_free(struct magic_entry *me, uint32_t nme) 1316267843Sdelphij{ 1317267843Sdelphij uint32_t i; 1318267843Sdelphij if (me == NULL) 1319267843Sdelphij return; 1320267843Sdelphij for (i = 0; i < nme; i++) 1321267843Sdelphij free(me[i].mp); 1322267843Sdelphij free(me); 1323267843Sdelphij} 1324267843Sdelphij 1325267843Sdelphijprivate struct magic_map * 1326267843Sdelphijapprentice_load(struct magic_set *ms, const char *fn, int action) 1327267843Sdelphij{ 132868349Sobrien int errs = 0; 1329267843Sdelphij uint32_t i, j; 1330267843Sdelphij size_t files = 0, maxfiles = 0; 1331226048Sobrien char **filearr = NULL, *mfn; 1332186690Sobrien struct stat st; 1333267843Sdelphij struct magic_map *map; 1334267843Sdelphij struct magic_entry_set mset[MAGIC_SETS]; 1335186690Sobrien DIR *dir; 1336186690Sobrien struct dirent *d; 133768349Sobrien 1338267843Sdelphij memset(mset, 0, sizeof(mset)); 1339169942Sobrien ms->flags |= MAGIC_CHECK; /* Enable checks for parsed files */ 1340169942Sobrien 1341267843Sdelphij 1342267843Sdelphij if ((map = CAST(struct magic_map *, calloc(1, sizeof(*map)))) == NULL) 1343267843Sdelphij { 1344267843Sdelphij file_oomem(ms, sizeof(*map)); 1345267843Sdelphij return NULL; 134674784Sobrien } 1347290152Sdelphij map->type = MAP_TYPE_MALLOC; 134874784Sobrien 1349133359Sobrien /* print silly verbose header for USG compat. */ 1350133359Sobrien if (action == FILE_CHECK) 1351186690Sobrien (void)fprintf(stderr, "%s\n", usg_hdr); 1352133359Sobrien 1353186690Sobrien /* load directory or file */ 1354186690Sobrien if (stat(fn, &st) == 0 && S_ISDIR(st.st_mode)) { 1355186690Sobrien dir = opendir(fn); 1356226048Sobrien if (!dir) { 1357226048Sobrien errs++; 1358226048Sobrien goto out; 1359226048Sobrien } 1360226048Sobrien while ((d = readdir(dir)) != NULL) { 1361330569Sgordon if (d->d_name[0] == '.') 1362330569Sgordon continue; 1363226048Sobrien if (asprintf(&mfn, "%s/%s", fn, d->d_name) < 0) { 1364226048Sobrien file_oomem(ms, 1365226048Sobrien strlen(fn) + strlen(d->d_name) + 2); 1366226048Sobrien errs++; 1367234250Sobrien closedir(dir); 1368226048Sobrien goto out; 1369226048Sobrien } 1370226048Sobrien if (stat(mfn, &st) == -1 || !S_ISREG(st.st_mode)) { 1371226048Sobrien free(mfn); 1372226048Sobrien continue; 1373226048Sobrien } 1374226048Sobrien if (files >= maxfiles) { 1375226048Sobrien size_t mlen; 1376226048Sobrien maxfiles = (maxfiles + 1) * 2; 1377226048Sobrien mlen = maxfiles * sizeof(*filearr); 1378226048Sobrien if ((filearr = CAST(char **, 1379226048Sobrien realloc(filearr, mlen))) == NULL) { 1380226048Sobrien file_oomem(ms, mlen); 1381226048Sobrien free(mfn); 1382234250Sobrien closedir(dir); 1383226048Sobrien errs++; 1384226048Sobrien goto out; 1385186690Sobrien } 1386186690Sobrien } 1387226048Sobrien filearr[files++] = mfn; 1388226048Sobrien } 1389226048Sobrien closedir(dir); 1390226048Sobrien qsort(filearr, files, sizeof(*filearr), cmpstrp); 1391226048Sobrien for (i = 0; i < files; i++) { 1392267843Sdelphij load_1(ms, action, filearr[i], &errs, mset); 1393226048Sobrien free(filearr[i]); 1394226048Sobrien } 1395226048Sobrien free(filearr); 1396186690Sobrien } else 1397267843Sdelphij load_1(ms, action, fn, &errs, mset); 1398186690Sobrien if (errs) 1399186690Sobrien goto out; 1400186690Sobrien 1401267843Sdelphij for (j = 0; j < MAGIC_SETS; j++) { 1402267843Sdelphij /* Set types of tests */ 1403267843Sdelphij for (i = 0; i < mset[j].count; ) { 1404267843Sdelphij if (mset[j].me[i].mp->cont_level != 0) { 1405267843Sdelphij i++; 1406186690Sobrien continue; 1407186690Sobrien } 1408267843Sdelphij i = set_text_binary(ms, mset[j].me, mset[j].count, i); 1409267843Sdelphij } 1410290152Sdelphij if (mset[j].me) 1411290152Sdelphij qsort(mset[j].me, mset[j].count, sizeof(*mset[j].me), 1412290152Sdelphij apprentice_sort); 141368349Sobrien 1414267843Sdelphij /* 1415267843Sdelphij * Make sure that any level 0 "default" line is last 1416267843Sdelphij * (if one exists). 1417267843Sdelphij */ 1418267843Sdelphij set_last_default(ms, mset[j].me, mset[j].count); 1419159764Sobrien 1420267843Sdelphij /* coalesce per file arrays into a single one */ 1421267843Sdelphij if (coalesce_entries(ms, mset[j].me, mset[j].count, 1422267843Sdelphij &map->magic[j], &map->nmagic[j]) == -1) { 1423267843Sdelphij errs++; 1424267843Sdelphij goto out; 1425169962Sobrien } 1426169962Sobrien } 1427159764Sobrien 1428267843Sdelphijout: 1429267843Sdelphij for (j = 0; j < MAGIC_SETS; j++) 1430267843Sdelphij magic_entry_free(mset[j].me, mset[j].count); 1431159764Sobrien 143274784Sobrien if (errs) { 1433267843Sdelphij apprentice_unmap(map); 1434267843Sdelphij return NULL; 143574784Sobrien } 1436267843Sdelphij return map; 143768349Sobrien} 143868349Sobrien 143968349Sobrien/* 144068349Sobrien * extend the sign bit if the comparison is to be signed 144168349Sobrien */ 1442169942Sobrienprotected uint64_t 1443169942Sobrienfile_signextend(struct magic_set *ms, struct magic *m, uint64_t v) 144468349Sobrien{ 1445169962Sobrien if (!(m->flag & UNSIGNED)) { 144668349Sobrien switch(m->type) { 144768349Sobrien /* 144868349Sobrien * Do not remove the casts below. They are 144968349Sobrien * vital. When later compared with the data, 145068349Sobrien * the sign extension must have happened. 145168349Sobrien */ 1452133359Sobrien case FILE_BYTE: 1453276415Sdelphij v = (signed char) v; 145468349Sobrien break; 1455133359Sobrien case FILE_SHORT: 1456133359Sobrien case FILE_BESHORT: 1457133359Sobrien case FILE_LESHORT: 145868349Sobrien v = (short) v; 145968349Sobrien break; 1460133359Sobrien case FILE_DATE: 1461133359Sobrien case FILE_BEDATE: 1462133359Sobrien case FILE_LEDATE: 1463159764Sobrien case FILE_MEDATE: 1464133359Sobrien case FILE_LDATE: 1465133359Sobrien case FILE_BELDATE: 1466133359Sobrien case FILE_LELDATE: 1467159764Sobrien case FILE_MELDATE: 1468133359Sobrien case FILE_LONG: 1469133359Sobrien case FILE_BELONG: 1470133359Sobrien case FILE_LELONG: 1471159764Sobrien case FILE_MELONG: 1472175296Sobrien case FILE_FLOAT: 1473175296Sobrien case FILE_BEFLOAT: 1474175296Sobrien case FILE_LEFLOAT: 1475103373Sobrien v = (int32_t) v; 147668349Sobrien break; 1477169942Sobrien case FILE_QUAD: 1478169942Sobrien case FILE_BEQUAD: 1479169942Sobrien case FILE_LEQUAD: 1480169942Sobrien case FILE_QDATE: 1481169942Sobrien case FILE_QLDATE: 1482267843Sdelphij case FILE_QWDATE: 1483169942Sobrien case FILE_BEQDATE: 1484169942Sobrien case FILE_BEQLDATE: 1485267843Sdelphij case FILE_BEQWDATE: 1486169942Sobrien case FILE_LEQDATE: 1487169942Sobrien case FILE_LEQLDATE: 1488267843Sdelphij case FILE_LEQWDATE: 1489175296Sobrien case FILE_DOUBLE: 1490175296Sobrien case FILE_BEDOUBLE: 1491175296Sobrien case FILE_LEDOUBLE: 1492169942Sobrien v = (int64_t) v; 1493169942Sobrien break; 1494133359Sobrien case FILE_STRING: 1495133359Sobrien case FILE_PSTRING: 1496139368Sobrien case FILE_BESTRING16: 1497139368Sobrien case FILE_LESTRING16: 1498133359Sobrien case FILE_REGEX: 1499159764Sobrien case FILE_SEARCH: 1500169962Sobrien case FILE_DEFAULT: 1501191736Sobrien case FILE_INDIRECT: 1502267843Sdelphij case FILE_NAME: 1503267843Sdelphij case FILE_USE: 1504267843Sdelphij case FILE_CLEAR: 1505330569Sgordon case FILE_DER: 1506103373Sobrien break; 150768349Sobrien default: 1508133359Sobrien if (ms->flags & MAGIC_CHECK) 1509139368Sobrien file_magwarn(ms, "cannot happen: m->type=%d\n", 1510133359Sobrien m->type); 1511133359Sobrien return ~0U; 151268349Sobrien } 1513169962Sobrien } 151468349Sobrien return v; 151568349Sobrien} 151668349Sobrien 1517169962Sobrienprivate int 1518186690Sobrienstring_modifier_check(struct magic_set *ms, struct magic *m) 1519169962Sobrien{ 1520169962Sobrien if ((ms->flags & MAGIC_CHECK) == 0) 1521169962Sobrien return 0; 1522169962Sobrien 1523267843Sdelphij if ((m->type != FILE_REGEX || (m->str_flags & REGEX_LINE_COUNT) == 0) && 1524267843Sdelphij (m->type != FILE_PSTRING && (m->str_flags & PSTRING_LEN) != 0)) { 1525226048Sobrien file_magwarn(ms, 1526226048Sobrien "'/BHhLl' modifiers are only allowed for pascal strings\n"); 1527226048Sobrien return -1; 1528226048Sobrien } 1529169962Sobrien switch (m->type) { 1530169962Sobrien case FILE_BESTRING16: 1531169962Sobrien case FILE_LESTRING16: 1532169962Sobrien if (m->str_flags != 0) { 1533186690Sobrien file_magwarn(ms, 1534186690Sobrien "no modifiers allowed for 16-bit strings\n"); 1535169962Sobrien return -1; 1536169962Sobrien } 1537169962Sobrien break; 1538169962Sobrien case FILE_STRING: 1539169962Sobrien case FILE_PSTRING: 1540169962Sobrien if ((m->str_flags & REGEX_OFFSET_START) != 0) { 1541186690Sobrien file_magwarn(ms, 1542186690Sobrien "'/%c' only allowed on regex and search\n", 1543169962Sobrien CHAR_REGEX_OFFSET_START); 1544169962Sobrien return -1; 1545169962Sobrien } 1546169962Sobrien break; 1547169962Sobrien case FILE_SEARCH: 1548186690Sobrien if (m->str_range == 0) { 1549186690Sobrien file_magwarn(ms, 1550186690Sobrien "missing range; defaulting to %d\n", 1551186690Sobrien STRING_DEFAULT_RANGE); 1552186690Sobrien m->str_range = STRING_DEFAULT_RANGE; 1553186690Sobrien return -1; 1554186690Sobrien } 1555169962Sobrien break; 1556169962Sobrien case FILE_REGEX: 1557226048Sobrien if ((m->str_flags & STRING_COMPACT_WHITESPACE) != 0) { 1558169962Sobrien file_magwarn(ms, "'/%c' not allowed on regex\n", 1559226048Sobrien CHAR_COMPACT_WHITESPACE); 1560169962Sobrien return -1; 1561169962Sobrien } 1562226048Sobrien if ((m->str_flags & STRING_COMPACT_OPTIONAL_WHITESPACE) != 0) { 1563169962Sobrien file_magwarn(ms, "'/%c' not allowed on regex\n", 1564226048Sobrien CHAR_COMPACT_OPTIONAL_WHITESPACE); 1565169962Sobrien return -1; 1566169962Sobrien } 1567169962Sobrien break; 1568169962Sobrien default: 1569169962Sobrien file_magwarn(ms, "coding error: m->type=%d\n", 1570169962Sobrien m->type); 1571169962Sobrien return -1; 1572169962Sobrien } 1573169962Sobrien return 0; 1574169962Sobrien} 1575169962Sobrien 1576169962Sobrienprivate int 1577169962Sobrienget_op(char c) 1578169962Sobrien{ 1579169962Sobrien switch (c) { 1580169962Sobrien case '&': 1581169962Sobrien return FILE_OPAND; 1582169962Sobrien case '|': 1583169962Sobrien return FILE_OPOR; 1584169962Sobrien case '^': 1585169962Sobrien return FILE_OPXOR; 1586169962Sobrien case '+': 1587169962Sobrien return FILE_OPADD; 1588169962Sobrien case '-': 1589169962Sobrien return FILE_OPMINUS; 1590169962Sobrien case '*': 1591169962Sobrien return FILE_OPMULTIPLY; 1592169962Sobrien case '/': 1593169962Sobrien return FILE_OPDIVIDE; 1594169962Sobrien case '%': 1595169962Sobrien return FILE_OPMODULO; 1596169962Sobrien default: 1597169962Sobrien return -1; 1598169962Sobrien } 1599169962Sobrien} 1600169962Sobrien 1601169962Sobrien#ifdef ENABLE_CONDITIONALS 1602169962Sobrienprivate int 1603169962Sobrienget_cond(const char *l, const char **t) 1604169962Sobrien{ 1605186690Sobrien static const struct cond_tbl_s { 1606186690Sobrien char name[8]; 1607186690Sobrien size_t len; 1608186690Sobrien int cond; 1609169962Sobrien } cond_tbl[] = { 1610169962Sobrien { "if", 2, COND_IF }, 1611169962Sobrien { "elif", 4, COND_ELIF }, 1612169962Sobrien { "else", 4, COND_ELSE }, 1613186690Sobrien { "", 0, COND_NONE }, 1614169962Sobrien }; 1615186690Sobrien const struct cond_tbl_s *p; 1616169962Sobrien 1617186690Sobrien for (p = cond_tbl; p->len; p++) { 1618169962Sobrien if (strncmp(l, p->name, p->len) == 0 && 1619169962Sobrien isspace((unsigned char)l[p->len])) { 1620169962Sobrien if (t) 1621169962Sobrien *t = l + p->len; 1622169962Sobrien break; 1623169962Sobrien } 1624169962Sobrien } 1625169962Sobrien return p->cond; 1626169962Sobrien} 1627169962Sobrien 1628169962Sobrienprivate int 1629169962Sobriencheck_cond(struct magic_set *ms, int cond, uint32_t cont_level) 1630169962Sobrien{ 1631169962Sobrien int last_cond; 1632169962Sobrien last_cond = ms->c.li[cont_level].last_cond; 1633169962Sobrien 1634169962Sobrien switch (cond) { 1635169962Sobrien case COND_IF: 1636169962Sobrien if (last_cond != COND_NONE && last_cond != COND_ELIF) { 1637169962Sobrien if (ms->flags & MAGIC_CHECK) 1638169962Sobrien file_magwarn(ms, "syntax error: `if'"); 1639169962Sobrien return -1; 1640169962Sobrien } 1641169962Sobrien last_cond = COND_IF; 1642169962Sobrien break; 1643169962Sobrien 1644169962Sobrien case COND_ELIF: 1645169962Sobrien if (last_cond != COND_IF && last_cond != COND_ELIF) { 1646169962Sobrien if (ms->flags & MAGIC_CHECK) 1647169962Sobrien file_magwarn(ms, "syntax error: `elif'"); 1648169962Sobrien return -1; 1649169962Sobrien } 1650169962Sobrien last_cond = COND_ELIF; 1651169962Sobrien break; 1652169962Sobrien 1653169962Sobrien case COND_ELSE: 1654169962Sobrien if (last_cond != COND_IF && last_cond != COND_ELIF) { 1655169962Sobrien if (ms->flags & MAGIC_CHECK) 1656169962Sobrien file_magwarn(ms, "syntax error: `else'"); 1657169962Sobrien return -1; 1658169962Sobrien } 1659169962Sobrien last_cond = COND_NONE; 1660169962Sobrien break; 1661169962Sobrien 1662169962Sobrien case COND_NONE: 1663169962Sobrien last_cond = COND_NONE; 1664169962Sobrien break; 1665169962Sobrien } 1666169962Sobrien 1667169962Sobrien ms->c.li[cont_level].last_cond = last_cond; 1668169962Sobrien return 0; 1669169962Sobrien} 1670169962Sobrien#endif /* ENABLE_CONDITIONALS */ 1671169962Sobrien 1672277592Sdelphijprivate int 1673277592Sdelphijparse_indirect_modifier(struct magic_set *ms, struct magic *m, const char **lp) 1674277592Sdelphij{ 1675277592Sdelphij const char *l = *lp; 1676277592Sdelphij 1677277592Sdelphij while (!isspace((unsigned char)*++l)) 1678277592Sdelphij switch (*l) { 1679277592Sdelphij case CHAR_INDIRECT_RELATIVE: 1680277592Sdelphij m->str_flags |= INDIRECT_RELATIVE; 1681277592Sdelphij break; 1682277592Sdelphij default: 1683277592Sdelphij if (ms->flags & MAGIC_CHECK) 1684277592Sdelphij file_magwarn(ms, "indirect modifier `%c' " 1685277592Sdelphij "invalid", *l); 1686277592Sdelphij *lp = l; 1687277592Sdelphij return -1; 1688277592Sdelphij } 1689277592Sdelphij *lp = l; 1690277592Sdelphij return 0; 1691277592Sdelphij} 1692277592Sdelphij 1693277592Sdelphijprivate void 1694277592Sdelphijparse_op_modifier(struct magic_set *ms, struct magic *m, const char **lp, 1695277592Sdelphij int op) 1696277592Sdelphij{ 1697277592Sdelphij const char *l = *lp; 1698277592Sdelphij char *t; 1699277592Sdelphij uint64_t val; 1700277592Sdelphij 1701277592Sdelphij ++l; 1702277592Sdelphij m->mask_op |= op; 1703277592Sdelphij val = (uint64_t)strtoull(l, &t, 0); 1704277592Sdelphij l = t; 1705277592Sdelphij m->num_mask = file_signextend(ms, m, val); 1706277592Sdelphij eatsize(&l); 1707277592Sdelphij *lp = l; 1708277592Sdelphij} 1709277592Sdelphij 1710277592Sdelphijprivate int 1711277592Sdelphijparse_string_modifier(struct magic_set *ms, struct magic *m, const char **lp) 1712277592Sdelphij{ 1713277592Sdelphij const char *l = *lp; 1714277592Sdelphij char *t; 1715277592Sdelphij int have_range = 0; 1716277592Sdelphij 1717277592Sdelphij while (!isspace((unsigned char)*++l)) { 1718277592Sdelphij switch (*l) { 1719277592Sdelphij case '0': case '1': case '2': 1720277592Sdelphij case '3': case '4': case '5': 1721277592Sdelphij case '6': case '7': case '8': 1722277592Sdelphij case '9': 1723277592Sdelphij if (have_range && (ms->flags & MAGIC_CHECK)) 1724277592Sdelphij file_magwarn(ms, "multiple ranges"); 1725277592Sdelphij have_range = 1; 1726277592Sdelphij m->str_range = CAST(uint32_t, strtoul(l, &t, 0)); 1727277592Sdelphij if (m->str_range == 0) 1728277592Sdelphij file_magwarn(ms, "zero range"); 1729277592Sdelphij l = t - 1; 1730277592Sdelphij break; 1731277592Sdelphij case CHAR_COMPACT_WHITESPACE: 1732277592Sdelphij m->str_flags |= STRING_COMPACT_WHITESPACE; 1733277592Sdelphij break; 1734277592Sdelphij case CHAR_COMPACT_OPTIONAL_WHITESPACE: 1735277592Sdelphij m->str_flags |= STRING_COMPACT_OPTIONAL_WHITESPACE; 1736277592Sdelphij break; 1737277592Sdelphij case CHAR_IGNORE_LOWERCASE: 1738277592Sdelphij m->str_flags |= STRING_IGNORE_LOWERCASE; 1739277592Sdelphij break; 1740277592Sdelphij case CHAR_IGNORE_UPPERCASE: 1741277592Sdelphij m->str_flags |= STRING_IGNORE_UPPERCASE; 1742277592Sdelphij break; 1743277592Sdelphij case CHAR_REGEX_OFFSET_START: 1744277592Sdelphij m->str_flags |= REGEX_OFFSET_START; 1745277592Sdelphij break; 1746277592Sdelphij case CHAR_BINTEST: 1747277592Sdelphij m->str_flags |= STRING_BINTEST; 1748277592Sdelphij break; 1749277592Sdelphij case CHAR_TEXTTEST: 1750277592Sdelphij m->str_flags |= STRING_TEXTTEST; 1751277592Sdelphij break; 1752277592Sdelphij case CHAR_TRIM: 1753277592Sdelphij m->str_flags |= STRING_TRIM; 1754277592Sdelphij break; 1755277592Sdelphij case CHAR_PSTRING_1_LE: 1756277592Sdelphij#define SET_LENGTH(a) m->str_flags = (m->str_flags & ~PSTRING_LEN) | (a) 1757277592Sdelphij if (m->type != FILE_PSTRING) 1758277592Sdelphij goto bad; 1759277592Sdelphij SET_LENGTH(PSTRING_1_LE); 1760277592Sdelphij break; 1761277592Sdelphij case CHAR_PSTRING_2_BE: 1762277592Sdelphij if (m->type != FILE_PSTRING) 1763277592Sdelphij goto bad; 1764277592Sdelphij SET_LENGTH(PSTRING_2_BE); 1765277592Sdelphij break; 1766277592Sdelphij case CHAR_PSTRING_2_LE: 1767277592Sdelphij if (m->type != FILE_PSTRING) 1768277592Sdelphij goto bad; 1769277592Sdelphij SET_LENGTH(PSTRING_2_LE); 1770277592Sdelphij break; 1771277592Sdelphij case CHAR_PSTRING_4_BE: 1772277592Sdelphij if (m->type != FILE_PSTRING) 1773277592Sdelphij goto bad; 1774277592Sdelphij SET_LENGTH(PSTRING_4_BE); 1775277592Sdelphij break; 1776277592Sdelphij case CHAR_PSTRING_4_LE: 1777277592Sdelphij switch (m->type) { 1778277592Sdelphij case FILE_PSTRING: 1779277592Sdelphij case FILE_REGEX: 1780277592Sdelphij break; 1781277592Sdelphij default: 1782277592Sdelphij goto bad; 1783277592Sdelphij } 1784277592Sdelphij SET_LENGTH(PSTRING_4_LE); 1785277592Sdelphij break; 1786277592Sdelphij case CHAR_PSTRING_LENGTH_INCLUDES_ITSELF: 1787277592Sdelphij if (m->type != FILE_PSTRING) 1788277592Sdelphij goto bad; 1789277592Sdelphij m->str_flags |= PSTRING_LENGTH_INCLUDES_ITSELF; 1790277592Sdelphij break; 1791277592Sdelphij default: 1792277592Sdelphij bad: 1793277592Sdelphij if (ms->flags & MAGIC_CHECK) 1794277592Sdelphij file_magwarn(ms, "string modifier `%c' " 1795277592Sdelphij "invalid", *l); 1796277592Sdelphij goto out; 1797277592Sdelphij } 1798277592Sdelphij /* allow multiple '/' for readability */ 1799277592Sdelphij if (l[1] == '/' && !isspace((unsigned char)l[2])) 1800277592Sdelphij l++; 1801277592Sdelphij } 1802277592Sdelphij if (string_modifier_check(ms, m) == -1) 1803277592Sdelphij goto out; 1804277592Sdelphij *lp = l; 1805277592Sdelphij return 0; 1806277592Sdelphijout: 1807277592Sdelphij *lp = l; 1808277592Sdelphij return -1; 1809277592Sdelphij} 1810277592Sdelphij 181168349Sobrien/* 181268349Sobrien * parse one line from magic file, put into magic[index++] if valid 181368349Sobrien */ 1814133359Sobrienprivate int 1815267843Sdelphijparse(struct magic_set *ms, struct magic_entry *me, const char *line, 1816267843Sdelphij size_t lineno, int action) 181768349Sobrien{ 1818169962Sobrien#ifdef ENABLE_CONDITIONALS 1819169962Sobrien static uint32_t last_cont_level = 0; 1820169962Sobrien#endif 1821169942Sobrien size_t i; 182268349Sobrien struct magic *m; 1823159764Sobrien const char *l = line; 182484685Sobrien char *t; 1825169962Sobrien int op; 1826159825Sobrien uint32_t cont_level; 1827267843Sdelphij int32_t diff; 182868349Sobrien 1829159764Sobrien cont_level = 0; 183068349Sobrien 1831267843Sdelphij /* 1832267843Sdelphij * Parse the offset. 1833267843Sdelphij */ 183468349Sobrien while (*l == '>') { 183568349Sobrien ++l; /* step over */ 1836159764Sobrien cont_level++; 183768349Sobrien } 1838169962Sobrien#ifdef ENABLE_CONDITIONALS 1839169962Sobrien if (cont_level == 0 || cont_level > last_cont_level) 1840169962Sobrien if (file_check_mem(ms, cont_level) == -1) 1841169962Sobrien return -1; 1842169962Sobrien last_cont_level = cont_level; 1843169962Sobrien#endif 1844159764Sobrien if (cont_level != 0) { 1845267843Sdelphij if (me->mp == NULL) { 1846267843Sdelphij file_magerror(ms, "No current entry for continuation"); 1847159764Sobrien return -1; 1848159764Sobrien } 1849267843Sdelphij if (me->cont_count == 0) { 1850267843Sdelphij file_magerror(ms, "Continuations present with 0 count"); 1851267843Sdelphij return -1; 1852267843Sdelphij } 1853267843Sdelphij m = &me->mp[me->cont_count - 1]; 1854267843Sdelphij diff = (int32_t)cont_level - (int32_t)m->cont_level; 1855267843Sdelphij if (diff > 1) 1856267843Sdelphij file_magwarn(ms, "New continuation level %u is more " 1857267843Sdelphij "than one larger than current level %u", cont_level, 1858267843Sdelphij m->cont_level); 1859159764Sobrien if (me->cont_count == me->max_count) { 1860159764Sobrien struct magic *nm; 1861159764Sobrien size_t cnt = me->max_count + ALLOC_CHUNK; 1862186690Sobrien if ((nm = CAST(struct magic *, realloc(me->mp, 1863186690Sobrien sizeof(*nm) * cnt))) == NULL) { 1864169942Sobrien file_oomem(ms, sizeof(*nm) * cnt); 1865159764Sobrien return -1; 1866159764Sobrien } 1867159764Sobrien me->mp = m = nm; 1868226048Sobrien me->max_count = CAST(uint32_t, cnt); 1869159764Sobrien } 1870159764Sobrien m = &me->mp[me->cont_count++]; 1871169962Sobrien (void)memset(m, 0, sizeof(*m)); 1872159764Sobrien m->cont_level = cont_level; 1873159764Sobrien } else { 1874267843Sdelphij static const size_t len = sizeof(*m) * ALLOC_CHUNK; 1875267843Sdelphij if (me->mp != NULL) 1876267843Sdelphij return 1; 1877267843Sdelphij if ((m = CAST(struct magic *, malloc(len))) == NULL) { 1878267843Sdelphij file_oomem(ms, len); 1879267843Sdelphij return -1; 1880159764Sobrien } 1881267843Sdelphij me->mp = m; 1882267843Sdelphij me->max_count = ALLOC_CHUNK; 1883169962Sobrien (void)memset(m, 0, sizeof(*m)); 1884186690Sobrien m->factor_op = FILE_FACTOR_OP_NONE; 1885159764Sobrien m->cont_level = 0; 1886159764Sobrien me->cont_count = 1; 1887159764Sobrien } 1888226048Sobrien m->lineno = CAST(uint32_t, lineno); 1889159764Sobrien 1890169962Sobrien if (*l == '&') { /* m->cont_level == 0 checked below. */ 1891159764Sobrien ++l; /* step over */ 1892159764Sobrien m->flag |= OFFADD; 1893159764Sobrien } 1894169962Sobrien if (*l == '(') { 189568349Sobrien ++l; /* step over */ 189668349Sobrien m->flag |= INDIR; 1897159764Sobrien if (m->flag & OFFADD) 1898159764Sobrien m->flag = (m->flag & ~OFFADD) | INDIROFFADD; 1899169962Sobrien 1900169962Sobrien if (*l == '&') { /* m->cont_level == 0 checked below */ 1901169962Sobrien ++l; /* step over */ 1902169962Sobrien m->flag |= OFFADD; 1903169962Sobrien } 190468349Sobrien } 1905169962Sobrien /* Indirect offsets are not valid at level 0. */ 1906284778Sdelphij if (m->cont_level == 0 && (m->flag & (OFFADD | INDIROFFADD))) { 1907169962Sobrien if (ms->flags & MAGIC_CHECK) 1908169962Sobrien file_magwarn(ms, "relative offset at level 0"); 1909284778Sdelphij return -1; 1910284778Sdelphij } 191168349Sobrien 191268349Sobrien /* get offset, then skip over it */ 1913133359Sobrien m->offset = (uint32_t)strtoul(l, &t, 0); 1914284778Sdelphij if (l == t) { 1915133359Sobrien if (ms->flags & MAGIC_CHECK) 1916139368Sobrien file_magwarn(ms, "offset `%s' invalid", l); 1917284778Sdelphij return -1; 1918284778Sdelphij } 191968349Sobrien l = t; 192068349Sobrien 192168349Sobrien if (m->flag & INDIR) { 1922133359Sobrien m->in_type = FILE_LONG; 192374784Sobrien m->in_offset = 0; 1924330569Sgordon m->in_op = 0; 192568349Sobrien /* 1926330569Sgordon * read [.,lbs][+-]nnnnn) 192768349Sobrien */ 1928330569Sgordon if (*l == '.' || *l == ',') { 1929330569Sgordon if (*l == ',') 1930330569Sgordon m->in_op |= FILE_OPSIGNED; 193168349Sobrien l++; 193268349Sobrien switch (*l) { 193368349Sobrien case 'l': 1934133359Sobrien m->in_type = FILE_LELONG; 193568349Sobrien break; 193668349Sobrien case 'L': 1937133359Sobrien m->in_type = FILE_BELONG; 193868349Sobrien break; 1939159764Sobrien case 'm': 1940159764Sobrien m->in_type = FILE_MELONG; 1941159764Sobrien break; 194268349Sobrien case 'h': 194368349Sobrien case 's': 1944133359Sobrien m->in_type = FILE_LESHORT; 194568349Sobrien break; 194668349Sobrien case 'H': 194768349Sobrien case 'S': 1948133359Sobrien m->in_type = FILE_BESHORT; 194968349Sobrien break; 195068349Sobrien case 'c': 195168349Sobrien case 'b': 195268349Sobrien case 'C': 195368349Sobrien case 'B': 1954133359Sobrien m->in_type = FILE_BYTE; 195568349Sobrien break; 1956175296Sobrien case 'e': 1957175296Sobrien case 'f': 1958175296Sobrien case 'g': 1959175296Sobrien m->in_type = FILE_LEDOUBLE; 1960175296Sobrien break; 1961175296Sobrien case 'E': 1962175296Sobrien case 'F': 1963175296Sobrien case 'G': 1964175296Sobrien m->in_type = FILE_BEDOUBLE; 1965175296Sobrien break; 1966191736Sobrien case 'i': 1967191736Sobrien m->in_type = FILE_LEID3; 1968191736Sobrien break; 1969191736Sobrien case 'I': 1970191736Sobrien m->in_type = FILE_BEID3; 1971191736Sobrien break; 197268349Sobrien default: 1973133359Sobrien if (ms->flags & MAGIC_CHECK) 1974139368Sobrien file_magwarn(ms, 1975139368Sobrien "indirect offset type `%c' invalid", 1976133359Sobrien *l); 1977284778Sdelphij return -1; 197868349Sobrien } 197968349Sobrien l++; 198068349Sobrien } 1981169962Sobrien 198280588Sobrien if (*l == '~') { 1983159764Sobrien m->in_op |= FILE_OPINVERSE; 198480588Sobrien l++; 198580588Sobrien } 1986169962Sobrien if ((op = get_op(*l)) != -1) { 1987169962Sobrien m->in_op |= op; 198880588Sobrien l++; 198980588Sobrien } 1990159764Sobrien if (*l == '(') { 1991159764Sobrien m->in_op |= FILE_OPINDIRECT; 1992159764Sobrien l++; 1993159764Sobrien } 1994159764Sobrien if (isdigit((unsigned char)*l) || *l == '-') { 1995159764Sobrien m->in_offset = (int32_t)strtol(l, &t, 0); 1996284778Sdelphij if (l == t) { 1997169962Sobrien if (ms->flags & MAGIC_CHECK) 1998169962Sobrien file_magwarn(ms, 1999169962Sobrien "in_offset `%s' invalid", l); 2000284778Sdelphij return -1; 2001284778Sdelphij } 2002159764Sobrien l = t; 2003159764Sobrien } 2004159764Sobrien if (*l++ != ')' || 2005284778Sdelphij ((m->in_op & FILE_OPINDIRECT) && *l++ != ')')) { 2006133359Sobrien if (ms->flags & MAGIC_CHECK) 2007139368Sobrien file_magwarn(ms, 2008139368Sobrien "missing ')' in indirect offset"); 2009284778Sdelphij return -1; 2010284778Sdelphij } 201168349Sobrien } 2012169962Sobrien EATAB; 201368349Sobrien 2014169962Sobrien#ifdef ENABLE_CONDITIONALS 2015169962Sobrien m->cond = get_cond(l, &l); 2016169962Sobrien if (check_cond(ms, m->cond, cont_level) == -1) 2017169962Sobrien return -1; 201868349Sobrien 201968349Sobrien EATAB; 2020169962Sobrien#endif 202168349Sobrien 2022267843Sdelphij /* 2023267843Sdelphij * Parse the type. 2024267843Sdelphij */ 202568349Sobrien if (*l == 'u') { 2026267843Sdelphij /* 2027267843Sdelphij * Try it as a keyword type prefixed by "u"; match what 2028267843Sdelphij * follows the "u". If that fails, try it as an SUS 2029267843Sdelphij * integer type. 2030267843Sdelphij */ 2031267843Sdelphij m->type = get_type(type_tbl, l + 1, &l); 2032267843Sdelphij if (m->type == FILE_INVALID) { 2033267843Sdelphij /* 2034267843Sdelphij * Not a keyword type; parse it as an SUS type, 2035267843Sdelphij * 'u' possibly followed by a number or C/S/L. 2036267843Sdelphij */ 2037267843Sdelphij m->type = get_standard_integer_type(l, &l); 2038267843Sdelphij } 2039267843Sdelphij /* It's unsigned. */ 2040267843Sdelphij if (m->type != FILE_INVALID) 2041267843Sdelphij m->flag |= UNSIGNED; 2042267843Sdelphij } else { 2043267843Sdelphij /* 2044267843Sdelphij * Try it as a keyword type. If that fails, try it as 2045267843Sdelphij * an SUS integer type if it begins with "d" or as an 2046267843Sdelphij * SUS string type if it begins with "s". In any case, 2047267843Sdelphij * it's not unsigned. 2048267843Sdelphij */ 2049267843Sdelphij m->type = get_type(type_tbl, l, &l); 2050267843Sdelphij if (m->type == FILE_INVALID) { 2051267843Sdelphij /* 2052267843Sdelphij * Not a keyword type; parse it as an SUS type, 2053267843Sdelphij * either 'd' possibly followed by a number or 2054267843Sdelphij * C/S/L, or just 's'. 2055267843Sdelphij */ 2056267843Sdelphij if (*l == 'd') 2057267843Sdelphij m->type = get_standard_integer_type(l, &l); 2058267843Sdelphij else if (*l == 's' && !isalpha((unsigned char)l[1])) { 2059267843Sdelphij m->type = FILE_STRING; 2060267843Sdelphij ++l; 2061267843Sdelphij } 2062267843Sdelphij } 206368349Sobrien } 206468349Sobrien 2065169962Sobrien if (m->type == FILE_INVALID) { 2066267843Sdelphij /* Not found - try it as a special keyword. */ 2067267843Sdelphij m->type = get_type(special_tbl, l, &l); 2068267843Sdelphij } 2069267843Sdelphij 2070267843Sdelphij if (m->type == FILE_INVALID) { 2071133359Sobrien if (ms->flags & MAGIC_CHECK) 2072139368Sobrien file_magwarn(ms, "type `%s' invalid", l); 207368349Sobrien return -1; 207468349Sobrien } 2075169962Sobrien 207668349Sobrien /* New-style anding: "0 byte&0x80 =0x80 dynamically linked" */ 207780588Sobrien /* New and improved: ~ & | ^ + - * / % -- exciting, isn't it? */ 2078169962Sobrien 2079169962Sobrien m->mask_op = 0; 208080588Sobrien if (*l == '~') { 2081139368Sobrien if (!IS_STRING(m->type)) 2082159764Sobrien m->mask_op |= FILE_OPINVERSE; 2083169962Sobrien else if (ms->flags & MAGIC_CHECK) 2084169962Sobrien file_magwarn(ms, "'~' invalid for string types"); 208568349Sobrien ++l; 208680588Sobrien } 2087186690Sobrien m->str_range = 0; 2088226048Sobrien m->str_flags = m->type == FILE_PSTRING ? PSTRING_1_LE : 0; 2089169962Sobrien if ((op = get_op(*l)) != -1) { 2090277592Sdelphij if (IS_STRING(m->type)) { 2091277592Sdelphij int r; 2092277592Sdelphij 2093277592Sdelphij if (op != FILE_OPDIVIDE) { 2094277592Sdelphij if (ms->flags & MAGIC_CHECK) 2095277592Sdelphij file_magwarn(ms, 2096277592Sdelphij "invalid string/indirect op: " 2097277592Sdelphij "`%c'", *t); 2098277592Sdelphij return -1; 209968349Sobrien } 2100277592Sdelphij 2101277592Sdelphij if (m->type == FILE_INDIRECT) 2102277592Sdelphij r = parse_indirect_modifier(ms, m, &l); 2103277592Sdelphij else 2104277592Sdelphij r = parse_string_modifier(ms, m, &l); 2105277592Sdelphij if (r == -1) 2106169962Sobrien return -1; 2107277592Sdelphij } else 2108277592Sdelphij parse_op_modifier(ms, m, &l, op); 210980588Sobrien } 2110277592Sdelphij 2111133359Sobrien /* 2112133359Sobrien * We used to set mask to all 1's here, instead let's just not do 2113133359Sobrien * anything if mask = 0 (unless you have a better idea) 2114133359Sobrien */ 211568349Sobrien EATAB; 211668349Sobrien 211768349Sobrien switch (*l) { 211868349Sobrien case '>': 211968349Sobrien case '<': 2120186690Sobrien m->reln = *l; 2121186690Sobrien ++l; 2122186690Sobrien if (*l == '=') { 2123186690Sobrien if (ms->flags & MAGIC_CHECK) { 2124186690Sobrien file_magwarn(ms, "%c= not supported", 2125186690Sobrien m->reln); 2126186690Sobrien return -1; 2127186690Sobrien } 2128186690Sobrien ++l; 2129186690Sobrien } 2130186690Sobrien break; 213168349Sobrien /* Old-style anding: "0 byte &0x80 dynamically linked" */ 213268349Sobrien case '&': 213368349Sobrien case '^': 213468349Sobrien case '=': 213568349Sobrien m->reln = *l; 213668349Sobrien ++l; 213768349Sobrien if (*l == '=') { 213868349Sobrien /* HP compat: ignore &= etc. */ 213968349Sobrien ++l; 214068349Sobrien } 214168349Sobrien break; 214268349Sobrien case '!': 2143159764Sobrien m->reln = *l; 2144159764Sobrien ++l; 2145159764Sobrien break; 214668349Sobrien default: 2147169962Sobrien m->reln = '='; /* the default relation */ 2148159764Sobrien if (*l == 'x' && ((isascii((unsigned char)l[1]) && 2149159764Sobrien isspace((unsigned char)l[1])) || !l[1])) { 215068349Sobrien m->reln = *l; 215168349Sobrien ++l; 215268349Sobrien } 215368349Sobrien break; 215468349Sobrien } 2155169962Sobrien /* 2156169962Sobrien * Grab the value part, except for an 'x' reln. 2157169962Sobrien */ 2158169962Sobrien if (m->reln != 'x' && getvalue(ms, m, &l, action)) 215968349Sobrien return -1; 2160169962Sobrien 216168349Sobrien /* 216268349Sobrien * TODO finish this macro and start using it! 2163330569Sgordon * #define offsetcheck {if (offset > ms->bytes_max -1) 216468349Sobrien * magwarn("offset too big"); } 216568349Sobrien */ 216668349Sobrien 216768349Sobrien /* 2168169962Sobrien * Now get last part - the description 216968349Sobrien */ 217068349Sobrien EATAB; 217168349Sobrien if (l[0] == '\b') { 217268349Sobrien ++l; 2173186690Sobrien m->flag |= NOSPACE; 217468349Sobrien } else if ((l[0] == '\\') && (l[1] == 'b')) { 217568349Sobrien ++l; 217668349Sobrien ++l; 2177186690Sobrien m->flag |= NOSPACE; 2178186690Sobrien } 2179169942Sobrien for (i = 0; (m->desc[i++] = *l++) != '\0' && i < sizeof(m->desc); ) 2180169942Sobrien continue; 2181169942Sobrien if (i == sizeof(m->desc)) { 2182169942Sobrien m->desc[sizeof(m->desc) - 1] = '\0'; 2183169942Sobrien if (ms->flags & MAGIC_CHECK) 2184169942Sobrien file_magwarn(ms, "description `%s' truncated", m->desc); 2185169942Sobrien } 218668349Sobrien 2187169942Sobrien /* 2188169942Sobrien * We only do this check while compiling, or if any of the magic 2189169942Sobrien * files were not compiled. 2190169942Sobrien */ 2191169942Sobrien if (ms->flags & MAGIC_CHECK) { 2192169942Sobrien if (check_format(ms, m) == -1) 2193133359Sobrien return -1; 2194133359Sobrien } 2195103373Sobrien#ifndef COMPILE_ONLY 2196133359Sobrien if (action == FILE_CHECK) { 2197133359Sobrien file_mdump(m); 219868349Sobrien } 2199103373Sobrien#endif 2200186690Sobrien m->mimetype[0] = '\0'; /* initialise MIME type to none */ 220168349Sobrien return 0; 220268349Sobrien} 220368349Sobrien 2204186690Sobrien/* 2205186690Sobrien * parse a STRENGTH annotation line from magic file, put into magic[index - 1] 2206186690Sobrien * if valid 2207186690Sobrien */ 2208169942Sobrienprivate int 2209186690Sobrienparse_strength(struct magic_set *ms, struct magic_entry *me, const char *line) 2210186690Sobrien{ 2211186690Sobrien const char *l = line; 2212186690Sobrien char *el; 2213186690Sobrien unsigned long factor; 2214186690Sobrien struct magic *m = &me->mp[0]; 2215186690Sobrien 2216186690Sobrien if (m->factor_op != FILE_FACTOR_OP_NONE) { 2217186690Sobrien file_magwarn(ms, 2218186690Sobrien "Current entry already has a strength type: %c %d", 2219186690Sobrien m->factor_op, m->factor); 2220186690Sobrien return -1; 2221186690Sobrien } 2222267843Sdelphij if (m->type == FILE_NAME) { 2223267843Sdelphij file_magwarn(ms, "%s: Strength setting is not supported in " 2224267843Sdelphij "\"name\" magic entries", m->value.s); 2225267843Sdelphij return -1; 2226267843Sdelphij } 2227186690Sobrien EATAB; 2228186690Sobrien switch (*l) { 2229186690Sobrien case FILE_FACTOR_OP_NONE: 2230186690Sobrien case FILE_FACTOR_OP_PLUS: 2231186690Sobrien case FILE_FACTOR_OP_MINUS: 2232186690Sobrien case FILE_FACTOR_OP_TIMES: 2233186690Sobrien case FILE_FACTOR_OP_DIV: 2234186690Sobrien m->factor_op = *l++; 2235186690Sobrien break; 2236186690Sobrien default: 2237186690Sobrien file_magwarn(ms, "Unknown factor op `%c'", *l); 2238186690Sobrien return -1; 2239186690Sobrien } 2240186690Sobrien EATAB; 2241186690Sobrien factor = strtoul(l, &el, 0); 2242186690Sobrien if (factor > 255) { 2243186690Sobrien file_magwarn(ms, "Too large factor `%lu'", factor); 2244186690Sobrien goto out; 2245186690Sobrien } 2246186690Sobrien if (*el && !isspace((unsigned char)*el)) { 2247186690Sobrien file_magwarn(ms, "Bad factor `%s'", l); 2248186690Sobrien goto out; 2249186690Sobrien } 2250186690Sobrien m->factor = (uint8_t)factor; 2251186690Sobrien if (m->factor == 0 && m->factor_op == FILE_FACTOR_OP_DIV) { 2252186690Sobrien file_magwarn(ms, "Cannot have factor op `%c' and factor %u", 2253186690Sobrien m->factor_op, m->factor); 2254186690Sobrien goto out; 2255186690Sobrien } 2256186690Sobrien return 0; 2257186690Sobrienout: 2258186690Sobrien m->factor_op = FILE_FACTOR_OP_NONE; 2259186690Sobrien m->factor = 0; 2260186690Sobrien return -1; 2261186690Sobrien} 2262186690Sobrien 2263191736Sobrienprivate int 2264276415Sdelphijgoodchar(unsigned char x, const char *extra) 2265276415Sdelphij{ 2266276415Sdelphij return (isascii(x) && isalnum(x)) || strchr(extra, x); 2267276415Sdelphij} 2268276415Sdelphij 2269276415Sdelphijprivate int 2270267843Sdelphijparse_extra(struct magic_set *ms, struct magic_entry *me, const char *line, 2271276415Sdelphij off_t off, size_t len, const char *name, const char *extra, int nt) 2272191736Sobrien{ 2273191736Sobrien size_t i; 2274191736Sobrien const char *l = line; 2275191736Sobrien struct magic *m = &me->mp[me->cont_count == 0 ? 0 : me->cont_count - 1]; 2276284778Sdelphij char *buf = CAST(char *, CAST(void *, m)) + off; 2277191736Sobrien 2278267843Sdelphij if (buf[0] != '\0') { 2279267843Sdelphij len = nt ? strlen(buf) : len; 2280267843Sdelphij file_magwarn(ms, "Current entry already has a %s type " 2281267843Sdelphij "`%.*s', new type `%s'", name, (int)len, buf, l); 2282191736Sobrien return -1; 2283191736Sobrien } 2284191736Sobrien 2285267843Sdelphij if (*m->desc == '\0') { 2286267843Sdelphij file_magwarn(ms, "Current entry does not yet have a " 2287267843Sdelphij "description for adding a %s type", name); 2288267843Sdelphij return -1; 2289267843Sdelphij } 2290267843Sdelphij 2291191736Sobrien EATAB; 2292276415Sdelphij for (i = 0; *l && i < len && goodchar(*l, extra); buf[i++] = *l++) 2293191736Sobrien continue; 2294267843Sdelphij 2295267843Sdelphij if (i == len && *l) { 2296267843Sdelphij if (nt) 2297267843Sdelphij buf[len - 1] = '\0'; 2298191736Sobrien if (ms->flags & MAGIC_CHECK) 2299267843Sdelphij file_magwarn(ms, "%s type `%s' truncated %" 2300267843Sdelphij SIZE_T_FORMAT "u", name, line, i); 2301267843Sdelphij } else { 2302276415Sdelphij if (!isspace((unsigned char)*l) && !goodchar(*l, extra)) 2303276415Sdelphij file_magwarn(ms, "%s type `%s' has bad char '%c'", 2304276415Sdelphij name, line, *l); 2305267843Sdelphij if (nt) 2306267843Sdelphij buf[i] = '\0'; 2307191736Sobrien } 2308191736Sobrien 2309191736Sobrien if (i > 0) 2310191736Sobrien return 0; 2311276415Sdelphij 2312276415Sdelphij file_magerror(ms, "Bad magic entry '%s'", line); 2313276415Sdelphij return -1; 2314191736Sobrien} 2315191736Sobrien 2316191736Sobrien/* 2317267843Sdelphij * Parse an Apple CREATOR/TYPE annotation from magic file and put it into 2318267843Sdelphij * magic[index - 1] 2319267843Sdelphij */ 2320267843Sdelphijprivate int 2321267843Sdelphijparse_apple(struct magic_set *ms, struct magic_entry *me, const char *line) 2322267843Sdelphij{ 2323267843Sdelphij struct magic *m = &me->mp[0]; 2324267843Sdelphij 2325284778Sdelphij return parse_extra(ms, me, line, 2326284778Sdelphij CAST(off_t, offsetof(struct magic, apple)), 2327330569Sgordon sizeof(m->apple), "APPLE", "!+-./?", 0); 2328267843Sdelphij} 2329267843Sdelphij 2330267843Sdelphij/* 2331284778Sdelphij * Parse a comma-separated list of extensions 2332284778Sdelphij */ 2333284778Sdelphijprivate int 2334284778Sdelphijparse_ext(struct magic_set *ms, struct magic_entry *me, const char *line) 2335284778Sdelphij{ 2336284778Sdelphij struct magic *m = &me->mp[0]; 2337284778Sdelphij 2338284778Sdelphij return parse_extra(ms, me, line, 2339284778Sdelphij CAST(off_t, offsetof(struct magic, ext)), 2340330569Sgordon sizeof(m->ext), "EXTENSION", ",!+-/@", 0); 2341284778Sdelphij} 2342284778Sdelphij 2343284778Sdelphij/* 2344186690Sobrien * parse a MIME annotation line from magic file, put into magic[index - 1] 2345186690Sobrien * if valid 2346186690Sobrien */ 2347186690Sobrienprivate int 2348186690Sobrienparse_mime(struct magic_set *ms, struct magic_entry *me, const char *line) 2349186690Sobrien{ 2350267843Sdelphij struct magic *m = &me->mp[0]; 2351186690Sobrien 2352284778Sdelphij return parse_extra(ms, me, line, 2353284778Sdelphij CAST(off_t, offsetof(struct magic, mimetype)), 2354276415Sdelphij sizeof(m->mimetype), "MIME", "+-/.", 1); 2355186690Sobrien} 2356186690Sobrien 2357186690Sobrienprivate int 2358330569Sgordoncheck_format_type(const char *ptr, int type, const char **estr) 2359169942Sobrien{ 2360267843Sdelphij int quad = 0, h; 2361330569Sgordon size_t len, cnt; 2362169942Sobrien if (*ptr == '\0') { 2363169942Sobrien /* Missing format string; bad */ 2364330569Sgordon *estr = "missing format spec"; 2365169942Sobrien return -1; 2366169942Sobrien } 2367169942Sobrien 2368267843Sdelphij switch (file_formats[type]) { 2369169942Sobrien case FILE_FMT_QUAD: 2370169942Sobrien quad = 1; 2371169942Sobrien /*FALLTHROUGH*/ 2372169942Sobrien case FILE_FMT_NUM: 2373267843Sdelphij if (quad == 0) { 2374267843Sdelphij switch (type) { 2375267843Sdelphij case FILE_BYTE: 2376267843Sdelphij h = 2; 2377267843Sdelphij break; 2378267843Sdelphij case FILE_SHORT: 2379267843Sdelphij case FILE_BESHORT: 2380267843Sdelphij case FILE_LESHORT: 2381267843Sdelphij h = 1; 2382267843Sdelphij break; 2383267843Sdelphij case FILE_LONG: 2384267843Sdelphij case FILE_BELONG: 2385267843Sdelphij case FILE_LELONG: 2386267843Sdelphij case FILE_MELONG: 2387267843Sdelphij case FILE_LEID3: 2388267843Sdelphij case FILE_BEID3: 2389267843Sdelphij case FILE_INDIRECT: 2390267843Sdelphij h = 0; 2391267843Sdelphij break; 2392267843Sdelphij default: 2393267843Sdelphij abort(); 2394267843Sdelphij } 2395267843Sdelphij } else 2396267843Sdelphij h = 0; 2397169942Sobrien if (*ptr == '-') 2398169942Sobrien ptr++; 2399169942Sobrien if (*ptr == '.') 2400169942Sobrien ptr++; 2401330569Sgordon if (*ptr == '#') 2402330569Sgordon ptr++; 2403330569Sgordon#define CHECKLEN() do { \ 2404330569Sgordon for (len = cnt = 0; isdigit((unsigned char)*ptr); ptr++, cnt++) \ 2405330569Sgordon len = len * 10 + (*ptr - '0'); \ 2406330569Sgordon if (cnt > 5 || len > 1024) \ 2407330569Sgordon goto toolong; \ 2408330569Sgordon} while (/*CONSTCOND*/0) 2409330569Sgordon 2410330569Sgordon CHECKLEN(); 2411169942Sobrien if (*ptr == '.') 2412169942Sobrien ptr++; 2413330569Sgordon CHECKLEN(); 2414169942Sobrien if (quad) { 2415169942Sobrien if (*ptr++ != 'l') 2416330569Sgordon goto invalid; 2417169942Sobrien if (*ptr++ != 'l') 2418330569Sgordon goto invalid; 2419169942Sobrien } 2420169942Sobrien 2421169942Sobrien switch (*ptr++) { 2422267843Sdelphij#ifdef STRICT_FORMAT /* "long" formats are int formats for us */ 2423267843Sdelphij /* so don't accept the 'l' modifier */ 2424169942Sobrien case 'l': 2425169942Sobrien switch (*ptr++) { 2426169942Sobrien case 'i': 2427169942Sobrien case 'd': 2428169942Sobrien case 'u': 2429267843Sdelphij case 'o': 2430169942Sobrien case 'x': 2431169942Sobrien case 'X': 2432330569Sgordon if (h == 0) 2433330569Sgordon return 0; 2434330569Sgordon /*FALLTHROUGH*/ 2435169942Sobrien default: 2436330569Sgordon goto invalid; 2437169942Sobrien } 2438169942Sobrien 2439267843Sdelphij /* 2440267843Sdelphij * Don't accept h and hh modifiers. They make writing 2441267843Sdelphij * magic entries more complicated, for very little benefit 2442267843Sdelphij */ 2443169942Sobrien case 'h': 2444267843Sdelphij if (h-- <= 0) 2445330569Sgordon goto invalid; 2446169942Sobrien switch (*ptr++) { 2447169942Sobrien case 'h': 2448267843Sdelphij if (h-- <= 0) 2449330569Sgordon goto invalid; 2450169942Sobrien switch (*ptr++) { 2451169942Sobrien case 'i': 2452169942Sobrien case 'd': 2453169942Sobrien case 'u': 2454267843Sdelphij case 'o': 2455169942Sobrien case 'x': 2456169942Sobrien case 'X': 2457169942Sobrien return 0; 2458169942Sobrien default: 2459330569Sgordon goto invalid; 2460169942Sobrien } 2461267843Sdelphij case 'i': 2462169942Sobrien case 'd': 2463267843Sdelphij case 'u': 2464267843Sdelphij case 'o': 2465267843Sdelphij case 'x': 2466267843Sdelphij case 'X': 2467330569Sgordon if (h == 0) 2468330569Sgordon return 0; 2469330569Sgordon /*FALLTHROUGH*/ 2470169942Sobrien default: 2471330569Sgordon goto invalid; 2472169942Sobrien } 2473267843Sdelphij#endif 2474267843Sdelphij case 'c': 2475330569Sgordon if (h == 2) 2476330569Sgordon return 0; 2477330569Sgordon goto invalid; 2478169942Sobrien case 'i': 2479169942Sobrien case 'd': 2480169942Sobrien case 'u': 2481267843Sdelphij case 'o': 2482169942Sobrien case 'x': 2483169942Sobrien case 'X': 2484267843Sdelphij#ifdef STRICT_FORMAT 2485330569Sgordon if (h == 0) 2486330569Sgordon return 0; 2487330569Sgordon /*FALLTHROUGH*/ 2488267843Sdelphij#else 2489169942Sobrien return 0; 2490267843Sdelphij#endif 2491169942Sobrien default: 2492330569Sgordon goto invalid; 2493169942Sobrien } 2494169942Sobrien 2495175296Sobrien case FILE_FMT_FLOAT: 2496175296Sobrien case FILE_FMT_DOUBLE: 2497175296Sobrien if (*ptr == '-') 2498175296Sobrien ptr++; 2499175296Sobrien if (*ptr == '.') 2500175296Sobrien ptr++; 2501330569Sgordon CHECKLEN(); 2502175296Sobrien if (*ptr == '.') 2503175296Sobrien ptr++; 2504330569Sgordon CHECKLEN(); 2505175296Sobrien switch (*ptr++) { 2506175296Sobrien case 'e': 2507175296Sobrien case 'E': 2508175296Sobrien case 'f': 2509175296Sobrien case 'F': 2510175296Sobrien case 'g': 2511175296Sobrien case 'G': 2512175296Sobrien return 0; 2513175296Sobrien 2514175296Sobrien default: 2515330569Sgordon goto invalid; 2516175296Sobrien } 2517175296Sobrien 2518175296Sobrien 2519169942Sobrien case FILE_FMT_STR: 2520169942Sobrien if (*ptr == '-') 2521169942Sobrien ptr++; 2522169942Sobrien while (isdigit((unsigned char )*ptr)) 2523169942Sobrien ptr++; 2524169942Sobrien if (*ptr == '.') { 2525169942Sobrien ptr++; 2526169942Sobrien while (isdigit((unsigned char )*ptr)) 2527169942Sobrien ptr++; 2528169942Sobrien } 2529169942Sobrien 2530169942Sobrien switch (*ptr++) { 2531169942Sobrien case 's': 2532169942Sobrien return 0; 2533169942Sobrien default: 2534330569Sgordon goto invalid; 2535169942Sobrien } 2536169942Sobrien 2537169942Sobrien default: 2538169942Sobrien /* internal error */ 2539169942Sobrien abort(); 2540169942Sobrien } 2541330569Sgordoninvalid: 2542330569Sgordon *estr = "not valid"; 2543330569Sgordontoolong: 2544330569Sgordon *estr = "too long"; 2545169942Sobrien return -1; 2546169942Sobrien} 2547169942Sobrien 2548133359Sobrien/* 2549133359Sobrien * Check that the optional printf format in description matches 2550133359Sobrien * the type of the magic. 2551133359Sobrien */ 2552133359Sobrienprivate int 2553139368Sobriencheck_format(struct magic_set *ms, struct magic *m) 2554133359Sobrien{ 2555133359Sobrien char *ptr; 2556330569Sgordon const char *estr; 2557133359Sobrien 2558133359Sobrien for (ptr = m->desc; *ptr; ptr++) 2559133359Sobrien if (*ptr == '%') 2560133359Sobrien break; 2561133359Sobrien if (*ptr == '\0') { 2562133359Sobrien /* No format string; ok */ 2563133359Sobrien return 1; 2564133359Sobrien } 2565169942Sobrien 2566169942Sobrien assert(file_nformats == file_nnames); 2567169942Sobrien 2568169942Sobrien if (m->type >= file_nformats) { 2569186690Sobrien file_magwarn(ms, "Internal error inconsistency between " 2570169942Sobrien "m->type and format strings"); 2571169942Sobrien return -1; 2572133359Sobrien } 2573169942Sobrien if (file_formats[m->type] == FILE_FMT_NONE) { 2574186690Sobrien file_magwarn(ms, "No format string for `%s' with description " 2575169942Sobrien "`%s'", m->desc, file_names[m->type]); 2576169942Sobrien return -1; 2577133359Sobrien } 2578169942Sobrien 2579169942Sobrien ptr++; 2580330569Sgordon if (check_format_type(ptr, m->type, &estr) == -1) { 2581169942Sobrien /* 2582169942Sobrien * TODO: this error message is unhelpful if the format 2583169942Sobrien * string is not one character long 2584169942Sobrien */ 2585330569Sgordon file_magwarn(ms, "Printf format is %s for type " 2586330569Sgordon "`%s' in description `%s'", estr, 2587169942Sobrien file_names[m->type], m->desc); 2588169942Sobrien return -1; 2589169942Sobrien } 2590169942Sobrien 2591133359Sobrien for (; *ptr; ptr++) { 2592169942Sobrien if (*ptr == '%') { 2593186690Sobrien file_magwarn(ms, 2594169942Sobrien "Too many format strings (should have at most one) " 2595169942Sobrien "for `%s' with description `%s'", 2596169942Sobrien file_names[m->type], m->desc); 2597169942Sobrien return -1; 2598133359Sobrien } 2599133359Sobrien } 2600169942Sobrien return 0; 2601133359Sobrien} 2602133359Sobrien 260368349Sobrien/* 260468349Sobrien * Read a numeric value from a pointer, into the value union of a magic 260568349Sobrien * pointer, according to the magic type. Update the string pointer to point 260668349Sobrien * just after the number read. Return 0 for success, non-zero for failure. 260768349Sobrien */ 2608133359Sobrienprivate int 2609169962Sobriengetvalue(struct magic_set *ms, struct magic *m, const char **p, int action) 261068349Sobrien{ 2611133359Sobrien switch (m->type) { 2612139368Sobrien case FILE_BESTRING16: 2613139368Sobrien case FILE_LESTRING16: 2614133359Sobrien case FILE_STRING: 2615133359Sobrien case FILE_PSTRING: 2616133359Sobrien case FILE_REGEX: 2617159764Sobrien case FILE_SEARCH: 2618267843Sdelphij case FILE_NAME: 2619267843Sdelphij case FILE_USE: 2620330569Sgordon case FILE_DER: 2621192348Sdelphij *p = getstr(ms, m, *p, action == FILE_COMPILE); 2622133359Sobrien if (*p == NULL) { 2623133359Sobrien if (ms->flags & MAGIC_CHECK) 2624139368Sobrien file_magwarn(ms, "cannot get string from `%s'", 2625133359Sobrien m->value.s); 2626133359Sobrien return -1; 2627133359Sobrien } 2628267843Sdelphij if (m->type == FILE_REGEX) { 2629267843Sdelphij file_regex_t rx; 2630267843Sdelphij int rc = file_regcomp(&rx, m->value.s, REG_EXTENDED); 2631267843Sdelphij if (rc) { 2632267843Sdelphij if (ms->flags & MAGIC_CHECK) 2633267843Sdelphij file_regerror(&rx, rc, ms); 2634267843Sdelphij } 2635267843Sdelphij file_regfree(&rx); 2636267843Sdelphij return rc ? -1 : 0; 2637267843Sdelphij } 2638133359Sobrien return 0; 2639175296Sobrien case FILE_FLOAT: 2640175296Sobrien case FILE_BEFLOAT: 2641175296Sobrien case FILE_LEFLOAT: 2642175296Sobrien if (m->reln != 'x') { 2643175296Sobrien char *ep; 2644290152Sdelphij errno = 0; 2645175296Sobrien#ifdef HAVE_STRTOF 2646175296Sobrien m->value.f = strtof(*p, &ep); 2647175296Sobrien#else 2648175296Sobrien m->value.f = (float)strtod(*p, &ep); 2649175296Sobrien#endif 2650290152Sdelphij if (errno == 0) 2651290152Sdelphij *p = ep; 2652175296Sobrien } 2653175296Sobrien return 0; 2654175296Sobrien case FILE_DOUBLE: 2655175296Sobrien case FILE_BEDOUBLE: 2656175296Sobrien case FILE_LEDOUBLE: 2657175296Sobrien if (m->reln != 'x') { 2658175296Sobrien char *ep; 2659290152Sdelphij errno = 0; 2660175296Sobrien m->value.d = strtod(*p, &ep); 2661290152Sdelphij if (errno == 0) 2662290152Sdelphij *p = ep; 2663175296Sobrien } 2664175296Sobrien return 0; 2665133359Sobrien default: 266668349Sobrien if (m->reln != 'x') { 2667159764Sobrien char *ep; 2668330569Sgordon uint64_t ull; 2669290152Sdelphij errno = 0; 2670330569Sgordon ull = (uint64_t)strtoull(*p, &ep, 0); 2671330569Sgordon m->value.q = file_signextend(ms, m, ull); 2672330569Sgordon if (*p == ep) { 2673330569Sgordon file_magwarn(ms, "Unparseable number `%s'", *p); 2674330569Sgordon } else { 2675330569Sgordon size_t ts = typesize(m->type); 2676330569Sgordon uint64_t x; 2677330569Sgordon const char *q; 2678330569Sgordon 2679330569Sgordon if (ts == (size_t)~0) { 2680330569Sgordon file_magwarn(ms, "Expected numeric type got `%s'", 2681330569Sgordon type_tbl[m->type].name); 2682330569Sgordon } 2683330569Sgordon for (q = *p; isspace((unsigned char)*q); q++) 2684330569Sgordon continue; 2685330569Sgordon if (*q == '-') 2686330569Sgordon ull = -(int64_t)ull; 2687330569Sgordon switch (ts) { 2688330569Sgordon case 1: 2689330569Sgordon x = ull & ~0xffULL; 2690330569Sgordon break; 2691330569Sgordon case 2: 2692330569Sgordon x = ull & ~0xffffULL; 2693330569Sgordon break; 2694330569Sgordon case 4: 2695330569Sgordon x = ull & ~0xffffffffULL; 2696330569Sgordon break; 2697330569Sgordon case 8: 2698330569Sgordon x = 0; 2699330569Sgordon break; 2700330569Sgordon default: 2701330569Sgordon abort(); 2702330569Sgordon } 2703330569Sgordon if (x) { 2704330569Sgordon file_magwarn(ms, "Overflow for numeric type `%s' value %#" PRIx64, 2705330569Sgordon type_tbl[m->type].name, ull); 2706330569Sgordon } 2707330569Sgordon } 2708290152Sdelphij if (errno == 0) { 2709290152Sdelphij *p = ep; 2710290152Sdelphij eatsize(p); 2711290152Sdelphij } 271268349Sobrien } 2713133359Sobrien return 0; 2714133359Sobrien } 271568349Sobrien} 271668349Sobrien 271768349Sobrien/* 271868349Sobrien * Convert a string containing C character escapes. Stop at an unescaped 271968349Sobrien * space or tab. 2720192348Sdelphij * Copy the converted version to "m->value.s", and the length in m->vallen. 2721192348Sdelphij * Return updated scan pointer as function result. Warn if set. 272268349Sobrien */ 2723159764Sobrienprivate const char * 2724192348Sdelphijgetstr(struct magic_set *ms, struct magic *m, const char *s, int warn) 272568349Sobrien{ 2726159764Sobrien const char *origs = s; 2727192348Sdelphij char *p = m->value.s; 2728192348Sdelphij size_t plen = sizeof(m->value.s); 2729159764Sobrien char *origp = p; 273068349Sobrien char *pmax = p + plen - 1; 273168349Sobrien int c; 273268349Sobrien int val; 273368349Sobrien 273468349Sobrien while ((c = *s++) != '\0') { 273568349Sobrien if (isspace((unsigned char) c)) 273668349Sobrien break; 273768349Sobrien if (p >= pmax) { 2738133359Sobrien file_error(ms, 0, "string too long: `%s'", origs); 2739133359Sobrien return NULL; 274068349Sobrien } 2741169962Sobrien if (c == '\\') { 274268349Sobrien switch(c = *s++) { 274368349Sobrien 274468349Sobrien case '\0': 2745192348Sdelphij if (warn) 2746169962Sobrien file_magwarn(ms, "incomplete escape"); 2747290152Sdelphij s--; 274868349Sobrien goto out; 274968349Sobrien 2750169962Sobrien case '\t': 2751192348Sdelphij if (warn) { 2752169962Sobrien file_magwarn(ms, 2753169962Sobrien "escaped tab found, use \\t instead"); 2754192348Sdelphij warn = 0; /* already did */ 2755169962Sobrien } 2756169962Sobrien /*FALLTHROUGH*/ 275768349Sobrien default: 2758192348Sdelphij if (warn) { 2759192348Sdelphij if (isprint((unsigned char)c)) { 2760192348Sdelphij /* Allow escaping of 2761192348Sdelphij * ``relations'' */ 2762226048Sobrien if (strchr("<>&^=!", c) == NULL 2763226048Sobrien && (m->type != FILE_REGEX || 2764226048Sobrien strchr("[]().*?^$|{}", c) 2765226048Sobrien == NULL)) { 2766192348Sdelphij file_magwarn(ms, "no " 2767192348Sdelphij "need to escape " 2768192348Sdelphij "`%c'", c); 2769192348Sdelphij } 2770192348Sdelphij } else { 2771192348Sdelphij file_magwarn(ms, 2772192348Sdelphij "unknown escape sequence: " 2773192348Sdelphij "\\%03o", c); 2774192348Sdelphij } 2775169962Sobrien } 2776169962Sobrien /*FALLTHROUGH*/ 2777169962Sobrien /* space, perhaps force people to use \040? */ 2778169962Sobrien case ' ': 2779169962Sobrien#if 0 2780169962Sobrien /* 2781169962Sobrien * Other things people escape, but shouldn't need to, 2782169962Sobrien * so we disallow them 2783169962Sobrien */ 2784169962Sobrien case '\'': 2785169962Sobrien case '"': 2786169962Sobrien case '?': 2787169962Sobrien#endif 2788169962Sobrien /* Relations */ 2789169962Sobrien case '>': 2790169962Sobrien case '<': 2791169962Sobrien case '&': 2792169962Sobrien case '^': 2793169962Sobrien case '=': 2794169962Sobrien case '!': 2795169962Sobrien /* and baskslash itself */ 2796169962Sobrien case '\\': 279768349Sobrien *p++ = (char) c; 279868349Sobrien break; 279968349Sobrien 2800169962Sobrien case 'a': 2801169962Sobrien *p++ = '\a'; 2802169962Sobrien break; 2803169962Sobrien 2804169962Sobrien case 'b': 2805169962Sobrien *p++ = '\b'; 2806169962Sobrien break; 2807169962Sobrien 2808169962Sobrien case 'f': 2809169962Sobrien *p++ = '\f'; 2810169962Sobrien break; 2811169962Sobrien 281268349Sobrien case 'n': 281368349Sobrien *p++ = '\n'; 281468349Sobrien break; 281568349Sobrien 281668349Sobrien case 'r': 281768349Sobrien *p++ = '\r'; 281868349Sobrien break; 281968349Sobrien 282068349Sobrien case 't': 282168349Sobrien *p++ = '\t'; 282268349Sobrien break; 282368349Sobrien 282468349Sobrien case 'v': 282568349Sobrien *p++ = '\v'; 282668349Sobrien break; 282768349Sobrien 282868349Sobrien /* \ and up to 3 octal digits */ 282968349Sobrien case '0': 283068349Sobrien case '1': 283168349Sobrien case '2': 283268349Sobrien case '3': 283368349Sobrien case '4': 283468349Sobrien case '5': 283568349Sobrien case '6': 283668349Sobrien case '7': 283768349Sobrien val = c - '0'; 283868349Sobrien c = *s++; /* try for 2 */ 2839169962Sobrien if (c >= '0' && c <= '7') { 2840169962Sobrien val = (val << 3) | (c - '0'); 284168349Sobrien c = *s++; /* try for 3 */ 2842169962Sobrien if (c >= '0' && c <= '7') 2843169962Sobrien val = (val << 3) | (c-'0'); 284468349Sobrien else 284568349Sobrien --s; 284668349Sobrien } 284768349Sobrien else 284868349Sobrien --s; 284968349Sobrien *p++ = (char)val; 285068349Sobrien break; 285168349Sobrien 285268349Sobrien /* \x and up to 2 hex digits */ 285368349Sobrien case 'x': 285468349Sobrien val = 'x'; /* Default if no digits */ 285568349Sobrien c = hextoint(*s++); /* Get next char */ 285668349Sobrien if (c >= 0) { 285768349Sobrien val = c; 285868349Sobrien c = hextoint(*s++); 285968349Sobrien if (c >= 0) 286068349Sobrien val = (val << 4) + c; 286168349Sobrien else 286268349Sobrien --s; 286368349Sobrien } else 286468349Sobrien --s; 286568349Sobrien *p++ = (char)val; 286668349Sobrien break; 286768349Sobrien } 286868349Sobrien } else 286968349Sobrien *p++ = (char)c; 287068349Sobrien } 2871290152Sdelphij --s; 287268349Sobrienout: 287368349Sobrien *p = '\0'; 2874226048Sobrien m->vallen = CAST(unsigned char, (p - origp)); 2875192348Sdelphij if (m->type == FILE_PSTRING) 2876226048Sobrien m->vallen += (unsigned char)file_pstring_length_size(m); 287768349Sobrien return s; 287868349Sobrien} 287968349Sobrien 288068349Sobrien 288168349Sobrien/* Single hex char to int; -1 if not a hex char. */ 2882133359Sobrienprivate int 2883103373Sobrienhextoint(int c) 288468349Sobrien{ 288568349Sobrien if (!isascii((unsigned char) c)) 288668349Sobrien return -1; 288768349Sobrien if (isdigit((unsigned char) c)) 288868349Sobrien return c - '0'; 2889169962Sobrien if ((c >= 'a') && (c <= 'f')) 289068349Sobrien return c + 10 - 'a'; 2891169962Sobrien if (( c>= 'A') && (c <= 'F')) 289268349Sobrien return c + 10 - 'A'; 289368349Sobrien return -1; 289468349Sobrien} 289568349Sobrien 289668349Sobrien 289768349Sobrien/* 289868349Sobrien * Print a string containing C character escapes. 289968349Sobrien */ 2900133359Sobrienprotected void 2901133359Sobrienfile_showstr(FILE *fp, const char *s, size_t len) 290268349Sobrien{ 290368349Sobrien char c; 290468349Sobrien 290568349Sobrien for (;;) { 2906133359Sobrien if (len == ~0U) { 2907226048Sobrien c = *s++; 290868349Sobrien if (c == '\0') 290968349Sobrien break; 291068349Sobrien } 291168349Sobrien else { 291268349Sobrien if (len-- == 0) 291368349Sobrien break; 2914226048Sobrien c = *s++; 291568349Sobrien } 2916169962Sobrien if (c >= 040 && c <= 0176) /* TODO isprint && !iscntrl */ 291768349Sobrien (void) fputc(c, fp); 291868349Sobrien else { 291968349Sobrien (void) fputc('\\', fp); 292068349Sobrien switch (c) { 2921169962Sobrien case '\a': 2922169962Sobrien (void) fputc('a', fp); 2923169962Sobrien break; 2924169962Sobrien 2925169962Sobrien case '\b': 2926169962Sobrien (void) fputc('b', fp); 2927169962Sobrien break; 2928169962Sobrien 2929169962Sobrien case '\f': 2930169962Sobrien (void) fputc('f', fp); 2931169962Sobrien break; 2932169962Sobrien 293368349Sobrien case '\n': 293468349Sobrien (void) fputc('n', fp); 293568349Sobrien break; 293668349Sobrien 293768349Sobrien case '\r': 293868349Sobrien (void) fputc('r', fp); 293968349Sobrien break; 294068349Sobrien 294168349Sobrien case '\t': 294268349Sobrien (void) fputc('t', fp); 294368349Sobrien break; 294468349Sobrien 294568349Sobrien case '\v': 294668349Sobrien (void) fputc('v', fp); 294768349Sobrien break; 294868349Sobrien 294968349Sobrien default: 295068349Sobrien (void) fprintf(fp, "%.3o", c & 0377); 295168349Sobrien break; 295268349Sobrien } 295368349Sobrien } 295468349Sobrien } 295568349Sobrien} 295668349Sobrien 295768349Sobrien/* 295868349Sobrien * eatsize(): Eat the size spec from a number [eg. 10UL] 295968349Sobrien */ 2960133359Sobrienprivate void 2961159764Sobrieneatsize(const char **p) 296268349Sobrien{ 2963159764Sobrien const char *l = *p; 296468349Sobrien 296568349Sobrien if (LOWCASE(*l) == 'u') 296668349Sobrien l++; 296768349Sobrien 296868349Sobrien switch (LOWCASE(*l)) { 296968349Sobrien case 'l': /* long */ 297068349Sobrien case 's': /* short */ 297168349Sobrien case 'h': /* short */ 297268349Sobrien case 'b': /* char/byte */ 297368349Sobrien case 'c': /* char/byte */ 297468349Sobrien l++; 297568349Sobrien /*FALLTHROUGH*/ 297668349Sobrien default: 297768349Sobrien break; 297868349Sobrien } 297968349Sobrien 298068349Sobrien *p = l; 298168349Sobrien} 298274784Sobrien 298374784Sobrien/* 2984276415Sdelphij * handle a buffer containing a compiled file. 2985276415Sdelphij */ 2986276415Sdelphijprivate struct magic_map * 2987276415Sdelphijapprentice_buf(struct magic_set *ms, struct magic *buf, size_t len) 2988276415Sdelphij{ 2989276415Sdelphij struct magic_map *map; 2990276415Sdelphij 2991276415Sdelphij if ((map = CAST(struct magic_map *, calloc(1, sizeof(*map)))) == NULL) { 2992276415Sdelphij file_oomem(ms, sizeof(*map)); 2993276415Sdelphij return NULL; 2994276415Sdelphij } 2995276415Sdelphij map->len = len; 2996276415Sdelphij map->p = buf; 2997276415Sdelphij map->type = MAP_TYPE_USER; 2998276415Sdelphij if (check_buffer(ms, map, "buffer") != 0) { 2999276415Sdelphij apprentice_unmap(map); 3000276415Sdelphij return NULL; 3001276415Sdelphij } 3002276415Sdelphij return map; 3003276415Sdelphij} 3004276415Sdelphij 3005276415Sdelphij/* 3006103373Sobrien * handle a compiled file. 300774784Sobrien */ 3008267843Sdelphij 3009267843Sdelphijprivate struct magic_map * 3010267843Sdelphijapprentice_map(struct magic_set *ms, const char *fn) 301174784Sobrien{ 301274784Sobrien int fd; 301374784Sobrien struct stat st; 3014186690Sobrien char *dbname = NULL; 3015267843Sdelphij struct magic_map *map; 3016330569Sgordon struct magic_map *rv = NULL; 301774784Sobrien 3018267843Sdelphij fd = -1; 3019267843Sdelphij if ((map = CAST(struct magic_map *, calloc(1, sizeof(*map)))) == NULL) { 3020267843Sdelphij file_oomem(ms, sizeof(*map)); 3021267843Sdelphij goto error; 3022267843Sdelphij } 3023330569Sgordon map->type = MAP_TYPE_USER; /* unspecified */ 3024267843Sdelphij 3025191736Sobrien dbname = mkdbname(ms, fn, 0); 302680588Sobrien if (dbname == NULL) 3027267843Sdelphij goto error; 302880588Sobrien 3029159764Sobrien if ((fd = open(dbname, O_RDONLY|O_BINARY)) == -1) 3030267843Sdelphij goto error; 303174784Sobrien 303274784Sobrien if (fstat(fd, &st) == -1) { 3033133359Sobrien file_error(ms, errno, "cannot stat `%s'", dbname); 3034267843Sdelphij goto error; 303574784Sobrien } 3036267843Sdelphij if (st.st_size < 8 || st.st_size > MAXMAGIC_SIZE) { 3037267843Sdelphij file_error(ms, 0, "file `%s' is too %s", dbname, 3038267843Sdelphij st.st_size < 8 ? "small" : "large"); 3039267843Sdelphij goto error; 3040133359Sobrien } 304174784Sobrien 3042267843Sdelphij map->len = (size_t)st.st_size; 304380588Sobrien#ifdef QUICK 3044330569Sgordon map->type = MAP_TYPE_MMAP; 3045267843Sdelphij if ((map->p = mmap(0, (size_t)st.st_size, PROT_READ|PROT_WRITE, 304674784Sobrien MAP_PRIVATE|MAP_FILE, fd, (off_t)0)) == MAP_FAILED) { 3047133359Sobrien file_error(ms, errno, "cannot map `%s'", dbname); 3048267843Sdelphij goto error; 304974784Sobrien } 305080588Sobrien#else 3051330569Sgordon map->type = MAP_TYPE_MALLOC; 3052267843Sdelphij if ((map->p = CAST(void *, malloc(map->len))) == NULL) { 3053267843Sdelphij file_oomem(ms, map->len); 3054267843Sdelphij goto error; 305580588Sobrien } 3056267843Sdelphij if (read(fd, map->p, map->len) != (ssize_t)map->len) { 3057133359Sobrien file_badread(ms); 3058267843Sdelphij goto error; 305980588Sobrien } 3060133359Sobrien#define RET 1 306180588Sobrien#endif 306274784Sobrien (void)close(fd); 306375937Sobrien fd = -1; 3064276415Sdelphij 3065330569Sgordon if (check_buffer(ms, map, dbname) != 0) { 3066330569Sgordon rv = (struct magic_map *)-1; 3067276415Sdelphij goto error; 3068330569Sgordon } 3069330569Sgordon#ifdef QUICK 3070330569Sgordon if (mprotect(map->p, (size_t)st.st_size, PROT_READ) == -1) { 3071330569Sgordon file_error(ms, errno, "cannot mprotect `%s'", dbname); 3072330569Sgordon goto error; 3073330569Sgordon } 3074330569Sgordon#endif 3075276415Sdelphij 3076276415Sdelphij free(dbname); 3077276415Sdelphij return map; 3078276415Sdelphij 3079276415Sdelphijerror: 3080276415Sdelphij if (fd != -1) 3081276415Sdelphij (void)close(fd); 3082276415Sdelphij apprentice_unmap(map); 3083276415Sdelphij free(dbname); 3084330569Sgordon return rv; 3085276415Sdelphij} 3086276415Sdelphij 3087276415Sdelphijprivate int 3088276415Sdelphijcheck_buffer(struct magic_set *ms, struct magic_map *map, const char *dbname) 3089276415Sdelphij{ 3090276415Sdelphij uint32_t *ptr; 3091276415Sdelphij uint32_t entries, nentries; 3092276415Sdelphij uint32_t version; 3093276415Sdelphij int i, needsbyteswap; 3094276415Sdelphij 3095267843Sdelphij ptr = CAST(uint32_t *, map->p); 309674784Sobrien if (*ptr != MAGICNO) { 309774784Sobrien if (swap4(*ptr) != MAGICNO) { 3098186690Sobrien file_error(ms, 0, "bad magic in `%s'", dbname); 3099276415Sdelphij return -1; 310074784Sobrien } 310174784Sobrien needsbyteswap = 1; 310274784Sobrien } else 310374784Sobrien needsbyteswap = 0; 310474784Sobrien if (needsbyteswap) 310574784Sobrien version = swap4(ptr[1]); 310674784Sobrien else 310774784Sobrien version = ptr[1]; 310874784Sobrien if (version != VERSIONNO) { 3109226048Sobrien file_error(ms, 0, "File %s supports only version %d magic " 3110226048Sobrien "files. `%s' is version %d", VERSION, 3111175296Sobrien VERSIONNO, dbname, version); 3112276415Sdelphij return -1; 311374784Sobrien } 3114276415Sdelphij entries = (uint32_t)(map->len / sizeof(struct magic)); 3115276415Sdelphij if ((entries * sizeof(struct magic)) != map->len) { 3116276415Sdelphij file_error(ms, 0, "Size of `%s' %" SIZE_T_FORMAT "u is not " 3117267843Sdelphij "a multiple of %" SIZE_T_FORMAT "u", 3118276415Sdelphij dbname, map->len, sizeof(struct magic)); 3119276415Sdelphij return -1; 3120267843Sdelphij } 3121267843Sdelphij map->magic[0] = CAST(struct magic *, map->p) + 1; 3122267843Sdelphij nentries = 0; 3123267843Sdelphij for (i = 0; i < MAGIC_SETS; i++) { 3124267843Sdelphij if (needsbyteswap) 3125267843Sdelphij map->nmagic[i] = swap4(ptr[i + 2]); 3126267843Sdelphij else 3127267843Sdelphij map->nmagic[i] = ptr[i + 2]; 3128267843Sdelphij if (i != MAGIC_SETS - 1) 3129267843Sdelphij map->magic[i + 1] = map->magic[i] + map->nmagic[i]; 3130267843Sdelphij nentries += map->nmagic[i]; 3131267843Sdelphij } 3132267843Sdelphij if (entries != nentries + 1) { 3133267843Sdelphij file_error(ms, 0, "Inconsistent entries in `%s' %u != %u", 3134267843Sdelphij dbname, entries, nentries + 1); 3135276415Sdelphij return -1; 3136267843Sdelphij } 313774784Sobrien if (needsbyteswap) 3138267843Sdelphij for (i = 0; i < MAGIC_SETS; i++) 3139267843Sdelphij byteswap(map->magic[i], map->nmagic[i]); 3140276415Sdelphij return 0; 314174784Sobrien} 314274784Sobrien 314374784Sobrien/* 314474784Sobrien * handle an mmaped file. 314574784Sobrien */ 3146133359Sobrienprivate int 3147267843Sdelphijapprentice_compile(struct magic_set *ms, struct magic_map *map, const char *fn) 314874784Sobrien{ 3149267843Sdelphij static const size_t nm = sizeof(*map->nmagic) * MAGIC_SETS; 3150267843Sdelphij static const size_t m = sizeof(**map->magic); 3151234250Sobrien int fd = -1; 3152267843Sdelphij size_t len; 3153186690Sobrien char *dbname; 3154186690Sobrien int rv = -1; 3155267843Sdelphij uint32_t i; 3156267843Sdelphij union { 3157267843Sdelphij struct magic m; 3158267843Sdelphij uint32_t h[2 + MAGIC_SETS]; 3159267843Sdelphij } hdr; 316074784Sobrien 3161191736Sobrien dbname = mkdbname(ms, fn, 1); 3162186690Sobrien 316380588Sobrien if (dbname == NULL) 3164186690Sobrien goto out; 316580588Sobrien 3166267843Sdelphij if ((fd = open(dbname, O_WRONLY|O_CREAT|O_TRUNC|O_BINARY, 0644)) == -1) 3167267843Sdelphij { 3168133359Sobrien file_error(ms, errno, "cannot open `%s'", dbname); 3169186690Sobrien goto out; 317074784Sobrien } 3171267843Sdelphij memset(&hdr, 0, sizeof(hdr)); 3172267843Sdelphij hdr.h[0] = MAGICNO; 3173267843Sdelphij hdr.h[1] = VERSIONNO; 3174267843Sdelphij memcpy(hdr.h + 2, map->nmagic, nm); 317574784Sobrien 3176267843Sdelphij if (write(fd, &hdr, sizeof(hdr)) != (ssize_t)sizeof(hdr)) { 3177133359Sobrien file_error(ms, errno, "error writing `%s'", dbname); 3178186690Sobrien goto out; 317974784Sobrien } 318074784Sobrien 3181267843Sdelphij for (i = 0; i < MAGIC_SETS; i++) { 3182267843Sdelphij len = m * map->nmagic[i]; 3183267843Sdelphij if (write(fd, map->magic[i], len) != (ssize_t)len) { 3184267843Sdelphij file_error(ms, errno, "error writing `%s'", dbname); 3185267843Sdelphij goto out; 3186267843Sdelphij } 318774784Sobrien } 318874784Sobrien 3189234250Sobrien if (fd != -1) 3190234250Sobrien (void)close(fd); 3191186690Sobrien rv = 0; 3192186690Sobrienout: 3193330569Sgordon apprentice_unmap(map); 3194186690Sobrien free(dbname); 3195186690Sobrien return rv; 319674784Sobrien} 319774784Sobrien 3198133359Sobrienprivate const char ext[] = ".mgc"; 319974784Sobrien/* 320074784Sobrien * make a dbname 320174784Sobrien */ 3202191736Sobrienprivate char * 3203191736Sobrienmkdbname(struct magic_set *ms, const char *fn, int strip) 320474784Sobrien{ 3205191736Sobrien const char *p, *q; 3206191736Sobrien char *buf; 3207191736Sobrien 3208139368Sobrien if (strip) { 3209139368Sobrien if ((p = strrchr(fn, '/')) != NULL) 3210139368Sobrien fn = ++p; 3211139368Sobrien } 3212139368Sobrien 3213191736Sobrien for (q = fn; *q; q++) 3214191736Sobrien continue; 3215191736Sobrien /* Look for .mgc */ 3216191736Sobrien for (p = ext + sizeof(ext) - 1; p >= ext && q >= fn; p--, q--) 3217191736Sobrien if (*p != *q) 3218191736Sobrien break; 3219186690Sobrien 3220191736Sobrien /* Did not find .mgc, restore q */ 3221191736Sobrien if (p >= ext) 3222191736Sobrien while (*q) 3223191736Sobrien q++; 3224191736Sobrien 3225191736Sobrien q++; 3226191736Sobrien /* Compatibility with old code that looked in .mime */ 3227191736Sobrien if (ms->flags & MAGIC_MIME) { 3228267843Sdelphij if (asprintf(&buf, "%.*s.mime%s", (int)(q - fn), fn, ext) < 0) 3229267843Sdelphij return NULL; 3230191736Sobrien if (access(buf, R_OK) != -1) { 3231191736Sobrien ms->flags &= MAGIC_MIME_TYPE; 3232191736Sobrien return buf; 3233191736Sobrien } 3234191736Sobrien free(buf); 3235186690Sobrien } 3236267843Sdelphij if (asprintf(&buf, "%.*s%s", (int)(q - fn), fn, ext) < 0) 3237267843Sdelphij return NULL; 3238191736Sobrien 3239191736Sobrien /* Compatibility with old code that looked in .mime */ 3240330569Sgordon if (strstr(fn, ".mime") != NULL) 3241191736Sobrien ms->flags &= MAGIC_MIME_TYPE; 3242191736Sobrien return buf; 324374784Sobrien} 324474784Sobrien 324574784Sobrien/* 324674784Sobrien * Byteswap an mmap'ed file if needed 324774784Sobrien */ 3248133359Sobrienprivate void 3249103373Sobrienbyteswap(struct magic *magic, uint32_t nmagic) 325074784Sobrien{ 3251103373Sobrien uint32_t i; 325274784Sobrien for (i = 0; i < nmagic; i++) 325374784Sobrien bs1(&magic[i]); 325474784Sobrien} 325574784Sobrien 325674784Sobrien/* 325774784Sobrien * swap a short 325874784Sobrien */ 3259133359Sobrienprivate uint16_t 3260103373Sobrienswap2(uint16_t sv) 326174784Sobrien{ 3262103373Sobrien uint16_t rv; 3263133359Sobrien uint8_t *s = (uint8_t *)(void *)&sv; 3264133359Sobrien uint8_t *d = (uint8_t *)(void *)&rv; 326574784Sobrien d[0] = s[1]; 326674784Sobrien d[1] = s[0]; 326774784Sobrien return rv; 326874784Sobrien} 326974784Sobrien 327074784Sobrien/* 327174784Sobrien * swap an int 327274784Sobrien */ 3273133359Sobrienprivate uint32_t 3274103373Sobrienswap4(uint32_t sv) 327574784Sobrien{ 3276103373Sobrien uint32_t rv; 3277133359Sobrien uint8_t *s = (uint8_t *)(void *)&sv; 3278133359Sobrien uint8_t *d = (uint8_t *)(void *)&rv; 327974784Sobrien d[0] = s[3]; 328074784Sobrien d[1] = s[2]; 328174784Sobrien d[2] = s[1]; 328274784Sobrien d[3] = s[0]; 328374784Sobrien return rv; 328474784Sobrien} 328574784Sobrien 328674784Sobrien/* 3287169942Sobrien * swap a quad 3288169942Sobrien */ 3289169942Sobrienprivate uint64_t 3290169942Sobrienswap8(uint64_t sv) 3291169942Sobrien{ 3292186690Sobrien uint64_t rv; 3293169942Sobrien uint8_t *s = (uint8_t *)(void *)&sv; 3294169942Sobrien uint8_t *d = (uint8_t *)(void *)&rv; 3295186690Sobrien#if 0 3296169942Sobrien d[0] = s[3]; 3297169942Sobrien d[1] = s[2]; 3298169942Sobrien d[2] = s[1]; 3299169942Sobrien d[3] = s[0]; 3300169942Sobrien d[4] = s[7]; 3301169942Sobrien d[5] = s[6]; 3302169942Sobrien d[6] = s[5]; 3303169942Sobrien d[7] = s[4]; 3304186690Sobrien#else 3305186690Sobrien d[0] = s[7]; 3306186690Sobrien d[1] = s[6]; 3307186690Sobrien d[2] = s[5]; 3308186690Sobrien d[3] = s[4]; 3309186690Sobrien d[4] = s[3]; 3310186690Sobrien d[5] = s[2]; 3311186690Sobrien d[6] = s[1]; 3312186690Sobrien d[7] = s[0]; 3313186690Sobrien#endif 3314169942Sobrien return rv; 3315169942Sobrien} 3316169942Sobrien 3317169942Sobrien/* 331874784Sobrien * byteswap a single magic entry 331974784Sobrien */ 3320133359Sobrienprivate void 3321133359Sobrienbs1(struct magic *m) 332274784Sobrien{ 332374784Sobrien m->cont_level = swap2(m->cont_level); 3324133359Sobrien m->offset = swap4((uint32_t)m->offset); 3325133359Sobrien m->in_offset = swap4((uint32_t)m->in_offset); 3326169962Sobrien m->lineno = swap4((uint32_t)m->lineno); 3327169962Sobrien if (IS_STRING(m->type)) { 3328186690Sobrien m->str_range = swap4(m->str_range); 3329169962Sobrien m->str_flags = swap4(m->str_flags); 3330169962Sobrien } 3331169962Sobrien else { 3332169942Sobrien m->value.q = swap8(m->value.q); 3333169962Sobrien m->num_mask = swap8(m->num_mask); 3334169962Sobrien } 333574784Sobrien} 3336226048Sobrien 3337226048Sobrienprotected size_t 3338226048Sobrienfile_pstring_length_size(const struct magic *m) 3339226048Sobrien{ 3340226048Sobrien switch (m->str_flags & PSTRING_LEN) { 3341226048Sobrien case PSTRING_1_LE: 3342226048Sobrien return 1; 3343226048Sobrien case PSTRING_2_LE: 3344226048Sobrien case PSTRING_2_BE: 3345226048Sobrien return 2; 3346226048Sobrien case PSTRING_4_LE: 3347226048Sobrien case PSTRING_4_BE: 3348226048Sobrien return 4; 3349226048Sobrien default: 3350226048Sobrien abort(); /* Impossible */ 3351226048Sobrien return 1; 3352226048Sobrien } 3353226048Sobrien} 3354226048Sobrienprotected size_t 3355290152Sdelphijfile_pstring_get_length(const struct magic *m, const char *ss) 3356226048Sobrien{ 3357226048Sobrien size_t len = 0; 3358290152Sdelphij const unsigned char *s = (const unsigned char *)ss; 3359330569Sgordon unsigned int s3, s2, s1, s0; 3360226048Sobrien 3361226048Sobrien switch (m->str_flags & PSTRING_LEN) { 3362226048Sobrien case PSTRING_1_LE: 3363226048Sobrien len = *s; 3364226048Sobrien break; 3365226048Sobrien case PSTRING_2_LE: 3366330569Sgordon s0 = s[0]; 3367330569Sgordon s1 = s[1]; 3368330569Sgordon len = (s1 << 8) | s0; 3369226048Sobrien break; 3370226048Sobrien case PSTRING_2_BE: 3371330569Sgordon s0 = s[0]; 3372330569Sgordon s1 = s[1]; 3373330569Sgordon len = (s0 << 8) | s1; 3374226048Sobrien break; 3375226048Sobrien case PSTRING_4_LE: 3376330569Sgordon s0 = s[0]; 3377330569Sgordon s1 = s[1]; 3378330569Sgordon s2 = s[2]; 3379330569Sgordon s3 = s[3]; 3380330569Sgordon len = (s3 << 24) | (s2 << 16) | (s1 << 8) | s0; 3381226048Sobrien break; 3382226048Sobrien case PSTRING_4_BE: 3383330569Sgordon s0 = s[0]; 3384330569Sgordon s1 = s[1]; 3385330569Sgordon s2 = s[2]; 3386330569Sgordon s3 = s[3]; 3387330569Sgordon len = (s0 << 24) | (s1 << 16) | (s2 << 8) | s3; 3388226048Sobrien break; 3389226048Sobrien default: 3390226048Sobrien abort(); /* Impossible */ 3391226048Sobrien } 3392226048Sobrien 3393226048Sobrien if (m->str_flags & PSTRING_LENGTH_INCLUDES_ITSELF) 3394226048Sobrien len -= file_pstring_length_size(m); 3395226048Sobrien 3396226048Sobrien return len; 3397226048Sobrien} 3398267843Sdelphij 3399267843Sdelphijprotected int 3400267843Sdelphijfile_magicfind(struct magic_set *ms, const char *name, struct mlist *v) 3401267843Sdelphij{ 3402267843Sdelphij uint32_t i, j; 3403267843Sdelphij struct mlist *mlist, *ml; 3404267843Sdelphij 3405267843Sdelphij mlist = ms->mlist[1]; 3406267843Sdelphij 3407267843Sdelphij for (ml = mlist->next; ml != mlist; ml = ml->next) { 3408267843Sdelphij struct magic *ma = ml->magic; 3409267843Sdelphij uint32_t nma = ml->nmagic; 3410267843Sdelphij for (i = 0; i < nma; i++) { 3411267843Sdelphij if (ma[i].type != FILE_NAME) 3412267843Sdelphij continue; 3413267843Sdelphij if (strcmp(ma[i].value.s, name) == 0) { 3414267843Sdelphij v->magic = &ma[i]; 3415267843Sdelphij for (j = i + 1; j < nma; j++) 3416267843Sdelphij if (ma[j].cont_level == 0) 3417267843Sdelphij break; 3418267843Sdelphij v->nmagic = j - i; 3419267843Sdelphij return 0; 3420267843Sdelphij } 3421267843Sdelphij } 3422267843Sdelphij } 3423267843Sdelphij return -1; 3424267843Sdelphij} 3425