1 /* $NetBSD: apprentice.c,v 1.30 2026/06/10 20:54:16 christos Exp $ */ 2 3 /* 4 * Copyright (c) Ian F. Darwin 1986-1995. 5 * Software written by Ian F. Darwin and others; 6 * maintained 1995-present by Christos Zoulas and others. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice immediately at the beginning of the file, without modification, 13 * this list of conditions, and the following disclaimer. 14 * 2. Redistributions in binary form must reproduce the above copyright 15 * notice, this list of conditions and the following disclaimer in the 16 * documentation and/or other materials provided with the distribution. 17 * 18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 19 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR 22 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 24 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 25 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 26 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 27 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 28 * SUCH DAMAGE. 29 */ 30 /* 31 * apprentice - make one pass through /etc/magic, learning its secrets. 32 */ 33 34 #include "file.h" 35 36 #ifndef lint 37 #if 0 38 FILE_RCSID("@(#)$File: apprentice.c,v 1.376 2026/05/09 22:44:32 christos Exp $") 39 #else 40 __RCSID("$NetBSD: apprentice.c,v 1.30 2026/06/10 20:54:16 christos Exp $"); 41 #endif 42 #endif /* lint */ 43 44 #include "magic.h" 45 #include "swap.h" 46 #include <stdlib.h> 47 #ifdef HAVE_UNISTD_H 48 #include <unistd.h> 49 #endif 50 #include <stddef.h> 51 #include <string.h> 52 #include <assert.h> 53 #include <ctype.h> 54 #include <fcntl.h> 55 #ifdef QUICK 56 #include <sys/mman.h> 57 #endif 58 #include <dirent.h> 59 #include <limits.h> 60 61 62 #define EATAB {while (*l && isascii(CAST(unsigned char, *l)) && \ 63 isspace(CAST(unsigned char, *l))) ++l;} 64 #define LOWCASE(l) (isupper(CAST(unsigned char, l)) ? \ 65 tolower(CAST(unsigned char, l)) : (l)) 66 /* 67 * Work around a bug in headers on Digital Unix. 68 * At least confirmed for: OSF1 V4.0 878 69 */ 70 #if defined(__osf__) && defined(__DECC) 71 #ifdef MAP_FAILED 72 #undef MAP_FAILED 73 #endif 74 #endif 75 76 #ifndef MAP_FAILED 77 #define MAP_FAILED (void *) -1 78 #endif 79 80 #ifndef MAP_FILE 81 #define MAP_FILE 0 82 #endif 83 84 #define ALLOC_CHUNK CAST(size_t, 10) 85 #define ALLOC_INCR CAST(size_t, 200) 86 87 #define MAP_TYPE_USER 0 88 #define MAP_TYPE_MALLOC 1 89 #define MAP_TYPE_MMAP 2 90 91 struct magic_entry { 92 struct magic *mp; 93 uint32_t cont_count; 94 uint32_t max_count; 95 }; 96 97 struct magic_entry_set { 98 struct magic_entry *me; 99 uint32_t count; 100 uint32_t max; 101 }; 102 103 struct magic_map { 104 void *p; 105 size_t len; 106 int type; 107 struct magic *magic[MAGIC_SETS]; 108 uint32_t nmagic[MAGIC_SETS]; 109 }; 110 111 file_private int file_formats[FILE_NAMES_SIZE]; 112 file_private const size_t file_nformats = FILE_NAMES_SIZE; 113 file_protected const char *file_names[FILE_NAMES_SIZE]; 114 file_protected const size_t file_nnames = FILE_NAMES_SIZE; 115 116 file_private int getvalue(struct magic_set *ms, struct magic *, const char **, int); 117 file_private int hextoint(int); 118 file_private const char *getstr(struct magic_set *, struct magic *, const char *, 119 int); 120 file_private int parse(struct magic_set *, struct magic_entry *, const char *, 121 const char *, size_t, size_t, int); 122 file_private void eatsize(const char **); 123 file_private int apprentice_1(struct magic_set *, const char *, int); 124 file_private ssize_t apprentice_magic_strength_1(const struct magic *); 125 file_private int apprentice_sort(const void *, const void *); 126 file_private void apprentice_list(struct mlist *, int ); 127 file_private struct magic_map *apprentice_load(struct magic_set *, 128 const char *, int); 129 file_private struct mlist *mlist_alloc(void); 130 file_private void mlist_free_all(struct magic_set *); 131 file_private void mlist_free(struct mlist *); 132 file_private void byteswap(struct magic *, uint32_t); 133 file_private void bs1(struct magic *); 134 135 file_private char *mkdbname(struct magic_set *, const char *, int); 136 file_private struct magic_map *apprentice_buf(struct magic_set *, struct magic *, 137 size_t); 138 file_private struct magic_map *apprentice_map(struct magic_set *, const char *); 139 file_private int check_buffer(struct magic_set *, struct magic_map *, const char *); 140 file_private void apprentice_unmap(struct magic_map *); 141 file_private int apprentice_compile(struct magic_set *, struct magic_map *, 142 const char *); 143 file_private int check_format_type(const char *, int, const char **); 144 file_private int check_format(struct magic_set *, struct magic *); 145 file_private int get_op(char); 146 file_private int parse_mime(struct magic_set *, struct magic_entry *, const char *, 147 size_t); 148 file_private int parse_strength(struct magic_set *, struct magic_entry *, 149 const char *, size_t); 150 file_private int parse_apple(struct magic_set *, struct magic_entry *, const char *, 151 size_t); 152 file_private int parse_ext(struct magic_set *, struct magic_entry *, const char *, 153 size_t); 154 155 156 file_private size_t magicsize = sizeof(struct magic); 157 158 file_private const char usg_hdr[] = "cont\toffset\ttype\topcode\tmask\tvalue\tdesc"; 159 160 file_private struct { 161 const char *name; 162 size_t len; 163 int (*fun)(struct magic_set *, struct magic_entry *, const char *, 164 size_t); 165 } bang[] = { 166 #define DECLARE_FIELD(name) { # name, sizeof(# name) - 1, parse_ ## name } 167 DECLARE_FIELD(mime), 168 DECLARE_FIELD(apple), 169 DECLARE_FIELD(ext), 170 DECLARE_FIELD(strength), 171 #undef DECLARE_FIELD 172 { NULL, 0, NULL } 173 }; 174 175 #ifdef COMPILE_ONLY 176 177 int main(int, char *[]); 178 179 int 180 main(int argc, char *argv[]) 181 { 182 int ret; 183 struct magic_set *ms; 184 char *progname; 185 186 if ((progname = strrchr(argv[0], '/')) != NULL) 187 progname++; 188 else 189 progname = argv[0]; 190 191 if (argc != 2) { 192 (void)fprintf(stderr, "Usage: %s file\n", progname); 193 return 1; 194 } 195 196 if ((ms = magic_open(MAGIC_CHECK)) == NULL) { 197 (void)fprintf(stderr, "%s: %s\n", progname, strerror(errno)); 198 return 1; 199 } 200 ret = magic_compile(ms, argv[1]) == -1 ? 1 : 0; 201 if (ret == 1) 202 (void)fprintf(stderr, "%s: %s\n", progname, magic_error(ms)); 203 magic_close(ms); 204 return ret; 205 } 206 #endif /* COMPILE_ONLY */ 207 208 struct type_tbl_s { 209 const char name[16]; 210 const size_t len; 211 const int type; 212 const int format; 213 }; 214 215 /* 216 * XXX - the actual Single UNIX Specification says that "long" means "long", 217 * as in the C data type, but we treat it as meaning "4-byte integer". 218 * Given that the OS X version of file 5.04 did the same, I guess that passes 219 * the actual test; having "long" be dependent on how big a "long" is on 220 * the machine running "file" is silly. 221 */ 222 static const struct type_tbl_s type_tbl[] = { 223 # define XX(s) s, (sizeof(s) - 1) 224 # define XX_NULL "", 0 225 { XX("invalid"), FILE_INVALID, FILE_FMT_NONE }, 226 { XX("byte"), FILE_BYTE, FILE_FMT_NUM }, 227 { XX("short"), FILE_SHORT, FILE_FMT_NUM }, 228 { XX("default"), FILE_DEFAULT, FILE_FMT_NONE }, 229 { XX("long"), FILE_LONG, FILE_FMT_NUM }, 230 { XX("string"), FILE_STRING, FILE_FMT_STR }, 231 { XX("date"), FILE_DATE, FILE_FMT_STR }, 232 { XX("beshort"), FILE_BESHORT, FILE_FMT_NUM }, 233 { XX("belong"), FILE_BELONG, FILE_FMT_NUM }, 234 { XX("bedate"), FILE_BEDATE, FILE_FMT_STR }, 235 { XX("leshort"), FILE_LESHORT, FILE_FMT_NUM }, 236 { XX("lelong"), FILE_LELONG, FILE_FMT_NUM }, 237 { XX("ledate"), FILE_LEDATE, FILE_FMT_STR }, 238 { XX("pstring"), FILE_PSTRING, FILE_FMT_STR }, 239 { XX("ldate"), FILE_LDATE, FILE_FMT_STR }, 240 { XX("beldate"), FILE_BELDATE, FILE_FMT_STR }, 241 { XX("leldate"), FILE_LELDATE, FILE_FMT_STR }, 242 { XX("regex"), FILE_REGEX, FILE_FMT_STR }, 243 { XX("bestring16"), FILE_BESTRING16, FILE_FMT_STR }, 244 { XX("lestring16"), FILE_LESTRING16, FILE_FMT_STR }, 245 { XX("search"), FILE_SEARCH, FILE_FMT_STR }, 246 { XX("medate"), FILE_MEDATE, FILE_FMT_STR }, 247 { XX("meldate"), FILE_MELDATE, FILE_FMT_STR }, 248 { XX("melong"), FILE_MELONG, FILE_FMT_NUM }, 249 { XX("quad"), FILE_QUAD, FILE_FMT_QUAD }, 250 { XX("lequad"), FILE_LEQUAD, FILE_FMT_QUAD }, 251 { XX("bequad"), FILE_BEQUAD, FILE_FMT_QUAD }, 252 { XX("qdate"), FILE_QDATE, FILE_FMT_STR }, 253 { XX("leqdate"), FILE_LEQDATE, FILE_FMT_STR }, 254 { XX("beqdate"), FILE_BEQDATE, FILE_FMT_STR }, 255 { XX("qldate"), FILE_QLDATE, FILE_FMT_STR }, 256 { XX("leqldate"), FILE_LEQLDATE, FILE_FMT_STR }, 257 { XX("beqldate"), FILE_BEQLDATE, FILE_FMT_STR }, 258 { XX("float"), FILE_FLOAT, FILE_FMT_FLOAT }, 259 { XX("befloat"), FILE_BEFLOAT, FILE_FMT_FLOAT }, 260 { XX("lefloat"), FILE_LEFLOAT, FILE_FMT_FLOAT }, 261 { XX("double"), FILE_DOUBLE, FILE_FMT_DOUBLE }, 262 { XX("bedouble"), FILE_BEDOUBLE, FILE_FMT_DOUBLE }, 263 { XX("ledouble"), FILE_LEDOUBLE, FILE_FMT_DOUBLE }, 264 { XX("leid3"), FILE_LEID3, FILE_FMT_NUM }, 265 { XX("beid3"), FILE_BEID3, FILE_FMT_NUM }, 266 { XX("indirect"), FILE_INDIRECT, FILE_FMT_NUM }, 267 { XX("qwdate"), FILE_QWDATE, FILE_FMT_STR }, 268 { XX("leqwdate"), FILE_LEQWDATE, FILE_FMT_STR }, 269 { XX("beqwdate"), FILE_BEQWDATE, FILE_FMT_STR }, 270 { XX("name"), FILE_NAME, FILE_FMT_NONE }, 271 { XX("use"), FILE_USE, FILE_FMT_NONE }, 272 { XX("clear"), FILE_CLEAR, FILE_FMT_NONE }, 273 { XX("der"), FILE_DER, FILE_FMT_STR }, 274 { XX("guid"), FILE_GUID, FILE_FMT_STR }, 275 { XX("leguid"), FILE_LEGUID, FILE_FMT_STR }, 276 { XX("beguid"), FILE_BEGUID, FILE_FMT_STR }, 277 { XX("offset"), FILE_OFFSET, FILE_FMT_QUAD }, 278 { XX("bevarint"), FILE_BEVARINT, FILE_FMT_STR }, 279 { XX("levarint"), FILE_LEVARINT, FILE_FMT_STR }, 280 { XX("msdosdate"), FILE_MSDOSDATE, FILE_FMT_STR }, 281 { XX("lemsdosdate"), FILE_LEMSDOSDATE, FILE_FMT_STR }, 282 { XX("bemsdosdate"), FILE_BEMSDOSDATE, FILE_FMT_STR }, 283 { XX("msdostime"), FILE_MSDOSTIME, FILE_FMT_STR }, 284 { XX("lemsdostime"), FILE_LEMSDOSTIME, FILE_FMT_STR }, 285 { XX("bemsdostime"), FILE_BEMSDOSTIME, FILE_FMT_STR }, 286 { XX("octal"), FILE_OCTAL, FILE_FMT_STR }, 287 { XX_NULL, FILE_INVALID, FILE_FMT_NONE }, 288 }; 289 290 /* 291 * These are not types, and cannot be preceded by "u" to make them 292 * unsigned. 293 */ 294 static const struct type_tbl_s special_tbl[] = { 295 { XX("der"), FILE_DER, FILE_FMT_STR }, 296 { XX("name"), FILE_NAME, FILE_FMT_STR }, 297 { XX("use"), FILE_USE, FILE_FMT_STR }, 298 { XX("octal"), FILE_OCTAL, FILE_FMT_STR }, 299 { XX_NULL, FILE_INVALID, FILE_FMT_NONE }, 300 }; 301 # undef XX 302 # undef XX_NULL 303 304 file_private int 305 get_type(const struct type_tbl_s *tbl, const char *l, const char **t) 306 { 307 const struct type_tbl_s *p; 308 309 for (p = tbl; p->len; p++) { 310 if (strncmp(l, p->name, p->len) == 0) { 311 if (t) 312 *t = l + p->len; 313 break; 314 } 315 } 316 return p->type; 317 } 318 319 file_private off_t 320 maxoff_t(void) { 321 if (/*CONSTCOND*/sizeof(off_t) == sizeof(int)) 322 return CAST(off_t, INT_MAX); 323 if (/*CONSTCOND*/sizeof(off_t) == sizeof(long)) 324 return CAST(off_t, LONG_MAX); 325 return 0x7fffffff; 326 } 327 328 file_private int 329 get_standard_integer_type(const char *l, const char **t) 330 { 331 int type; 332 333 if (l[0] == '\0') 334 return FILE_INVALID; 335 if (l[1] == '\0') 336 return FILE_INVALID; 337 else if (isalpha(CAST(unsigned char, l[1]))) { 338 switch (l[1]) { 339 case 'C': 340 /* "dC" and "uC" */ 341 type = FILE_BYTE; 342 break; 343 case 'S': 344 /* "dS" and "uS" */ 345 type = FILE_SHORT; 346 break; 347 case 'I': 348 case 'L': 349 /* 350 * "dI", "dL", "uI", and "uL". 351 * 352 * XXX - the actual Single UNIX Specification says 353 * that "L" means "long", as in the C data type, 354 * but we treat it as meaning "4-byte integer". 355 * Given that the OS X version of file 5.04 did 356 * the same, I guess that passes the actual SUS 357 * validation suite; having "dL" be dependent on 358 * how big a "long" is on the machine running 359 * "file" is silly. 360 */ 361 type = FILE_LONG; 362 break; 363 case 'Q': 364 /* "dQ" and "uQ" */ 365 type = FILE_QUAD; 366 break; 367 default: 368 /* "d{anything else}", "u{anything else}" */ 369 return FILE_INVALID; 370 } 371 l += 2; 372 } else if (isdigit(CAST(unsigned char, l[1]))) { 373 /* 374 * "d{num}" and "u{num}"; we only support {num} values 375 * of 1, 2, 4, and 8 - the Single UNIX Specification 376 * doesn't say anything about whether arbitrary 377 * values should be supported, but both the Solaris 10 378 * and OS X Mountain Lion versions of file passed the 379 * Single UNIX Specification validation suite, and 380 * neither of them support values bigger than 8 or 381 * non-power-of-2 values. 382 */ 383 if (isdigit(CAST(unsigned char, l[2]))) { 384 /* Multi-digit, so > 9 */ 385 return FILE_INVALID; 386 } 387 switch (l[1]) { 388 case '1': 389 type = FILE_BYTE; 390 break; 391 case '2': 392 type = FILE_SHORT; 393 break; 394 case '4': 395 type = FILE_LONG; 396 break; 397 case '8': 398 type = FILE_QUAD; 399 break; 400 default: 401 /* XXX - what about 3, 5, 6, or 7? */ 402 return FILE_INVALID; 403 } 404 l += 2; 405 } else { 406 /* 407 * "d" or "u" by itself. 408 */ 409 type = FILE_LONG; 410 ++l; 411 } 412 if (t) 413 *t = l; 414 return type; 415 } 416 417 file_private void 418 init_file_tables(void) 419 { 420 static int done = 0; 421 const struct type_tbl_s *p; 422 423 if (done) 424 return; 425 done++; 426 427 for (p = type_tbl; p->len; p++) { 428 assert(p->type < FILE_NAMES_SIZE); 429 file_names[p->type] = p->name; 430 file_formats[p->type] = p->format; 431 } 432 assert(p - type_tbl == FILE_NAMES_SIZE); 433 } 434 435 file_private int 436 add_mlist(struct mlist *mlp, struct magic_map *map, size_t idx) 437 { 438 struct mlist *ml; 439 440 mlp->map = NULL; 441 if ((ml = CAST(struct mlist *, malloc(sizeof(*ml)))) == NULL) 442 return -1; 443 444 ml->map = idx == 0 ? map : NULL; 445 ml->magic = map->magic[idx]; 446 ml->nmagic = map->nmagic[idx]; 447 if (ml->nmagic) { 448 ml->magic_rxcomp = CAST(file_regex_t **, 449 calloc(ml->nmagic, sizeof(*ml->magic_rxcomp))); 450 if (ml->magic_rxcomp == NULL) { 451 free(ml); 452 return -1; 453 } 454 } else 455 ml->magic_rxcomp = NULL; 456 mlp->prev->next = ml; 457 ml->prev = mlp->prev; 458 ml->next = mlp; 459 mlp->prev = ml; 460 return 0; 461 } 462 463 /* 464 * Handle one file or directory. 465 */ 466 file_private int 467 apprentice_1(struct magic_set *ms, const char *fn, int action) 468 { 469 struct magic_map *map; 470 #ifndef COMPILE_ONLY 471 size_t i; 472 #endif 473 474 if (magicsize != FILE_MAGICSIZE) { 475 file_error(ms, 0, "magic element size %lu != %lu", 476 CAST(unsigned long, sizeof(*map->magic[0])), 477 CAST(unsigned long, FILE_MAGICSIZE)); 478 return -1; 479 } 480 481 if (action == FILE_COMPILE) { 482 map = apprentice_load(ms, fn, action); 483 if (map == NULL) 484 return -1; 485 return apprentice_compile(ms, map, fn); 486 } 487 488 #ifndef COMPILE_ONLY 489 map = apprentice_map(ms, fn); 490 if (map == NULL) { 491 if (ms->flags & MAGIC_CHECK) 492 file_magwarn(ms, "using regular magic file `%s'", fn); 493 map = apprentice_load(ms, fn, action); 494 if (map == NULL) 495 return -1; 496 } 497 498 for (i = 0; i < MAGIC_SETS; i++) { 499 if (add_mlist(ms->mlist[i], map, i) == -1) { 500 /* failed to add to any list, free explicitly */ 501 if (i == 0) 502 apprentice_unmap(map); 503 else 504 mlist_free_all(ms); 505 file_oomem(ms, sizeof(*ms->mlist[0])); 506 return -1; 507 } 508 } 509 510 if (action == FILE_LIST) { 511 for (i = 0; i < MAGIC_SETS; i++) { 512 printf("Set %" SIZE_T_FORMAT "u:\nBinary patterns:\n", 513 i); 514 apprentice_list(ms->mlist[i], BINTEST); 515 printf("Text patterns:\n"); 516 apprentice_list(ms->mlist[i], TEXTTEST); 517 } 518 } 519 return 0; 520 #else 521 return 0; 522 #endif /* COMPILE_ONLY */ 523 } 524 525 file_protected void 526 file_ms_free(struct magic_set *ms) 527 { 528 size_t i; 529 if (ms == NULL) 530 return; 531 for (i = 0; i < MAGIC_SETS; i++) 532 mlist_free(ms->mlist[i]); 533 free(ms->o.pbuf); 534 free(ms->o.buf); 535 free(ms->c.li); 536 free(ms->fnamebuf); 537 #ifdef USE_C_LOCALE 538 freelocale(ms->c_lc_ctype); 539 #endif 540 free(ms); 541 } 542 543 file_protected struct magic_set * 544 file_ms_alloc(int flags) 545 { 546 struct magic_set *ms; 547 size_t i, len; 548 549 if ((ms = CAST(struct magic_set *, calloc(CAST(size_t, 1u), 550 sizeof(*ms)))) == NULL) 551 return NULL; 552 553 if (magic_setflags(ms, flags) == -1) { 554 errno = EINVAL; 555 goto free; 556 } 557 558 ms->o.buf = ms->o.pbuf = NULL; 559 ms->o.blen = 0; 560 len = (ms->c.len = 10) * sizeof(*ms->c.li); 561 562 if ((ms->c.li = CAST(struct level_info *, malloc(len))) == NULL) 563 goto free; 564 565 ms->event_flags = 0; 566 ms->error = -1; 567 for (i = 0; i < MAGIC_SETS; i++) 568 ms->mlist[i] = NULL; 569 ms->fnamebuf = NULL; 570 ms->file = "unknown"; 571 ms->line = 0; 572 ms->magwarn = 0; 573 ms->indir_max = FILE_INDIR_MAX; 574 ms->name_max = FILE_NAME_MAX; 575 ms->elf_shnum_max = FILE_ELF_SHNUM_MAX; 576 ms->elf_shsize_max = FILE_ELF_SHSIZE_MAX; 577 ms->elf_phnum_max = FILE_ELF_PHNUM_MAX; 578 ms->elf_notes_max = FILE_ELF_NOTES_MAX; 579 ms->regex_max = FILE_REGEX_MAX; 580 ms->bytes_max = FILE_BYTES_MAX; 581 ms->encoding_max = FILE_ENCODING_MAX; 582 ms->magwarn_max = FILE_MAGWARN_MAX; 583 #ifdef USE_C_LOCALE 584 ms->c_lc_ctype = newlocale(LC_CTYPE_MASK, "C", 0); 585 assert(ms->c_lc_ctype != NULL); 586 #endif 587 return ms; 588 free: 589 free(ms); 590 return NULL; 591 } 592 593 file_private void 594 apprentice_unmap(struct magic_map *map) 595 { 596 size_t i; 597 char *p; 598 if (map == NULL) 599 return; 600 601 switch (map->type) { 602 case MAP_TYPE_USER: 603 break; 604 case MAP_TYPE_MALLOC: 605 p = CAST(char *, map->p); 606 for (i = 0; i < MAGIC_SETS; i++) { 607 char *b = RCAST(char *, map->magic[i]); 608 if (p != NULL && b >= p && b <= p + map->len) 609 continue; 610 free(b); 611 } 612 free(p); 613 break; 614 #ifdef QUICK 615 case MAP_TYPE_MMAP: 616 if (map->p && map->p != MAP_FAILED) 617 (void)munmap(map->p, map->len); 618 break; 619 #endif 620 default: 621 fprintf(stderr, "Bad map type %d", map->type); 622 abort(); 623 } 624 free(map); 625 } 626 627 file_private struct mlist * 628 mlist_alloc(void) 629 { 630 struct mlist *mlist; 631 if ((mlist = CAST(struct mlist *, calloc(1, sizeof(*mlist)))) == NULL) { 632 return NULL; 633 } 634 mlist->next = mlist->prev = mlist; 635 return mlist; 636 } 637 638 file_private void 639 mlist_free_all(struct magic_set *ms) 640 { 641 size_t i; 642 643 for (i = 0; i < MAGIC_SETS; i++) { 644 mlist_free(ms->mlist[i]); 645 ms->mlist[i] = NULL; 646 } 647 } 648 649 file_private void 650 mlist_free_one(struct mlist *ml) 651 { 652 size_t i; 653 654 if (ml->map) 655 apprentice_unmap(CAST(struct magic_map *, ml->map)); 656 657 for (i = 0; i < ml->nmagic; ++i) { 658 if (ml->magic_rxcomp[i]) { 659 file_regfree(ml->magic_rxcomp[i]); 660 free(ml->magic_rxcomp[i]); 661 ml->magic_rxcomp[i] = NULL; 662 } 663 } 664 free(ml->magic_rxcomp); 665 ml->magic_rxcomp = NULL; 666 free(ml); 667 } 668 669 file_private void 670 mlist_free(struct mlist *mlist) 671 { 672 struct mlist *ml, *next; 673 674 if (mlist == NULL) 675 return; 676 677 for (ml = mlist->next; ml != mlist;) { 678 next = ml->next; 679 mlist_free_one(ml); 680 ml = next; 681 } 682 mlist_free_one(mlist); 683 } 684 685 #ifndef COMPILE_ONLY 686 /* void **bufs: an array of compiled magic files */ 687 file_protected int 688 buffer_apprentice(struct magic_set *ms, struct magic **bufs, 689 size_t *sizes, size_t nbufs) 690 { 691 size_t i, j; 692 struct magic_map *map; 693 694 if (nbufs == 0) 695 return -1; 696 697 (void)file_reset(ms, 0); 698 699 init_file_tables(); 700 701 for (i = 0; i < MAGIC_SETS; i++) { 702 mlist_free(ms->mlist[i]); 703 if ((ms->mlist[i] = mlist_alloc()) == NULL) { 704 file_oomem(ms, sizeof(*ms->mlist[0])); 705 goto fail; 706 } 707 } 708 709 for (i = 0; i < nbufs; i++) { 710 map = apprentice_buf(ms, bufs[i], sizes[i]); 711 if (map == NULL) 712 goto fail; 713 714 for (j = 0; j < MAGIC_SETS; j++) { 715 if (add_mlist(ms->mlist[j], map, j) == -1) { 716 file_oomem(ms, sizeof(*ms->mlist[0])); 717 goto fail; 718 } 719 } 720 } 721 722 return 0; 723 fail: 724 mlist_free_all(ms); 725 return -1; 726 } 727 #endif 728 729 /* const char *fn: list of magic files and directories */ 730 file_protected int 731 file_apprentice(struct magic_set *ms, const char *fn, int action) 732 { 733 char *p; 734 int fileerr, errs = -1; 735 size_t i, j; 736 737 (void)file_reset(ms, 0); 738 739 if ((fn = magic_getpath(fn, action)) == NULL) 740 return -1; 741 742 init_file_tables(); 743 744 free(ms->fnamebuf); 745 ms->file = NULL; 746 if ((ms->fnamebuf = strdup(fn)) == NULL) { 747 file_oomem(ms, strlen(fn)); 748 return -1; 749 } 750 751 for (i = 0; i < MAGIC_SETS; i++) { 752 mlist_free(ms->mlist[i]); 753 if ((ms->mlist[i] = mlist_alloc()) == NULL) { 754 file_oomem(ms, sizeof(*ms->mlist[0])); 755 for (j = 0; j < i; j++) { 756 mlist_free(ms->mlist[j]); 757 ms->mlist[j] = NULL; 758 } 759 return -1; 760 } 761 } 762 fn = ms->fnamebuf; 763 764 while (fn) { 765 p = CCAST(char *, strchr(fn, PATHSEP)); 766 if (p) 767 *p++ = '\0'; 768 if (*fn == '\0') 769 break; 770 fileerr = apprentice_1(ms, fn, action); 771 errs = MAX(errs, fileerr); 772 fn = p; 773 } 774 775 if (errs == -1) { 776 for (i = 0; i < MAGIC_SETS; i++) { 777 mlist_free(ms->mlist[i]); 778 ms->mlist[i] = NULL; 779 } 780 file_error(ms, 0, "could not find any valid magic files!"); 781 return -1; 782 } 783 784 #if 0 785 /* 786 * Always leave the database loaded 787 */ 788 if (action == FILE_LOAD) 789 return 0; 790 791 for (i = 0; i < MAGIC_SETS; i++) { 792 mlist_free(ms->mlist[i]); 793 ms->mlist[i] = NULL; 794 } 795 #endif 796 797 switch (action) { 798 case FILE_LOAD: 799 case FILE_COMPILE: 800 case FILE_CHECK: 801 case FILE_LIST: 802 return 0; 803 default: 804 file_error(ms, 0, "Invalid action %d", action); 805 return -1; 806 } 807 } 808 809 /* 810 * Compute the real length of a magic expression, for the purposes 811 * of determining how "strong" a magic expression is (approximating 812 * how specific its matches are): 813 * - magic characters count 0 unless escaped. 814 * - [] expressions count 1 815 * - {} expressions count 0 816 * - regular characters or escaped magic characters count 1 817 * - 0 length expressions count as one 818 */ 819 file_private size_t 820 nonmagic(const char *str) 821 { 822 const char *p; 823 size_t rv = 0; 824 825 for (p = str; *p; p++) 826 switch (*p) { 827 case '\\': /* Escaped anything counts 1 */ 828 if (!*++p) 829 p--; 830 rv++; 831 continue; 832 case '?': /* Magic characters count 0 */ 833 case '*': 834 case '.': 835 case '+': 836 case '^': 837 case '$': 838 continue; 839 case '[': /* Bracketed expressions count 1 the ']' */ 840 while (*p && *p != ']') 841 p++; 842 p--; 843 continue; 844 case '{': /* Braced expressions count 0 */ 845 while (*p && *p != '}') 846 p++; 847 if (!*p) 848 p--; 849 continue; 850 default: /* Anything else counts 1 */ 851 rv++; 852 continue; 853 } 854 855 return rv == 0 ? 1 : rv; /* Return at least 1 */ 856 } 857 858 859 file_private size_t 860 typesize(int type) 861 { 862 switch (type) { 863 case FILE_BYTE: 864 return 1; 865 866 case FILE_SHORT: 867 case FILE_LESHORT: 868 case FILE_BESHORT: 869 case FILE_MSDOSDATE: 870 case FILE_BEMSDOSDATE: 871 case FILE_LEMSDOSDATE: 872 case FILE_MSDOSTIME: 873 case FILE_BEMSDOSTIME: 874 case FILE_LEMSDOSTIME: 875 return 2; 876 877 case FILE_LONG: 878 case FILE_LELONG: 879 case FILE_BELONG: 880 case FILE_MELONG: 881 return 4; 882 883 case FILE_DATE: 884 case FILE_LEDATE: 885 case FILE_BEDATE: 886 case FILE_MEDATE: 887 case FILE_LDATE: 888 case FILE_LELDATE: 889 case FILE_BELDATE: 890 case FILE_MELDATE: 891 case FILE_FLOAT: 892 case FILE_BEFLOAT: 893 case FILE_LEFLOAT: 894 case FILE_BEID3: 895 case FILE_LEID3: 896 return 4; 897 898 case FILE_QUAD: 899 case FILE_BEQUAD: 900 case FILE_LEQUAD: 901 case FILE_QDATE: 902 case FILE_LEQDATE: 903 case FILE_BEQDATE: 904 case FILE_QLDATE: 905 case FILE_LEQLDATE: 906 case FILE_BEQLDATE: 907 case FILE_QWDATE: 908 case FILE_LEQWDATE: 909 case FILE_BEQWDATE: 910 case FILE_DOUBLE: 911 case FILE_BEDOUBLE: 912 case FILE_LEDOUBLE: 913 case FILE_OFFSET: 914 case FILE_BEVARINT: 915 case FILE_LEVARINT: 916 return 8; 917 918 case FILE_LEGUID: 919 case FILE_BEGUID: 920 case FILE_GUID: 921 return 16; 922 923 default: 924 return FILE_BADSIZE; 925 } 926 } 927 928 /* 929 * Get weight of this magic entry, for sorting purposes. 930 */ 931 file_private ssize_t 932 apprentice_magic_strength_1(const struct magic *m) 933 { 934 #define MULT 10U 935 size_t ts, v; 936 ssize_t val = 2 * MULT; /* baseline strength */ 937 938 switch (m->type) { 939 case FILE_DEFAULT: /* make sure this sorts last */ 940 if (m->factor_op != FILE_FACTOR_OP_NONE) { 941 file_magwarn1("Unsupported factor_op in default %d", 942 m->factor_op); 943 } 944 return 0; 945 946 case FILE_BYTE: 947 case FILE_SHORT: 948 case FILE_LESHORT: 949 case FILE_BESHORT: 950 case FILE_LONG: 951 case FILE_LELONG: 952 case FILE_BELONG: 953 case FILE_MELONG: 954 case FILE_DATE: 955 case FILE_LEDATE: 956 case FILE_BEDATE: 957 case FILE_MEDATE: 958 case FILE_LDATE: 959 case FILE_LELDATE: 960 case FILE_BELDATE: 961 case FILE_MELDATE: 962 case FILE_FLOAT: 963 case FILE_BEFLOAT: 964 case FILE_LEFLOAT: 965 case FILE_QUAD: 966 case FILE_BEQUAD: 967 case FILE_LEQUAD: 968 case FILE_QDATE: 969 case FILE_LEQDATE: 970 case FILE_BEQDATE: 971 case FILE_QLDATE: 972 case FILE_LEQLDATE: 973 case FILE_BEQLDATE: 974 case FILE_QWDATE: 975 case FILE_LEQWDATE: 976 case FILE_BEQWDATE: 977 case FILE_DOUBLE: 978 case FILE_BEDOUBLE: 979 case FILE_LEDOUBLE: 980 case FILE_BEVARINT: 981 case FILE_LEVARINT: 982 case FILE_GUID: 983 case FILE_LEGUID: 984 case FILE_BEGUID: 985 case FILE_BEID3: 986 case FILE_LEID3: 987 case FILE_OFFSET: 988 case FILE_MSDOSDATE: 989 case FILE_BEMSDOSDATE: 990 case FILE_LEMSDOSDATE: 991 case FILE_MSDOSTIME: 992 case FILE_BEMSDOSTIME: 993 case FILE_LEMSDOSTIME: 994 ts = typesize(m->type); 995 if (ts == FILE_BADSIZE) { 996 (void)fprintf(stderr, "Bad size for type %d\n", 997 m->type); 998 abort(); 999 } 1000 val += ts * MULT; 1001 break; 1002 1003 case FILE_PSTRING: 1004 case FILE_STRING: 1005 case FILE_OCTAL: 1006 val += m->vallen * MULT; 1007 break; 1008 1009 case FILE_BESTRING16: 1010 case FILE_LESTRING16: 1011 val += m->vallen * MULT / 2; 1012 break; 1013 1014 case FILE_SEARCH: 1015 if (m->vallen == 0) 1016 break; 1017 val += m->vallen * MAX(MULT / m->vallen, 1); 1018 break; 1019 1020 case FILE_REGEX: 1021 v = nonmagic(m->value.s); 1022 val += v * MAX(MULT / v, 1); 1023 break; 1024 1025 case FILE_INDIRECT: 1026 case FILE_NAME: 1027 case FILE_USE: 1028 case FILE_CLEAR: 1029 break; 1030 1031 case FILE_DER: 1032 val += MULT; 1033 break; 1034 1035 default: 1036 (void)fprintf(stderr, "Bad type %d\n", m->type); 1037 abort(); 1038 } 1039 1040 switch (m->reln) { 1041 case 'x': /* matches anything penalize */ 1042 case '!': /* matches almost anything penalize */ 1043 val = 0; 1044 break; 1045 1046 case '=': /* Exact match, prefer */ 1047 val += MULT; 1048 break; 1049 1050 case '>': 1051 case '<': /* comparison match reduce strength */ 1052 val -= 2 * MULT; 1053 break; 1054 1055 case '^': 1056 case '&': /* masking bits, we could count them too */ 1057 val -= MULT; 1058 break; 1059 1060 default: 1061 (void)fprintf(stderr, "Bad relation %c\n", m->reln); 1062 abort(); 1063 } 1064 1065 return val; 1066 } 1067 1068 1069 /*ARGSUSED*/ 1070 file_protected size_t 1071 file_magic_strength(const struct magic *m, 1072 size_t nmagic __attribute__((__unused__))) 1073 { 1074 ssize_t val = apprentice_magic_strength_1(m); 1075 1076 #ifdef notyet 1077 if (m->desc[0] == '\0') { 1078 size_t i; 1079 /* 1080 * Magic entries with no description get their continuations 1081 * added 1082 */ 1083 for (i = 1; m[i].cont_level != 0 && i < MIN(nmagic, 3); i++) { 1084 ssize_t v = apprentice_magic_strength_1(&m[i]) >> 1085 (i + 1); 1086 val += v; 1087 if (m[i].desc[0] != '\0') 1088 break; 1089 } 1090 } 1091 #endif 1092 1093 switch (m->factor_op) { 1094 case FILE_FACTOR_OP_NONE: 1095 break; 1096 case FILE_FACTOR_OP_PLUS: 1097 val += m->factor; 1098 break; 1099 case FILE_FACTOR_OP_MINUS: 1100 val -= m->factor; 1101 break; 1102 case FILE_FACTOR_OP_TIMES: 1103 val *= m->factor; 1104 break; 1105 case FILE_FACTOR_OP_DIV: 1106 val /= m->factor; 1107 break; 1108 default: 1109 (void)fprintf(stderr, "Bad factor_op %u\n", m->factor_op); 1110 abort(); 1111 } 1112 1113 if (val <= 0) /* ensure we only return 0 for FILE_DEFAULT */ 1114 val = 1; 1115 1116 #ifndef notyet 1117 /* 1118 * Magic entries with no description get a bonus because they depend 1119 * on subsequent magic entries to print something. 1120 */ 1121 if (m->desc[0] == '\0') 1122 val++; 1123 #endif 1124 1125 return val; 1126 } 1127 1128 /* 1129 * Sort callback for sorting entries by "strength" (basically length) 1130 */ 1131 file_private int 1132 apprentice_sort(const void *a, const void *b) 1133 { 1134 const struct magic_entry *ma = CAST(const struct magic_entry *, a); 1135 const struct magic_entry *mb = CAST(const struct magic_entry *, b); 1136 size_t sa = file_magic_strength(ma->mp, ma->cont_count); 1137 size_t sb = file_magic_strength(mb->mp, mb->cont_count); 1138 if (sa == sb) { 1139 struct magic mpa = *ma->mp; 1140 struct magic mpb = *mb->mp; 1141 mpa.lineno = mpb.lineno = 0; 1142 int x = memcmp(&mpa, &mpb, sizeof(mpa)); 1143 if (x == 0) { 1144 // Don't warn for DER 1145 if (mpa.type == FILE_DER) 1146 return 0; 1147 file_magwarn1("Duplicate magic entry `%s'", 1148 ma->mp->desc); 1149 #ifndef COMPILE_ONLY 1150 file_mdump(ma->mp); 1151 file_mdump(mb->mp); 1152 #endif 1153 return 0; 1154 } 1155 return x > 0 ? -1 : 1; 1156 } 1157 return sa > sb ? -1 : 1; 1158 } 1159 1160 /* 1161 * Shows sorted patterns list in the order which is used for the matching 1162 */ 1163 file_private void 1164 apprentice_list(struct mlist *mlist, int mode) 1165 { 1166 uint32_t magindex, descindex, mimeindex, lineindex; 1167 struct mlist *ml; 1168 for (ml = mlist->next; ml != mlist; ml = ml->next) { 1169 for (magindex = 0; magindex < ml->nmagic; magindex++) { 1170 struct magic *m = &ml->magic[magindex]; 1171 if ((m->flag & mode) != mode) { 1172 /* Skip sub-tests */ 1173 while (magindex + 1 < ml->nmagic && 1174 ml->magic[magindex + 1].cont_level != 0) 1175 ++magindex; 1176 continue; /* Skip to next top-level test*/ 1177 } 1178 1179 /* 1180 * Try to iterate over the tree until we find item with 1181 * description/mimetype. 1182 */ 1183 lineindex = descindex = mimeindex = magindex; 1184 for (; magindex + 1 < ml->nmagic && 1185 ml->magic[magindex + 1].cont_level != 0; 1186 magindex++) { 1187 uint32_t mi = magindex + 1; 1188 if (*ml->magic[descindex].desc == '\0' 1189 && *ml->magic[mi].desc) 1190 descindex = mi; 1191 if (*ml->magic[mimeindex].mimetype == '\0' 1192 && *ml->magic[mi].mimetype) 1193 mimeindex = mi; 1194 } 1195 1196 printf("Strength = %3" SIZE_T_FORMAT "u@%u: %s [%s]\n", 1197 file_magic_strength(m, ml->nmagic - magindex), 1198 ml->magic[lineindex].lineno, 1199 ml->magic[descindex].desc, 1200 ml->magic[mimeindex].mimetype); 1201 } 1202 } 1203 } 1204 1205 file_private void 1206 set_test_type(struct magic *mstart, struct magic *m) 1207 { 1208 switch (m->type) { 1209 case FILE_BYTE: 1210 case FILE_SHORT: 1211 case FILE_LONG: 1212 case FILE_DATE: 1213 case FILE_BESHORT: 1214 case FILE_BELONG: 1215 case FILE_BEDATE: 1216 case FILE_LESHORT: 1217 case FILE_LELONG: 1218 case FILE_LEDATE: 1219 case FILE_LDATE: 1220 case FILE_BELDATE: 1221 case FILE_LELDATE: 1222 case FILE_MEDATE: 1223 case FILE_MELDATE: 1224 case FILE_MELONG: 1225 case FILE_QUAD: 1226 case FILE_LEQUAD: 1227 case FILE_BEQUAD: 1228 case FILE_QDATE: 1229 case FILE_LEQDATE: 1230 case FILE_BEQDATE: 1231 case FILE_QLDATE: 1232 case FILE_LEQLDATE: 1233 case FILE_BEQLDATE: 1234 case FILE_QWDATE: 1235 case FILE_LEQWDATE: 1236 case FILE_BEQWDATE: 1237 case FILE_FLOAT: 1238 case FILE_BEFLOAT: 1239 case FILE_LEFLOAT: 1240 case FILE_DOUBLE: 1241 case FILE_BEDOUBLE: 1242 case FILE_LEDOUBLE: 1243 case FILE_BEVARINT: 1244 case FILE_LEVARINT: 1245 case FILE_DER: 1246 case FILE_GUID: 1247 case FILE_LEGUID: 1248 case FILE_BEGUID: 1249 case FILE_OFFSET: 1250 case FILE_MSDOSDATE: 1251 case FILE_BEMSDOSDATE: 1252 case FILE_LEMSDOSDATE: 1253 case FILE_MSDOSTIME: 1254 case FILE_BEMSDOSTIME: 1255 case FILE_LEMSDOSTIME: 1256 case FILE_OCTAL: 1257 mstart->flag |= BINTEST; 1258 break; 1259 case FILE_STRING: 1260 case FILE_PSTRING: 1261 case FILE_BESTRING16: 1262 case FILE_LESTRING16: 1263 case FILE_REGEX: 1264 case FILE_SEARCH: 1265 /* Check for override */ 1266 if (mstart->str_flags & STRING_BINTEST) 1267 mstart->flag |= BINTEST; 1268 if (mstart->str_flags & STRING_TEXTTEST) 1269 mstart->flag |= TEXTTEST; 1270 1271 if (mstart->flag & (TEXTTEST|BINTEST)) 1272 break; 1273 1274 /* 1275 * XXX: Compatibility: For string types assume binary match 1276 * in reality it is better in the long term to change all 1277 * the magic to be string/b where appropriate 1278 */ 1279 if (m->type != FILE_REGEX && m->type != FILE_SEARCH) { 1280 mstart->flag |= BINTEST; 1281 break; 1282 } 1283 1284 /* binary test if pattern is not text */ 1285 if (file_looks_utf8(m->value.us, CAST(size_t, m->vallen), NULL, 1286 NULL) <= 0) 1287 mstart->flag |= BINTEST; 1288 else 1289 mstart->flag |= TEXTTEST; 1290 break; 1291 case FILE_DEFAULT: 1292 /* can't deduce anything; we shouldn't see this at the 1293 top level anyway */ 1294 break; 1295 case FILE_INVALID: 1296 default: 1297 /* invalid search type, but no need to complain here */ 1298 break; 1299 } 1300 } 1301 1302 file_private int 1303 addentry(struct magic_set *ms, struct magic_entry *me, 1304 struct magic_entry_set *mset) 1305 { 1306 size_t i = me->mp->type == FILE_NAME ? 1 : 0; 1307 if (mset[i].me == NULL || mset[i].count == mset[i].max) { 1308 struct magic_entry *mp; 1309 1310 size_t incr = mset[i].max + ALLOC_INCR; 1311 if ((mp = CAST(struct magic_entry *, 1312 realloc(mset[i].me, sizeof(*mp) * incr))) == 1313 NULL) { 1314 file_oomem(ms, sizeof(*mp) * incr); 1315 return -1; 1316 } 1317 (void)memset(&mp[mset[i].count], 0, sizeof(*mp) * 1318 ALLOC_INCR); 1319 mset[i].me = mp; 1320 mset[i].max = CAST(uint32_t, incr); 1321 assert(mset[i].max == incr); 1322 } 1323 mset[i].me[mset[i].count++] = *me; 1324 memset(me, 0, sizeof(*me)); 1325 return 0; 1326 } 1327 1328 /* 1329 * Load and parse one file. 1330 */ 1331 file_private void 1332 load_1(struct magic_set *ms, int action, const char *fn, int *errs, 1333 struct magic_entry_set *mset) 1334 { 1335 size_t lineno = 0, llen = 0; 1336 char *line = NULL; 1337 ssize_t len; 1338 struct magic_entry me; 1339 1340 FILE *f = fopen(ms->file = fn, "r"); 1341 if (f == NULL) { 1342 if (errno != ENOENT) 1343 file_error(ms, errno, "cannot read magic file `%s'", 1344 fn); 1345 (*errs)++; 1346 return; 1347 } 1348 1349 memset(&me, 0, sizeof(me)); 1350 /* read and parse this file */ 1351 for (ms->line = 1; (len = getline(&line, &llen, f)) != -1; 1352 ms->line++) { 1353 if (ms->magwarn >= ms->magwarn_max) 1354 break; 1355 if (len == 0) /* null line, garbage, etc */ 1356 continue; 1357 if (line[len - 1] == '\n') { 1358 lineno++; 1359 line[len - 1] = '\0'; /* delete newline */ 1360 } 1361 switch (line[0]) { 1362 case '\0': /* empty, do not parse */ 1363 case '#': /* comment, do not parse */ 1364 continue; 1365 case '!': 1366 if (line[1] == ':') { 1367 size_t i; 1368 1369 for (i = 0; bang[i].name != NULL; i++) { 1370 if (CAST(size_t, len - 2) > bang[i].len && 1371 memcmp(bang[i].name, line + 2, 1372 bang[i].len) == 0) 1373 break; 1374 } 1375 if (bang[i].name == NULL) { 1376 file_error(ms, 0, 1377 "Unknown !: entry `%s'", line); 1378 (*errs)++; 1379 continue; 1380 } 1381 if (me.mp == NULL) { 1382 file_error(ms, 0, 1383 "No current entry for :!%s type", 1384 bang[i].name); 1385 (*errs)++; 1386 continue; 1387 } 1388 if ((*bang[i].fun)(ms, &me, 1389 line + bang[i].len + 2, 1390 len - bang[i].len - 2) != 0) { 1391 (*errs)++; 1392 continue; 1393 } 1394 continue; 1395 } 1396 /*FALLTHROUGH*/ 1397 default: 1398 again: 1399 switch (parse(ms, &me, fn, line, llen, lineno, action)) { 1400 case 0: 1401 continue; 1402 case 1: 1403 (void)addentry(ms, &me, mset); 1404 goto again; 1405 default: 1406 (*errs)++; 1407 break; 1408 } 1409 } 1410 } 1411 if (me.mp) 1412 (void)addentry(ms, &me, mset); 1413 free(line); 1414 (void)fclose(f); 1415 } 1416 1417 /* 1418 * parse a file or directory of files 1419 * const char *fn: name of magic file or directory 1420 */ 1421 file_private int 1422 cmpstrp(const void *p1, const void *p2) 1423 { 1424 return strcmp(*RCAST(char *const *, p1), *RCAST(char *const *, p2)); 1425 } 1426 1427 1428 file_private uint32_t 1429 set_text_binary(struct magic_set *ms, struct magic_entry *me, uint32_t nme, 1430 uint32_t starttest) 1431 { 1432 static const char text[] = "text"; 1433 static const char binary[] = "binary"; 1434 static const size_t len = sizeof(text); 1435 1436 uint32_t i = starttest; 1437 1438 do { 1439 set_test_type(me[starttest].mp, me[i].mp); 1440 if ((ms->flags & MAGIC_DEBUG) == 0) 1441 continue; 1442 (void)fprintf(stderr, "%s%s%s: %s\n", 1443 me[i].mp->mimetype, 1444 me[i].mp->mimetype[0] == '\0' ? "" : "; ", 1445 me[i].mp->desc[0] ? me[i].mp->desc : "(no description)", 1446 me[i].mp->flag & BINTEST ? binary : text); 1447 if (me[i].mp->flag & BINTEST) { 1448 char *p = strstr(me[i].mp->desc, text); 1449 if (p && (p == me[i].mp->desc || 1450 isspace(CAST(unsigned char, p[-1]))) && 1451 (p + len - me[i].mp->desc == MAXstring 1452 || (p[len] == '\0' || 1453 isspace(CAST(unsigned char, p[len]))))) 1454 (void)fprintf(stderr, "*** Possible " 1455 "binary test for text type\n"); 1456 } 1457 } while (++i < nme && me[i].mp->cont_level != 0); 1458 return i; 1459 } 1460 1461 file_private void 1462 set_last_default(struct magic_set *ms, struct magic_entry *me, uint32_t nme) 1463 { 1464 uint32_t i; 1465 for (i = 0; i < nme; i++) { 1466 if (me[i].mp->cont_level == 0 && 1467 me[i].mp->type == FILE_DEFAULT) { 1468 while (++i < nme) 1469 if (me[i].mp->cont_level == 0) 1470 break; 1471 if (i != nme) { 1472 /* XXX - Ugh! */ 1473 ms->line = me[i].mp->lineno; 1474 file_magwarn(ms, 1475 "level 0 \"default\" did not sort last"); 1476 } 1477 return; 1478 } 1479 } 1480 } 1481 1482 file_private int 1483 coalesce_entries(struct magic_set *ms, struct magic_entry *me, uint32_t nme, 1484 struct magic **ma, uint32_t *nma) 1485 { 1486 uint32_t i; 1487 size_t mentrycount = 0; 1488 size_t slen; 1489 1490 for (i = 0; i < nme; i++) 1491 mentrycount += me[i].cont_count; 1492 1493 if (mentrycount > UINT32_MAX / sizeof(**ma)) { 1494 file_error(ms, 0, "too many magic entries (%zu)", mentrycount); 1495 return -1; 1496 } 1497 1498 if (mentrycount == 0) { 1499 *ma = NULL; 1500 *nma = 0; 1501 return 0; 1502 } 1503 1504 slen = sizeof(**ma) * mentrycount; 1505 if ((*ma = CAST(struct magic *, malloc(slen))) == NULL) { 1506 file_oomem(ms, slen); 1507 return -1; 1508 } 1509 1510 mentrycount = 0; 1511 for (i = 0; i < nme; i++) { 1512 (void)memcpy(*ma + mentrycount, me[i].mp, 1513 me[i].cont_count * sizeof(**ma)); 1514 mentrycount += me[i].cont_count; 1515 } 1516 *nma = mentrycount; 1517 return 0; 1518 } 1519 1520 file_private void 1521 magic_entry_free(struct magic_entry *me, uint32_t nme) 1522 { 1523 uint32_t i; 1524 if (me == NULL) 1525 return; 1526 for (i = 0; i < nme; i++) 1527 free(me[i].mp); 1528 free(me); 1529 } 1530 1531 file_private struct magic_map * 1532 apprentice_load(struct magic_set *ms, const char *fn, int action) 1533 { 1534 int errs = 0; 1535 uint32_t i, j; 1536 size_t files = 0, maxfiles = 0; 1537 char **filearr = NULL, *mfn; 1538 struct stat st; 1539 struct magic_map *map; 1540 struct magic_entry_set mset[MAGIC_SETS]; 1541 DIR *dir; 1542 struct dirent *d; 1543 1544 memset(mset, 0, sizeof(mset)); 1545 ms->flags |= MAGIC_CHECK; /* Enable checks for parsed files */ 1546 1547 1548 if ((map = CAST(struct magic_map *, calloc(1, sizeof(*map)))) == NULL) 1549 { 1550 file_oomem(ms, sizeof(*map)); 1551 return NULL; 1552 } 1553 map->type = MAP_TYPE_MALLOC; 1554 1555 /* print silly verbose header for USG compat. */ 1556 if (action == FILE_CHECK) 1557 (void)fprintf(stderr, "%s\n", usg_hdr); 1558 1559 /* load directory or file */ 1560 if (stat(fn, &st) == 0 && S_ISDIR(st.st_mode)) { 1561 dir = opendir(fn); 1562 if (!dir) { 1563 errs++; 1564 goto out; 1565 } 1566 while ((d = readdir(dir)) != NULL) { 1567 if (d->d_name[0] == '.') 1568 continue; 1569 if (asprintf(&mfn, "%s/%s", fn, d->d_name) < 0) { 1570 file_oomem(ms, 1571 strlen(fn) + strlen(d->d_name) + 2); 1572 errs++; 1573 closedir(dir); 1574 goto out; 1575 } 1576 if (stat(mfn, &st) == -1 || !S_ISREG(st.st_mode)) { 1577 free(mfn); 1578 continue; 1579 } 1580 if (files >= maxfiles) { 1581 size_t mlen; 1582 char **nfilearr; 1583 maxfiles = (maxfiles + 1) * 2; 1584 mlen = maxfiles * sizeof(*filearr); 1585 if ((nfilearr = CAST(char **, 1586 realloc(filearr, mlen))) == NULL) { 1587 file_oomem(ms, mlen); 1588 free(mfn); 1589 closedir(dir); 1590 errs++; 1591 goto out; 1592 } 1593 filearr = nfilearr; 1594 } 1595 filearr[files++] = mfn; 1596 } 1597 closedir(dir); 1598 if (filearr) { 1599 qsort(filearr, files, sizeof(*filearr), cmpstrp); 1600 for (i = 0; i < files; i++) { 1601 load_1(ms, action, filearr[i], &errs, mset); 1602 free(filearr[i]); 1603 } 1604 free(filearr); 1605 filearr = NULL; 1606 } 1607 } else 1608 load_1(ms, action, fn, &errs, mset); 1609 if (errs) 1610 goto out; 1611 1612 for (j = 0; j < MAGIC_SETS; j++) { 1613 /* Set types of tests */ 1614 for (i = 0; i < mset[j].count; ) { 1615 if (mset[j].me[i].mp->cont_level != 0) { 1616 i++; 1617 continue; 1618 } 1619 i = set_text_binary(ms, mset[j].me, mset[j].count, i); 1620 } 1621 if (mset[j].me) 1622 qsort(mset[j].me, mset[j].count, sizeof(*mset[0].me), 1623 apprentice_sort); 1624 1625 /* 1626 * Make sure that any level 0 "default" line is last 1627 * (if one exists). 1628 */ 1629 set_last_default(ms, mset[j].me, mset[j].count); 1630 1631 /* coalesce per file arrays into a single one, if needed */ 1632 if (mset[j].count == 0) 1633 continue; 1634 1635 if (coalesce_entries(ms, mset[j].me, mset[j].count, 1636 &map->magic[j], &map->nmagic[j]) == -1) { 1637 errs++; 1638 goto out; 1639 } 1640 } 1641 1642 out: 1643 free(filearr); 1644 for (j = 0; j < MAGIC_SETS; j++) 1645 magic_entry_free(mset[j].me, mset[j].count); 1646 1647 if (errs) { 1648 apprentice_unmap(map); 1649 return NULL; 1650 } 1651 return map; 1652 } 1653 1654 /* 1655 * extend the sign bit if the comparison is to be signed 1656 */ 1657 file_protected uint64_t 1658 file_signextend(struct magic_set *ms, struct magic *m, uint64_t v) 1659 { 1660 if (!(m->flag & UNSIGNED)) { 1661 switch(m->type) { 1662 /* 1663 * Do not remove the casts below. They are 1664 * vital. When later compared with the data, 1665 * the sign extension must have happened. 1666 */ 1667 case FILE_BYTE: 1668 v = CAST(signed char, v); 1669 break; 1670 case FILE_SHORT: 1671 case FILE_BESHORT: 1672 case FILE_LESHORT: 1673 v = CAST(short, v); 1674 break; 1675 case FILE_DATE: 1676 case FILE_BEDATE: 1677 case FILE_LEDATE: 1678 case FILE_MEDATE: 1679 case FILE_LDATE: 1680 case FILE_BELDATE: 1681 case FILE_LELDATE: 1682 case FILE_MELDATE: 1683 case FILE_LONG: 1684 case FILE_BELONG: 1685 case FILE_LELONG: 1686 case FILE_MELONG: 1687 case FILE_FLOAT: 1688 case FILE_BEFLOAT: 1689 case FILE_LEFLOAT: 1690 case FILE_MSDOSDATE: 1691 case FILE_BEMSDOSDATE: 1692 case FILE_LEMSDOSDATE: 1693 case FILE_MSDOSTIME: 1694 case FILE_BEMSDOSTIME: 1695 case FILE_LEMSDOSTIME: 1696 v = CAST(int32_t, v); 1697 break; 1698 case FILE_QUAD: 1699 case FILE_BEQUAD: 1700 case FILE_LEQUAD: 1701 case FILE_QDATE: 1702 case FILE_QLDATE: 1703 case FILE_QWDATE: 1704 case FILE_BEQDATE: 1705 case FILE_BEQLDATE: 1706 case FILE_BEQWDATE: 1707 case FILE_LEQDATE: 1708 case FILE_LEQLDATE: 1709 case FILE_LEQWDATE: 1710 case FILE_DOUBLE: 1711 case FILE_BEDOUBLE: 1712 case FILE_LEDOUBLE: 1713 case FILE_OFFSET: 1714 case FILE_BEVARINT: 1715 case FILE_LEVARINT: 1716 v = CAST(int64_t, v); 1717 break; 1718 case FILE_STRING: 1719 case FILE_PSTRING: 1720 case FILE_BESTRING16: 1721 case FILE_LESTRING16: 1722 case FILE_REGEX: 1723 case FILE_SEARCH: 1724 case FILE_DEFAULT: 1725 case FILE_INDIRECT: 1726 case FILE_NAME: 1727 case FILE_USE: 1728 case FILE_CLEAR: 1729 case FILE_DER: 1730 case FILE_GUID: 1731 case FILE_LEGUID: 1732 case FILE_BEGUID: 1733 case FILE_OCTAL: 1734 break; 1735 default: 1736 if (ms->flags & MAGIC_CHECK) 1737 file_magwarn(ms, "cannot happen: m->type=%d\n", 1738 m->type); 1739 return FILE_BADSIZE; 1740 } 1741 } 1742 return v; 1743 } 1744 1745 file_private int 1746 string_modifier_check(struct magic_set *ms, struct magic *m) 1747 { 1748 if ((ms->flags & MAGIC_CHECK) == 0) 1749 return 0; 1750 1751 if ((m->type != FILE_REGEX || (m->str_flags & REGEX_LINE_COUNT) == 0) && 1752 (m->type != FILE_PSTRING && (m->str_flags & PSTRING_LEN) != 0)) { 1753 file_magwarn(ms, 1754 "'/BHhLl' modifiers are only allowed for pascal strings\n"); 1755 return -1; 1756 } 1757 switch (m->type) { 1758 case FILE_BESTRING16: 1759 case FILE_LESTRING16: 1760 if (m->str_flags != 0) { 1761 file_magwarn(ms, 1762 "no modifiers allowed for 16-bit strings\n"); 1763 return -1; 1764 } 1765 break; 1766 case FILE_STRING: 1767 case FILE_PSTRING: 1768 if ((m->str_flags & REGEX_OFFSET_START) != 0) { 1769 file_magwarn(ms, 1770 "'/%c' only allowed on regex and search\n", 1771 CHAR_REGEX_OFFSET_START); 1772 return -1; 1773 } 1774 break; 1775 case FILE_SEARCH: 1776 if (m->str_range == 0) { 1777 file_magwarn(ms, 1778 "missing range; defaulting to %d\n", 1779 STRING_DEFAULT_RANGE); 1780 m->str_range = STRING_DEFAULT_RANGE; 1781 return -1; 1782 } 1783 break; 1784 case FILE_REGEX: 1785 if ((m->str_flags & STRING_COMPACT_WHITESPACE) != 0) { 1786 file_magwarn(ms, "'/%c' not allowed on regex\n", 1787 CHAR_COMPACT_WHITESPACE); 1788 return -1; 1789 } 1790 if ((m->str_flags & STRING_COMPACT_OPTIONAL_WHITESPACE) != 0) { 1791 file_magwarn(ms, "'/%c' not allowed on regex\n", 1792 CHAR_COMPACT_OPTIONAL_WHITESPACE); 1793 return -1; 1794 } 1795 break; 1796 default: 1797 file_magwarn(ms, "coding error: m->type=%d\n", 1798 m->type); 1799 return -1; 1800 } 1801 return 0; 1802 } 1803 1804 file_private int 1805 get_op(char c) 1806 { 1807 switch (c) { 1808 case '&': 1809 return FILE_OPAND; 1810 case '|': 1811 return FILE_OPOR; 1812 case '^': 1813 return FILE_OPXOR; 1814 case '+': 1815 return FILE_OPADD; 1816 case '-': 1817 return FILE_OPMINUS; 1818 case '*': 1819 return FILE_OPMULTIPLY; 1820 case '/': 1821 return FILE_OPDIVIDE; 1822 case '%': 1823 return FILE_OPMODULO; 1824 default: 1825 return -1; 1826 } 1827 } 1828 1829 #ifdef ENABLE_CONDITIONALS 1830 file_private int 1831 get_cond(const char *l, const char **t) 1832 { 1833 static const struct cond_tbl_s { 1834 char name[8]; 1835 size_t len; 1836 int cond; 1837 } cond_tbl[] = { 1838 { "if", 2, COND_IF }, 1839 { "elif", 4, COND_ELIF }, 1840 { "else", 4, COND_ELSE }, 1841 { "", 0, COND_NONE }, 1842 }; 1843 const struct cond_tbl_s *p; 1844 1845 for (p = cond_tbl; p->len; p++) { 1846 if (strncmp(l, p->name, p->len) == 0 && 1847 isspace(CAST(unsigned char, l[p->len]))) { 1848 if (t) 1849 *t = l + p->len; 1850 break; 1851 } 1852 } 1853 return p->cond; 1854 } 1855 1856 file_private int 1857 check_cond(struct magic_set *ms, int cond, uint32_t cont_level) 1858 { 1859 int last_cond; 1860 last_cond = ms->c.li[cont_level].last_cond; 1861 1862 switch (cond) { 1863 case COND_IF: 1864 if (last_cond != COND_NONE && last_cond != COND_ELIF) { 1865 if (ms->flags & MAGIC_CHECK) 1866 file_magwarn(ms, "syntax error: `if'"); 1867 return -1; 1868 } 1869 last_cond = COND_IF; 1870 break; 1871 1872 case COND_ELIF: 1873 if (last_cond != COND_IF && last_cond != COND_ELIF) { 1874 if (ms->flags & MAGIC_CHECK) 1875 file_magwarn(ms, "syntax error: `elif'"); 1876 return -1; 1877 } 1878 last_cond = COND_ELIF; 1879 break; 1880 1881 case COND_ELSE: 1882 if (last_cond != COND_IF && last_cond != COND_ELIF) { 1883 if (ms->flags & MAGIC_CHECK) 1884 file_magwarn(ms, "syntax error: `else'"); 1885 return -1; 1886 } 1887 last_cond = COND_NONE; 1888 break; 1889 1890 case COND_NONE: 1891 last_cond = COND_NONE; 1892 break; 1893 } 1894 1895 ms->c.li[cont_level].last_cond = last_cond; 1896 return 0; 1897 } 1898 #endif /* ENABLE_CONDITIONALS */ 1899 1900 file_private int 1901 parse_indirect_modifier(struct magic_set *ms, struct magic *m, const char **lp) 1902 { 1903 const char *l = *lp; 1904 1905 while (!isspace(CAST(unsigned char, *++l))) 1906 switch (*l) { 1907 case CHAR_INDIRECT_RELATIVE: 1908 m->str_flags |= INDIRECT_RELATIVE; 1909 break; 1910 default: 1911 if (ms->flags & MAGIC_CHECK) 1912 file_magwarn(ms, "indirect modifier `%c' " 1913 "invalid", *l); 1914 *lp = l; 1915 return -1; 1916 } 1917 *lp = l; 1918 return 0; 1919 } 1920 1921 file_private void 1922 parse_op_modifier(struct magic_set *ms, struct magic *m, const char **lp, 1923 int op) 1924 { 1925 const char *l = *lp; 1926 char *t; 1927 uint64_t val; 1928 1929 ++l; 1930 m->mask_op |= op; 1931 val = CAST(uint64_t, strtoull(l, &t, 0)); 1932 l = t; 1933 m->num_mask = file_signextend(ms, m, val); 1934 eatsize(&l); 1935 *lp = l; 1936 } 1937 1938 file_private int 1939 parse_string_modifier(struct magic_set *ms, struct magic *m, const char **lp) 1940 { 1941 const char *l = *lp; 1942 char *t; 1943 int have_range = 0; 1944 1945 while (!isspace(CAST(unsigned char, *++l))) { 1946 switch (*l) { 1947 case '0': case '1': case '2': 1948 case '3': case '4': case '5': 1949 case '6': case '7': case '8': 1950 case '9': 1951 if (have_range && (ms->flags & MAGIC_CHECK)) 1952 file_magwarn(ms, "multiple ranges"); 1953 have_range = 1; 1954 m->str_range = CAST(uint32_t, strtoul(l, &t, 0)); 1955 if (m->str_range == 0) 1956 file_magwarn(ms, "zero range"); 1957 l = t - 1; 1958 break; 1959 case CHAR_COMPACT_WHITESPACE: 1960 m->str_flags |= STRING_COMPACT_WHITESPACE; 1961 break; 1962 case CHAR_COMPACT_OPTIONAL_WHITESPACE: 1963 m->str_flags |= STRING_COMPACT_OPTIONAL_WHITESPACE; 1964 break; 1965 case CHAR_IGNORE_LOWERCASE: 1966 m->str_flags |= STRING_IGNORE_LOWERCASE; 1967 break; 1968 case CHAR_IGNORE_UPPERCASE: 1969 m->str_flags |= STRING_IGNORE_UPPERCASE; 1970 break; 1971 case CHAR_REGEX_OFFSET_START: 1972 m->str_flags |= REGEX_OFFSET_START; 1973 break; 1974 case CHAR_BINTEST: 1975 m->str_flags |= STRING_BINTEST; 1976 break; 1977 case CHAR_TEXTTEST: 1978 m->str_flags |= STRING_TEXTTEST; 1979 break; 1980 case CHAR_TRIM: 1981 m->str_flags |= STRING_TRIM; 1982 break; 1983 case CHAR_FULL_WORD: 1984 m->str_flags |= STRING_FULL_WORD; 1985 break; 1986 case CHAR_PSTRING_1_LE: 1987 #define SET_LENGTH(a) m->str_flags = (m->str_flags & ~PSTRING_LEN) | (a) 1988 if (m->type != FILE_PSTRING) 1989 goto bad; 1990 SET_LENGTH(PSTRING_1_LE); 1991 break; 1992 case CHAR_PSTRING_2_BE: 1993 if (m->type != FILE_PSTRING) 1994 goto bad; 1995 SET_LENGTH(PSTRING_2_BE); 1996 break; 1997 case CHAR_PSTRING_2_LE: 1998 if (m->type != FILE_PSTRING) 1999 goto bad; 2000 SET_LENGTH(PSTRING_2_LE); 2001 break; 2002 case CHAR_PSTRING_4_BE: 2003 if (m->type != FILE_PSTRING) 2004 goto bad; 2005 SET_LENGTH(PSTRING_4_BE); 2006 break; 2007 case CHAR_PSTRING_4_LE: 2008 switch (m->type) { 2009 case FILE_PSTRING: 2010 case FILE_REGEX: 2011 break; 2012 default: 2013 goto bad; 2014 } 2015 SET_LENGTH(PSTRING_4_LE); 2016 break; 2017 case CHAR_PSTRING_LENGTH_INCLUDES_ITSELF: 2018 if (m->type != FILE_PSTRING) 2019 goto bad; 2020 m->str_flags |= PSTRING_LENGTH_INCLUDES_ITSELF; 2021 break; 2022 default: 2023 bad: 2024 if (ms->flags & MAGIC_CHECK) 2025 file_magwarn(ms, "string modifier `%c' " 2026 "invalid", *l); 2027 goto out; 2028 } 2029 /* allow multiple '/' for readability */ 2030 if (l[1] == '/' && !isspace(CAST(unsigned char, l[2]))) 2031 l++; 2032 } 2033 if (string_modifier_check(ms, m) == -1) 2034 goto out; 2035 *lp = l; 2036 return 0; 2037 out: 2038 *lp = l; 2039 return -1; 2040 } 2041 2042 /* 2043 * parse one line from magic file, put into magic[index++] if valid 2044 */ 2045 file_private int 2046 parse(struct magic_set *ms, struct magic_entry *me, const char *file, 2047 const char *line, size_t llen, size_t lineno, int action) 2048 { 2049 #ifdef ENABLE_CONDITIONALS 2050 static uint32_t last_cont_level = 0; 2051 #endif 2052 size_t i; 2053 struct magic *m; 2054 const char *l = line, *el = line + llen; 2055 char *t; 2056 int op; 2057 uint32_t cont_level; 2058 int32_t diff; 2059 2060 cont_level = 0; 2061 2062 /* 2063 * Parse the offset. 2064 */ 2065 while (*l == '>') { 2066 if (l >= el) 2067 return -1; 2068 ++l; /* step over */ 2069 cont_level++; 2070 } 2071 #ifdef ENABLE_CONDITIONALS 2072 if (cont_level == 0 || cont_level > last_cont_level) 2073 if (file_check_mem(ms, cont_level) == -1) 2074 return -1; 2075 last_cont_level = cont_level; 2076 #endif 2077 if (cont_level != 0) { 2078 if (me->mp == NULL) { 2079 file_magerror(ms, "No current entry for continuation"); 2080 return -1; 2081 } 2082 if (me->cont_count == 0) { 2083 file_magerror(ms, "Continuations present with 0 count"); 2084 return -1; 2085 } 2086 m = &me->mp[me->cont_count - 1]; 2087 diff = CAST(int32_t, cont_level) - CAST(int32_t, m->cont_level); 2088 if (diff > 1) 2089 file_magwarn(ms, "New continuation level %u is more " 2090 "than one larger than current level %u", cont_level, 2091 m->cont_level); 2092 if (me->cont_count == me->max_count) { 2093 struct magic *nm; 2094 size_t cnt = me->max_count + ALLOC_CHUNK; 2095 if ((nm = CAST(struct magic *, realloc(me->mp, 2096 sizeof(*nm) * cnt))) == NULL) { 2097 file_oomem(ms, sizeof(*nm) * cnt); 2098 return -1; 2099 } 2100 me->mp = nm; 2101 me->max_count = CAST(uint32_t, cnt); 2102 } 2103 m = &me->mp[me->cont_count++]; 2104 (void)memset(m, 0, sizeof(*m)); 2105 m->cont_level = cont_level; 2106 } else { 2107 static const size_t len = sizeof(*m) * ALLOC_CHUNK; 2108 if (me->mp != NULL) 2109 return 1; 2110 if ((m = CAST(struct magic *, malloc(len))) == NULL) { 2111 file_oomem(ms, len); 2112 return -1; 2113 } 2114 me->mp = m; 2115 me->max_count = ALLOC_CHUNK; 2116 (void)memset(m, 0, sizeof(*m)); 2117 m->factor_op = FILE_FACTOR_OP_NONE; 2118 m->cont_level = 0; 2119 me->cont_count = 1; 2120 } 2121 m->lineno = CAST(uint32_t, lineno); 2122 2123 if (*l == '&') { /* m->cont_level == 0 checked below. */ 2124 ++l; /* step over */ 2125 m->flag |= OFFADD; 2126 } 2127 if (*l == '(') { 2128 ++l; /* step over */ 2129 m->flag |= INDIR; 2130 if (m->flag & OFFADD) 2131 m->flag = (m->flag & ~OFFADD) | INDIROFFADD; 2132 2133 if (*l == '&') { /* m->cont_level == 0 checked below */ 2134 ++l; /* step over */ 2135 m->flag |= OFFADD; 2136 } 2137 } 2138 /* Indirect offsets are not valid at level 0. */ 2139 if (m->cont_level == 0 && (m->flag & (OFFADD | INDIROFFADD))) { 2140 if (ms->flags & MAGIC_CHECK) 2141 file_magwarn(ms, "relative offset at level 0"); 2142 return -1; 2143 } 2144 2145 /* get offset, then skip over it */ 2146 if (*l == '-' || *l == '+') { 2147 ++l; /* step over */ 2148 m->flag |= l[-1] == '-' ? OFFNEGATIVE : OFFPOSITIVE; 2149 } 2150 m->offset = CAST(int32_t, strtol(l, &t, 0)); 2151 if (l == t) { 2152 if (ms->flags & MAGIC_CHECK) 2153 file_magwarn(ms, "offset `%s' invalid", l); 2154 return -1; 2155 } 2156 2157 l = t; 2158 2159 if (m->flag & INDIR) { 2160 m->in_type = FILE_LONG; 2161 m->in_offset = 0; 2162 m->in_op = 0; 2163 /* 2164 * read [.,lbs][+-]nnnnn) 2165 */ 2166 if (*l == '.' || *l == ',') { 2167 if (*l == ',') 2168 m->in_op |= FILE_OPSIGNED; 2169 l++; 2170 switch (*l) { 2171 case 'l': 2172 m->in_type = FILE_LELONG; 2173 break; 2174 case 'L': 2175 m->in_type = FILE_BELONG; 2176 break; 2177 case 'm': 2178 m->in_type = FILE_MELONG; 2179 break; 2180 case 'h': 2181 case 's': 2182 m->in_type = FILE_LESHORT; 2183 break; 2184 case 'H': 2185 case 'S': 2186 m->in_type = FILE_BESHORT; 2187 break; 2188 case 'c': 2189 case 'b': 2190 case 'C': 2191 case 'B': 2192 m->in_type = FILE_BYTE; 2193 break; 2194 case 'e': 2195 case 'f': 2196 case 'g': 2197 m->in_type = FILE_LEDOUBLE; 2198 break; 2199 case 'E': 2200 case 'F': 2201 case 'G': 2202 m->in_type = FILE_BEDOUBLE; 2203 break; 2204 case 'i': 2205 m->in_type = FILE_LEID3; 2206 break; 2207 case 'I': 2208 m->in_type = FILE_BEID3; 2209 break; 2210 case 'o': 2211 m->in_type = FILE_OCTAL; 2212 break; 2213 case 'q': 2214 m->in_type = FILE_LEQUAD; 2215 break; 2216 case 'Q': 2217 m->in_type = FILE_BEQUAD; 2218 break; 2219 default: 2220 if (ms->flags & MAGIC_CHECK) 2221 file_magwarn(ms, 2222 "indirect offset type `%c' invalid", 2223 *l); 2224 return -1; 2225 } 2226 l++; 2227 } 2228 2229 if (*l == '~') { 2230 m->in_op |= FILE_OPINVERSE; 2231 l++; 2232 } 2233 if ((op = get_op(*l)) != -1) { 2234 m->in_op |= op; 2235 l++; 2236 } 2237 if (*l == '(') { 2238 m->in_op |= FILE_OPINDIRECT; 2239 l++; 2240 } 2241 if (isdigit(CAST(unsigned char, *l)) || *l == '-') { 2242 m->in_offset = CAST(int32_t, strtol(l, &t, 0)); 2243 if (l == t) { 2244 if (ms->flags & MAGIC_CHECK) 2245 file_magwarn(ms, 2246 "in_offset `%s' invalid", l); 2247 return -1; 2248 } 2249 l = t; 2250 } 2251 if (*l++ != ')' || 2252 ((m->in_op & FILE_OPINDIRECT) && *l++ != ')')) { 2253 if (ms->flags & MAGIC_CHECK) 2254 file_magwarn(ms, 2255 "missing ')' in indirect offset"); 2256 return -1; 2257 } 2258 } 2259 EATAB; 2260 2261 #ifdef ENABLE_CONDITIONALS 2262 m->cond = get_cond(l, &l); 2263 if (check_cond(ms, m->cond, cont_level) == -1) 2264 return -1; 2265 2266 EATAB; 2267 #endif 2268 2269 /* 2270 * Parse the type. 2271 */ 2272 if (*l == 'u') { 2273 /* 2274 * Try it as a keyword type prefixed by "u"; match what 2275 * follows the "u". If that fails, try it as an SUS 2276 * integer type. 2277 */ 2278 m->type = get_type(type_tbl, l + 1, &l); 2279 if (m->type == FILE_INVALID) { 2280 /* 2281 * Not a keyword type; parse it as an SUS type, 2282 * 'u' possibly followed by a number or C/S/L. 2283 */ 2284 m->type = get_standard_integer_type(l, &l); 2285 } 2286 /* It's unsigned. */ 2287 if (m->type != FILE_INVALID) 2288 m->flag |= UNSIGNED; 2289 } else { 2290 /* 2291 * Try it as a keyword type. If that fails, try it as 2292 * an SUS integer type if it begins with "d" or as an 2293 * SUS string type if it begins with "s". In any case, 2294 * it's not unsigned. 2295 */ 2296 m->type = get_type(type_tbl, l, &l); 2297 if (m->type == FILE_INVALID) { 2298 /* 2299 * Not a keyword type; parse it as an SUS type, 2300 * either 'd' possibly followed by a number or 2301 * C/S/L, or just 's'. 2302 */ 2303 if (*l == 'd') 2304 m->type = get_standard_integer_type(l, &l); 2305 else if (*l == 's' 2306 && !isalpha(CAST(unsigned char, l[1]))) { 2307 m->type = FILE_STRING; 2308 ++l; 2309 } 2310 } 2311 } 2312 2313 if (m->type == FILE_INVALID) { 2314 /* Not found - try it as a special keyword. */ 2315 m->type = get_type(special_tbl, l, &l); 2316 } 2317 2318 if (m->type == FILE_INVALID) { 2319 if (ms->flags & MAGIC_CHECK) 2320 file_magwarn(ms, "type `%s' invalid", l); 2321 return -1; 2322 } 2323 2324 if (m->type == FILE_NAME && cont_level != 0) { 2325 if (ms->flags & MAGIC_CHECK) 2326 file_magwarn(ms, "`name%s' entries can only be " 2327 "declared at top level", l); 2328 return -1; 2329 } 2330 2331 /* New-style anding: "0 byte&0x80 =0x80 dynamically linked" */ 2332 /* New and improved: ~ & | ^ + - * / % -- exciting, isn't it? */ 2333 2334 m->mask_op = 0; 2335 if (*l == '~') { 2336 if (!IS_STRING(m->type)) 2337 m->mask_op |= FILE_OPINVERSE; 2338 else if (ms->flags & MAGIC_CHECK) 2339 file_magwarn(ms, "'~' invalid for string types"); 2340 ++l; 2341 } 2342 m->str_range = 0; 2343 m->str_flags = m->type == FILE_PSTRING ? PSTRING_1_LE : 0; 2344 if ((op = get_op(*l)) != -1) { 2345 if (IS_STRING(m->type)) { 2346 int r; 2347 2348 if (op != FILE_OPDIVIDE) { 2349 if (ms->flags & MAGIC_CHECK) 2350 file_magwarn(ms, 2351 "invalid string/indirect op: " 2352 "`%c'", *t); 2353 return -1; 2354 } 2355 2356 if (m->type == FILE_INDIRECT) 2357 r = parse_indirect_modifier(ms, m, &l); 2358 else 2359 r = parse_string_modifier(ms, m, &l); 2360 if (r == -1) 2361 return -1; 2362 } else 2363 parse_op_modifier(ms, m, &l, op); 2364 } 2365 2366 /* 2367 * We used to set mask to all 1's here, instead let's just not do 2368 * anything if mask = 0 (unless you have a better idea) 2369 */ 2370 EATAB; 2371 2372 switch (*l) { 2373 case '>': 2374 case '<': 2375 m->reln = *l; 2376 ++l; 2377 if (*l == '=') { 2378 if (ms->flags & MAGIC_CHECK) { 2379 file_magwarn(ms, "%c= not supported", 2380 m->reln); 2381 return -1; 2382 } 2383 ++l; 2384 } 2385 break; 2386 /* Old-style anding: "0 byte &0x80 dynamically linked" */ 2387 case '&': 2388 case '^': 2389 case '=': 2390 m->reln = *l; 2391 ++l; 2392 if (*l == '=') { 2393 /* HP compat: ignore &= etc. */ 2394 ++l; 2395 } 2396 break; 2397 case '!': 2398 m->reln = *l; 2399 ++l; 2400 break; 2401 default: 2402 m->reln = '='; /* the default relation */ 2403 if (*l == 'x' && ((isascii(CAST(unsigned char, l[1])) && 2404 isspace(CAST(unsigned char, l[1]))) || !l[1])) { 2405 m->reln = *l; 2406 ++l; 2407 } 2408 break; 2409 } 2410 2411 2412 /* 2413 * Grab the value part, except for an 'x' reln. 2414 */ 2415 if (m->reln != 'x') { 2416 if (*l == '\0') { 2417 file_magwarn(ms, "incomplete magic `%s'", line); 2418 return -1; 2419 } 2420 if (getvalue(ms, m, &l, action)) 2421 return -1; 2422 } 2423 2424 /* 2425 * TODO finish this macro and start using it! 2426 * #define offsetcheck {if (offset > ms->bytes_max -1) 2427 * magwarn("offset too big"); } 2428 */ 2429 2430 /* 2431 * Now get last part - the description 2432 */ 2433 EATAB; 2434 if (l[0] == '\b') { 2435 ++l; 2436 m->flag |= NOSPACE; 2437 } else if ((l[0] == '\\') && (l[1] == 'b')) { 2438 ++l; 2439 ++l; 2440 m->flag |= NOSPACE; 2441 } 2442 for (i = 0; i < sizeof(m->desc) && (m->desc[i++] = *l++) != '\0';) 2443 continue; 2444 if (m->desc[0] == '\0') { 2445 // Tuck in the filename for debugging. 2446 strlcpy(m->desc + 1, file, sizeof(m->desc) - 1); 2447 } 2448 if (i == sizeof(m->desc)) { 2449 m->desc[sizeof(m->desc) - 1] = '\0'; 2450 if (ms->flags & MAGIC_CHECK) 2451 file_magwarn(ms, "description `%s' truncated", m->desc); 2452 } 2453 2454 /* 2455 * We only do this check while compiling, or if any of the magic 2456 * files were not compiled. 2457 */ 2458 if (ms->flags & MAGIC_CHECK) { 2459 if (check_format(ms, m) == -1) 2460 return -1; 2461 } 2462 #ifndef COMPILE_ONLY 2463 if (action == FILE_CHECK) { 2464 file_mdump(m); 2465 } 2466 #endif 2467 m->mimetype[0] = '\0'; /* initialise MIME type to none */ 2468 return 0; 2469 } 2470 2471 /* 2472 * parse a STRENGTH annotation line from magic file, put into magic[index - 1] 2473 * if valid 2474 */ 2475 /*ARGSUSED*/ 2476 file_private int 2477 parse_strength(struct magic_set *ms, struct magic_entry *me, const char *line, 2478 size_t len __attribute__((__unused__))) 2479 { 2480 const char *l = line; 2481 char *el; 2482 unsigned long factor; 2483 char sbuf[512]; 2484 struct magic *m = &me->mp[0]; 2485 2486 if (m->factor_op != FILE_FACTOR_OP_NONE) { 2487 file_magwarn(ms, 2488 "Current entry already has a strength type: %c %d", 2489 m->factor_op, m->factor); 2490 return -1; 2491 } 2492 if (m->type == FILE_NAME) { 2493 file_magwarn(ms, "%s: Strength setting is not supported in " 2494 "\"name\" magic entries", 2495 file_printable(ms, sbuf, sizeof(sbuf), m->value.s, 2496 sizeof(m->value.s))); 2497 return -1; 2498 } 2499 EATAB; 2500 switch (*l) { 2501 case FILE_FACTOR_OP_NONE: 2502 break; 2503 case FILE_FACTOR_OP_PLUS: 2504 case FILE_FACTOR_OP_MINUS: 2505 case FILE_FACTOR_OP_TIMES: 2506 case FILE_FACTOR_OP_DIV: 2507 m->factor_op = *l++; 2508 break; 2509 default: 2510 file_magwarn(ms, "Unknown factor op `%c'", *l); 2511 return -1; 2512 } 2513 EATAB; 2514 factor = strtoul(l, &el, 0); 2515 if (factor > 255) { 2516 file_magwarn(ms, "Too large factor `%lu'", factor); 2517 goto out; 2518 } 2519 if (*el && !isspace(CAST(unsigned char, *el))) { 2520 file_magwarn(ms, "Bad factor `%s'", l); 2521 goto out; 2522 } 2523 m->factor = CAST(uint8_t, factor); 2524 if (m->factor == 0 && m->factor_op == FILE_FACTOR_OP_DIV) { 2525 file_magwarn(ms, "Cannot have factor op `%c' and factor %u", 2526 m->factor_op, m->factor); 2527 goto out; 2528 } 2529 return 0; 2530 out: 2531 m->factor_op = FILE_FACTOR_OP_NONE; 2532 m->factor = 0; 2533 return -1; 2534 } 2535 2536 file_private int 2537 goodchar(unsigned char x, const char *extra) 2538 { 2539 return (isascii(x) && isalnum(x)) || strchr(extra, x); 2540 } 2541 2542 file_private int 2543 parse_extra(struct magic_set *ms, struct magic_entry *me, const char *line, 2544 size_t llen, off_t off, size_t len, const char *name, const char *extra, 2545 int nt) 2546 { 2547 size_t i; 2548 const char *l = line; 2549 struct magic *m = &me->mp[me->cont_count == 0 ? 0 : me->cont_count - 1]; 2550 char *buf = CAST(char *, CAST(void *, m)) + off; 2551 2552 if (buf[0] != '\0') { 2553 len = nt ? strlen(buf) : len; 2554 file_magwarn(ms, "Current entry already has a %s type " 2555 "`%.*s', new type `%s'", name, CAST(int, len), buf, l); 2556 return -1; 2557 } 2558 2559 if (*m->desc == '\0') { 2560 file_magwarn(ms, "Current entry does not yet have a " 2561 "description for adding a %s type", name); 2562 return -1; 2563 } 2564 2565 EATAB; 2566 for (i = 0; *l && i < llen && i < len && goodchar(*l, extra); 2567 buf[i++] = *l++) 2568 continue; 2569 2570 if (i == len && *l) { 2571 if (nt) 2572 buf[len - 1] = '\0'; 2573 if (ms->flags & MAGIC_CHECK) 2574 file_magwarn(ms, "%s type `%s' truncated %" 2575 SIZE_T_FORMAT "u", name, line, i); 2576 } else { 2577 if (!isspace(CAST(unsigned char, *l)) && !goodchar(*l, extra)) 2578 file_magwarn(ms, "%s type `%s' has bad char '%c'", 2579 name, line, *l); 2580 if (nt) 2581 buf[i] = '\0'; 2582 } 2583 2584 if (i > 0) 2585 return 0; 2586 2587 file_magerror(ms, "Bad magic entry '%s'", line); 2588 return -1; 2589 } 2590 2591 /* 2592 * Parse an Apple CREATOR/TYPE annotation from magic file and put it into 2593 * magic[index - 1] 2594 */ 2595 file_private int 2596 parse_apple(struct magic_set *ms, struct magic_entry *me, const char *line, 2597 size_t len) 2598 { 2599 return parse_extra(ms, me, line, len, 2600 CAST(off_t, offsetof(struct magic, apple)), 2601 sizeof(me->mp[me->cont_count - 1].apple), "APPLE", "!+-./?", 0); 2602 } 2603 2604 /* 2605 * Parse a comma-separated list of extensions 2606 */ 2607 file_private int 2608 parse_ext(struct magic_set *ms, struct magic_entry *me, const char *line, 2609 size_t len) 2610 { 2611 return parse_extra(ms, me, line, len, 2612 CAST(off_t, offsetof(struct magic, ext)), 2613 sizeof(me->mp[me->cont_count - 1].ext), "EXTENSION", ",!+-/@?_$&~.", 2614 0); 2615 /* & for b&w */ 2616 /* ~ for journal~ */ 2617 } 2618 2619 /* 2620 * parse a MIME annotation line from magic file, put into magic[index - 1] 2621 * if valid 2622 */ 2623 file_private int 2624 parse_mime(struct magic_set *ms, struct magic_entry *me, const char *line, 2625 size_t len) 2626 { 2627 return parse_extra(ms, me, line, len, 2628 CAST(off_t, offsetof(struct magic, mimetype)), 2629 sizeof(me->mp[me->cont_count - 1].mimetype), "MIME", "+-/.$?:{};=", 2630 1); 2631 } 2632 2633 file_private int 2634 check_format_type(const char *ptr, int type, const char **estr) 2635 { 2636 int quad = 0, h; 2637 size_t len, cnt; 2638 if (*ptr == '\0') { 2639 /* Missing format string; bad */ 2640 *estr = "missing format spec"; 2641 return -1; 2642 } 2643 2644 switch (file_formats[type]) { 2645 case FILE_FMT_QUAD: 2646 quad = 1; 2647 /*FALLTHROUGH*/ 2648 case FILE_FMT_NUM: 2649 if (quad == 0) { 2650 switch (type) { 2651 case FILE_BYTE: 2652 h = 2; 2653 break; 2654 case FILE_SHORT: 2655 case FILE_BESHORT: 2656 case FILE_LESHORT: 2657 h = 1; 2658 break; 2659 case FILE_LONG: 2660 case FILE_BELONG: 2661 case FILE_LELONG: 2662 case FILE_MELONG: 2663 case FILE_LEID3: 2664 case FILE_BEID3: 2665 case FILE_INDIRECT: 2666 h = 0; 2667 break; 2668 default: 2669 fprintf(stderr, "Bad number format %d", type); 2670 abort(); 2671 } 2672 } else 2673 h = 0; 2674 while (*ptr && strchr("+-.#", *ptr) != NULL) 2675 ptr++; 2676 #define CHECKLEN() do { \ 2677 for (len = cnt = 0; isdigit(CAST(unsigned char, *ptr)); ptr++, cnt++) \ 2678 len = len * 10 + (*ptr - '0'); \ 2679 if (cnt > 5 || len > 1024) \ 2680 goto toolong; \ 2681 } while (/*CONSTCOND*/0) 2682 2683 CHECKLEN(); 2684 if (*ptr == '.') 2685 ptr++; 2686 CHECKLEN(); 2687 if (quad) { 2688 if (*ptr++ != 'l') 2689 goto invalid; 2690 if (*ptr++ != 'l') 2691 goto invalid; 2692 } 2693 2694 switch (*ptr++) { 2695 #ifdef STRICT_FORMAT /* "long" formats are int formats for us */ 2696 /* so don't accept the 'l' modifier */ 2697 case 'l': 2698 switch (*ptr++) { 2699 case 'i': 2700 case 'd': 2701 case 'u': 2702 case 'o': 2703 case 'x': 2704 case 'X': 2705 if (h == 0) 2706 return 0; 2707 /*FALLTHROUGH*/ 2708 default: 2709 goto invalid; 2710 } 2711 2712 /* 2713 * Don't accept h and hh modifiers. They make writing 2714 * magic entries more complicated, for very little benefit 2715 */ 2716 case 'h': 2717 if (h-- <= 0) 2718 goto invalid; 2719 switch (*ptr++) { 2720 case 'h': 2721 if (h-- <= 0) 2722 goto invalid; 2723 switch (*ptr++) { 2724 case 'i': 2725 case 'd': 2726 case 'u': 2727 case 'o': 2728 case 'x': 2729 case 'X': 2730 return 0; 2731 default: 2732 goto invalid; 2733 } 2734 case 'i': 2735 case 'd': 2736 case 'u': 2737 case 'o': 2738 case 'x': 2739 case 'X': 2740 if (h == 0) 2741 return 0; 2742 /*FALLTHROUGH*/ 2743 default: 2744 goto invalid; 2745 } 2746 #endif 2747 case 'c': 2748 if (h == 2) 2749 return 0; 2750 goto invalid; 2751 case 'i': 2752 case 'd': 2753 case 'u': 2754 case 'o': 2755 case 'x': 2756 case 'X': 2757 #ifdef STRICT_FORMAT 2758 if (h == 0) 2759 return 0; 2760 /*FALLTHROUGH*/ 2761 #else 2762 return 0; 2763 #endif 2764 default: 2765 goto invalid; 2766 } 2767 2768 case FILE_FMT_FLOAT: 2769 case FILE_FMT_DOUBLE: 2770 if (*ptr == '-') 2771 ptr++; 2772 if (*ptr == '.') 2773 ptr++; 2774 CHECKLEN(); 2775 if (*ptr == '.') 2776 ptr++; 2777 CHECKLEN(); 2778 switch (*ptr++) { 2779 case 'e': 2780 case 'E': 2781 case 'f': 2782 case 'F': 2783 case 'g': 2784 case 'G': 2785 return 0; 2786 2787 default: 2788 goto invalid; 2789 } 2790 2791 2792 case FILE_FMT_STR: 2793 if (*ptr == '-') 2794 ptr++; 2795 while (isdigit(CAST(unsigned char, *ptr))) 2796 ptr++; 2797 if (*ptr == '.') { 2798 ptr++; 2799 while (isdigit(CAST(unsigned char , *ptr))) 2800 ptr++; 2801 } 2802 2803 switch (*ptr++) { 2804 case 's': 2805 return 0; 2806 default: 2807 goto invalid; 2808 } 2809 2810 default: 2811 /* internal error */ 2812 fprintf(stderr, "Bad file format %d", type); 2813 abort(); 2814 } 2815 invalid: 2816 *estr = "not valid"; 2817 return -1; 2818 toolong: 2819 *estr = "too long"; 2820 return -1; 2821 } 2822 2823 /* 2824 * Check that the optional printf format in description matches 2825 * the type of the magic. 2826 */ 2827 file_private int 2828 check_format(struct magic_set *ms, struct magic *m) 2829 { 2830 char *ptr; 2831 const char *estr; 2832 2833 for (ptr = m->desc; *ptr; ptr++) 2834 if (*ptr == '%') 2835 break; 2836 if (*ptr == '\0') { 2837 /* No format string; ok */ 2838 return 1; 2839 } 2840 2841 assert(file_nformats == file_nnames); 2842 2843 if (m->type >= file_nformats) { 2844 file_magwarn(ms, "Internal error inconsistency between " 2845 "m->type and format strings"); 2846 return -1; 2847 } 2848 if (file_formats[m->type] == FILE_FMT_NONE) { 2849 file_magwarn(ms, "No format string for `%s' with description " 2850 "`%s'", m->desc, file_names[m->type]); 2851 return -1; 2852 } 2853 2854 ptr++; 2855 if (check_format_type(ptr, m->type, &estr) == -1) { 2856 /* 2857 * TODO: this error message is unhelpful if the format 2858 * string is not one character long 2859 */ 2860 file_magwarn(ms, "Printf format is %s for type " 2861 "`%s' in description `%s'", estr, 2862 file_names[m->type], m->desc); 2863 return -1; 2864 } 2865 2866 for (; *ptr; ptr++) { 2867 if (*ptr == '%') { 2868 file_magwarn(ms, 2869 "Too many format strings (should have at most one) " 2870 "for `%s' with description `%s'", 2871 file_names[m->type], m->desc); 2872 return -1; 2873 } 2874 } 2875 return 0; 2876 } 2877 2878 /* 2879 * Read a numeric value from a pointer, into the value union of a magic 2880 * pointer, according to the magic type. Update the string pointer to point 2881 * just after the number read. Return 0 for success, non-zero for failure. 2882 */ 2883 file_no_overflow file_private int 2884 getvalue(struct magic_set *ms, struct magic *m, const char **p, int action) 2885 { 2886 char *ep; 2887 uint64_t ull; 2888 int y; 2889 2890 switch (m->type) { 2891 case FILE_BESTRING16: 2892 case FILE_LESTRING16: 2893 case FILE_STRING: 2894 case FILE_PSTRING: 2895 case FILE_REGEX: 2896 case FILE_SEARCH: 2897 case FILE_NAME: 2898 case FILE_USE: 2899 case FILE_DER: 2900 case FILE_OCTAL: 2901 *p = getstr(ms, m, *p, action == FILE_COMPILE); 2902 if (*p == NULL) { 2903 if (ms->flags & MAGIC_CHECK) 2904 file_magwarn(ms, "cannot get string from `%s'", 2905 m->value.s); 2906 return -1; 2907 } 2908 if (m->type == FILE_REGEX) { 2909 file_regex_t rx; 2910 int rc = file_regcomp(ms, &rx, m->value.s, 2911 REG_EXTENDED | REGEX_ICASE(m)); 2912 if (rc == 0) { 2913 file_regfree(&rx); 2914 } 2915 return rc ? -1 : 0; 2916 } 2917 return 0; 2918 default: 2919 if (m->reln == 'x') 2920 return 0; 2921 break; 2922 } 2923 2924 switch (m->type) { 2925 case FILE_FLOAT: 2926 case FILE_BEFLOAT: 2927 case FILE_LEFLOAT: 2928 errno = 0; 2929 #ifdef HAVE_STRTOF 2930 m->value.f = strtof(*p, &ep); 2931 #else 2932 m->value.f = (float)strtod(*p, &ep); 2933 #endif 2934 if (errno == 0) 2935 *p = ep; 2936 return 0; 2937 case FILE_DOUBLE: 2938 case FILE_BEDOUBLE: 2939 case FILE_LEDOUBLE: 2940 errno = 0; 2941 m->value.d = strtod(*p, &ep); 2942 if (errno == 0) 2943 *p = ep; 2944 return 0; 2945 case FILE_BEGUID: 2946 case FILE_LEGUID: 2947 case FILE_GUID: 2948 if (file_parse_guid(*p, m->value.guid) == -1) { 2949 file_magwarn(ms, "Error parsing guid `%s'", *p); 2950 return -1; 2951 } 2952 *p += FILE_GUID_SIZE - 1; 2953 return 0; 2954 default: 2955 errno = 0; 2956 ull = CAST(uint64_t, strtoull(*p, &ep, 0)); 2957 m->value.q = file_signextend(ms, m, ull); 2958 if (*p == ep) { 2959 file_magwarn(ms, "Unparsable number `%s'", *p); 2960 return -1; 2961 } else { 2962 size_t ts = typesize(m->type); 2963 uint64_t x; 2964 const char *q; 2965 2966 if (ts == FILE_BADSIZE) { 2967 file_magwarn(ms, 2968 "Expected numeric type got `%s'", 2969 type_tbl[m->type].name); 2970 return -1; 2971 } 2972 for (q = *p; isspace(CAST(unsigned char, *q)); q++) 2973 continue; 2974 if (*q == '-' && ull != UINT64_MAX) 2975 ull = -CAST(int64_t, ull); 2976 switch (ts) { 2977 case 1: 2978 x = CAST(uint64_t, ull & ~0xffULL); 2979 y = (x & ~0xffULL) != ~0xffULL; 2980 break; 2981 case 2: 2982 x = CAST(uint64_t, ull & ~0xffffULL); 2983 y = (x & ~0xffffULL) != ~0xffffULL; 2984 break; 2985 case 4: 2986 x = CAST(uint64_t, ull & ~0xffffffffULL); 2987 y = (x & ~0xffffffffULL) != ~0xffffffffULL; 2988 break; 2989 case 8: 2990 x = 0; 2991 y = 0; 2992 break; 2993 default: 2994 fprintf(stderr, "Bad width %zu", ts); 2995 abort(); 2996 } 2997 if (x && y) { 2998 file_magwarn(ms, "Overflow for numeric" 2999 " type `%s' value %#" PRIx64, 3000 type_tbl[m->type].name, ull); 3001 return -1; 3002 } 3003 } 3004 if (errno == 0) { 3005 *p = ep; 3006 eatsize(p); 3007 } 3008 return 0; 3009 } 3010 } 3011 3012 /* 3013 * Convert a string containing C character escapes. Stop at an unescaped 3014 * space or tab. 3015 * Copy the converted version to "m->value.s", and the length in m->vallen. 3016 * Return updated scan pointer as function result. Warn if set. 3017 */ 3018 file_private const char * 3019 getstr(struct magic_set *ms, struct magic *m, const char *s, int warn) 3020 { 3021 const char *origs = s; 3022 char *p = m->value.s; 3023 size_t plen = sizeof(m->value.s); 3024 char *origp = p; 3025 char *pmax = p + plen - 1; 3026 int c; 3027 int val; 3028 size_t bracket_nesting = 0; 3029 3030 while ((c = *s++) != '\0') { 3031 if (isspace(CAST(unsigned char, c))) 3032 break; 3033 if (p >= pmax) { 3034 file_error(ms, 0, "string too long: `%s'", origs); 3035 return NULL; 3036 } 3037 if (c != '\\') { 3038 if (c == '[') { 3039 bracket_nesting++; 3040 } 3041 if (c == ']' && bracket_nesting > 0) { 3042 bracket_nesting--; 3043 } 3044 *p++ = CAST(char, c); 3045 continue; 3046 } 3047 switch(c = *s++) { 3048 3049 case '\0': 3050 if (warn) 3051 file_magwarn(ms, "incomplete escape"); 3052 s--; 3053 goto out; 3054 case '.': 3055 if (m->type == FILE_REGEX && 3056 bracket_nesting == 0 && warn) { 3057 file_magwarn(ms, "escaped dot ('.') found, " 3058 "use \\\\. instead"); 3059 } 3060 warn = 0; /* already did */ 3061 /*FALLTHROUGH*/ 3062 case '\t': 3063 if (warn) { 3064 file_magwarn(ms, 3065 "escaped tab found, use \\\\t instead"); 3066 warn = 0; /* already did */ 3067 } 3068 /*FALLTHROUGH*/ 3069 default: 3070 if (warn) { 3071 if (isprint(CAST(unsigned char, c))) { 3072 /* Allow escaping of 3073 * ``relations'' */ 3074 if (strchr("<>&^=!", c) == NULL 3075 && (m->type != FILE_REGEX || 3076 strchr("[]().*?^$|{}", c) 3077 == NULL)) { 3078 file_magwarn(ms, "no " 3079 "need to escape " 3080 "`%c'", c); 3081 } 3082 } else { 3083 file_magwarn(ms, 3084 "unknown escape sequence: " 3085 "\\%03o", c); 3086 } 3087 } 3088 /*FALLTHROUGH*/ 3089 /* space, perhaps force people to use \040? */ 3090 case ' ': 3091 #if 0 3092 /* 3093 * Other things people escape, but shouldn't need to, 3094 * so we disallow them 3095 */ 3096 case '\'': 3097 case '"': 3098 case '?': 3099 #endif 3100 /* Relations */ 3101 case '>': 3102 case '<': 3103 case '&': 3104 case '^': 3105 case '=': 3106 case '!': 3107 /* and backslash itself */ 3108 case '\\': 3109 *p++ = CAST(char, c); 3110 break; 3111 3112 case 'a': 3113 *p++ = '\a'; 3114 break; 3115 3116 case 'b': 3117 *p++ = '\b'; 3118 break; 3119 3120 case 'f': 3121 *p++ = '\f'; 3122 break; 3123 3124 case 'n': 3125 *p++ = '\n'; 3126 break; 3127 3128 case 'r': 3129 *p++ = '\r'; 3130 break; 3131 3132 case 't': 3133 *p++ = '\t'; 3134 break; 3135 3136 case 'v': 3137 *p++ = '\v'; 3138 break; 3139 3140 /* \ and up to 3 octal digits */ 3141 case '0': 3142 case '1': 3143 case '2': 3144 case '3': 3145 case '4': 3146 case '5': 3147 case '6': 3148 case '7': 3149 val = c - '0'; 3150 c = *s++; /* try for 2 */ 3151 if (c >= '0' && c <= '7') { 3152 val = (val << 3) | (c - '0'); 3153 c = *s++; /* try for 3 */ 3154 if (c >= '0' && c <= '7') 3155 val = (val << 3) | (c-'0'); 3156 else 3157 --s; 3158 } 3159 else 3160 --s; 3161 *p++ = CAST(char, val); 3162 break; 3163 3164 /* \x and up to 2 hex digits */ 3165 case 'x': 3166 val = 'x'; /* Default if no digits */ 3167 c = hextoint(*s++); /* Get next char */ 3168 if (c >= 0) { 3169 val = c; 3170 c = hextoint(*s++); 3171 if (c >= 0) 3172 val = (val << 4) + c; 3173 else 3174 --s; 3175 } else 3176 --s; 3177 *p++ = CAST(char, val); 3178 break; 3179 } 3180 } 3181 --s; 3182 out: 3183 *p = '\0'; 3184 if (CAST(size_t, (p - origp)) > sizeof(m->value.s)) 3185 return NULL; 3186 m->vallen = CAST(unsigned char, (p - origp)); 3187 if (m->type == FILE_PSTRING) { 3188 size_t l = file_pstring_length_size(ms, m); 3189 if (l == FILE_BADSIZE) 3190 return NULL; 3191 if (m->vallen + l > sizeof(m->value.s)) 3192 return NULL; 3193 m->vallen += CAST(unsigned char, l); 3194 } 3195 return s; 3196 } 3197 3198 3199 /* Single hex char to int; -1 if not a hex char. */ 3200 file_private int 3201 hextoint(int c) 3202 { 3203 if (!isascii(CAST(unsigned char, c))) 3204 return -1; 3205 if (isdigit(CAST(unsigned char, c))) 3206 return c - '0'; 3207 if ((c >= 'a') && (c <= 'f')) 3208 return c + 10 - 'a'; 3209 if (( c>= 'A') && (c <= 'F')) 3210 return c + 10 - 'A'; 3211 return -1; 3212 } 3213 3214 3215 /* 3216 * Print a string containing C character escapes. 3217 */ 3218 file_protected void 3219 file_showstr(FILE *fp, const char *s, size_t len) 3220 { 3221 char c; 3222 3223 for (;;) { 3224 if (len == FILE_BADSIZE) { 3225 c = *s++; 3226 if (c == '\0') 3227 break; 3228 } 3229 else { 3230 if (len-- == 0) 3231 break; 3232 c = *s++; 3233 } 3234 if (c >= 040 && c <= 0176) /* TODO isprint && !iscntrl */ 3235 (void) fputc(c, fp); 3236 else { 3237 (void) fputc('\\', fp); 3238 switch (c) { 3239 case '\a': 3240 (void) fputc('a', fp); 3241 break; 3242 3243 case '\b': 3244 (void) fputc('b', fp); 3245 break; 3246 3247 case '\f': 3248 (void) fputc('f', fp); 3249 break; 3250 3251 case '\n': 3252 (void) fputc('n', fp); 3253 break; 3254 3255 case '\r': 3256 (void) fputc('r', fp); 3257 break; 3258 3259 case '\t': 3260 (void) fputc('t', fp); 3261 break; 3262 3263 case '\v': 3264 (void) fputc('v', fp); 3265 break; 3266 3267 default: 3268 (void) fprintf(fp, "%.3o", c & 0377); 3269 break; 3270 } 3271 } 3272 } 3273 } 3274 3275 /* 3276 * eatsize(): Eat the size spec from a number [eg. 10UL] 3277 */ 3278 file_private void 3279 eatsize(const char **p) 3280 { 3281 const char *l = *p; 3282 3283 if (LOWCASE(*l) == 'u') 3284 l++; 3285 3286 switch (LOWCASE(*l)) { 3287 case 'l': /* long */ 3288 case 's': /* short */ 3289 case 'h': /* short */ 3290 case 'b': /* char/byte */ 3291 case 'c': /* char/byte */ 3292 l++; 3293 /*FALLTHROUGH*/ 3294 default: 3295 break; 3296 } 3297 3298 *p = l; 3299 } 3300 3301 /* 3302 * handle a buffer containing a compiled file. 3303 */ 3304 file_private struct magic_map * 3305 apprentice_buf(struct magic_set *ms, struct magic *buf, size_t len) 3306 { 3307 struct magic_map *map; 3308 3309 if ((map = CAST(struct magic_map *, calloc(1, sizeof(*map)))) == NULL) { 3310 file_oomem(ms, sizeof(*map)); 3311 return NULL; 3312 } 3313 map->len = len; 3314 map->p = buf; 3315 map->type = MAP_TYPE_USER; 3316 if (check_buffer(ms, map, "buffer") != 0) { 3317 apprentice_unmap(map); 3318 return NULL; 3319 } 3320 return map; 3321 } 3322 3323 /* 3324 * handle a compiled file. 3325 */ 3326 3327 file_private struct magic_map * 3328 apprentice_map(struct magic_set *ms, const char *fn) 3329 { 3330 int fd; 3331 struct stat st; 3332 char *dbname = NULL; 3333 struct magic_map *map; 3334 struct magic_map *rv = NULL; 3335 3336 fd = -1; 3337 if ((map = CAST(struct magic_map *, calloc(1, sizeof(*map)))) == NULL) { 3338 file_oomem(ms, sizeof(*map)); 3339 goto error; 3340 } 3341 map->type = MAP_TYPE_USER; /* unspecified */ 3342 3343 dbname = mkdbname(ms, fn, 0); 3344 if (dbname == NULL) 3345 goto error; 3346 3347 if ((fd = open(dbname, O_RDONLY|O_BINARY)) == -1) 3348 goto error; 3349 3350 if (fstat(fd, &st) == -1) { 3351 file_error(ms, errno, "cannot stat `%s'", dbname); 3352 goto error; 3353 } 3354 if (st.st_size < 8 || st.st_size > maxoff_t()) { 3355 file_error(ms, 0, "file `%s' is too %s", dbname, 3356 st.st_size < 8 ? "small" : "large"); 3357 goto error; 3358 } 3359 3360 map->len = CAST(size_t, st.st_size); 3361 #ifdef QUICK 3362 map->type = MAP_TYPE_MMAP; 3363 if ((map->p = mmap(0, CAST(size_t, st.st_size), PROT_READ|PROT_WRITE, 3364 MAP_PRIVATE|MAP_FILE, fd, CAST(off_t, 0))) == MAP_FAILED) { 3365 file_error(ms, errno, "cannot map `%s'", dbname); 3366 goto error; 3367 } 3368 #else 3369 map->type = MAP_TYPE_MALLOC; 3370 if ((map->p = CAST(void *, malloc(map->len))) == NULL) { 3371 file_oomem(ms, map->len); 3372 goto error; 3373 } 3374 if (read(fd, map->p, map->len) != (ssize_t)map->len) { 3375 file_badread(ms); 3376 goto error; 3377 } 3378 #endif 3379 (void)close(fd); 3380 fd = -1; 3381 3382 if (check_buffer(ms, map, dbname) != 0) { 3383 goto error; 3384 } 3385 #ifdef QUICK 3386 if (mprotect(map->p, CAST(size_t, st.st_size), PROT_READ) == -1) { 3387 file_error(ms, errno, "cannot mprotect `%s'", dbname); 3388 goto error; 3389 } 3390 #endif 3391 3392 free(dbname); 3393 return map; 3394 3395 error: 3396 if (fd != -1) 3397 (void)close(fd); 3398 apprentice_unmap(map); 3399 free(dbname); 3400 return rv; 3401 } 3402 3403 file_private int 3404 check_buffer(struct magic_set *ms, struct magic_map *map, const char *dbname) 3405 { 3406 uint32_t *ptr; 3407 uint32_t entries, nentries; 3408 uint32_t version; 3409 int i, needsbyteswap; 3410 3411 entries = CAST(uint32_t, map->len / sizeof(struct magic)); 3412 if (entries < MAGIC_SETS) { 3413 file_error(ms, 0, "Too few magic entries %u in `%s'", 3414 entries, dbname); 3415 return -1; 3416 } 3417 if ((entries * sizeof(struct magic)) != map->len) { 3418 file_error(ms, 0, "Size of `%s' %" SIZE_T_FORMAT "u is not " 3419 "a multiple of %" SIZE_T_FORMAT "u", 3420 dbname, map->len, sizeof(struct magic)); 3421 return -1; 3422 } 3423 3424 ptr = CAST(uint32_t *, map->p); 3425 if (*ptr != MAGICNO) { 3426 if (file_swap4(*ptr) != MAGICNO) { 3427 file_error(ms, 0, "bad magic in `%s'", dbname); 3428 return -1; 3429 } 3430 needsbyteswap = 1; 3431 } else 3432 needsbyteswap = 0; 3433 if (needsbyteswap) 3434 version = file_swap4(ptr[1]); 3435 else 3436 version = ptr[1]; 3437 if (version != VERSIONNO) { 3438 file_error(ms, 0, "File %s supports only version %d magic " 3439 "files. `%s' is version %d", VERSION, 3440 VERSIONNO, dbname, version); 3441 return -1; 3442 } 3443 map->magic[0] = CAST(struct magic *, map->p) + 1; 3444 nentries = 0; 3445 for (i = 0; i < MAGIC_SETS; i++) { 3446 if (needsbyteswap) 3447 map->nmagic[i] = file_swap4(ptr[i + 2]); 3448 else 3449 map->nmagic[i] = ptr[i + 2]; 3450 if (map->nmagic[i] > entries) { 3451 file_error(ms, 0, "nmagic[%u] too large in `%s'", i, 3452 dbname); 3453 return -1; 3454 } 3455 if (i != MAGIC_SETS - 1) 3456 map->magic[i + 1] = map->magic[i] + map->nmagic[i]; 3457 nentries += map->nmagic[i]; 3458 } 3459 if (entries != nentries + 1) { 3460 file_error(ms, 0, "Inconsistent entries in `%s' %u != %u", 3461 dbname, entries, nentries + 1); 3462 return -1; 3463 } 3464 if (needsbyteswap) 3465 for (i = 0; i < MAGIC_SETS; i++) 3466 byteswap(map->magic[i], map->nmagic[i]); 3467 return 0; 3468 } 3469 3470 /* 3471 * handle an mmaped file. 3472 */ 3473 file_private int 3474 apprentice_compile(struct magic_set *ms, struct magic_map *map, const char *fn) 3475 { 3476 static const size_t nm = sizeof(*map->nmagic) * MAGIC_SETS; 3477 static const size_t m = sizeof(**map->magic); 3478 int fd = -1; 3479 size_t len; 3480 char *dbname; 3481 int rv = -1; 3482 uint32_t i; 3483 union { 3484 struct magic m; 3485 uint32_t h[2 + MAGIC_SETS]; 3486 } hdr; 3487 3488 dbname = mkdbname(ms, fn, 1); 3489 3490 if (dbname == NULL) 3491 goto out; 3492 3493 if ((fd = open(dbname, O_WRONLY|O_CREAT|O_TRUNC|O_BINARY, 0644)) == -1) 3494 { 3495 file_error(ms, errno, "cannot open `%s'", dbname); 3496 goto out; 3497 } 3498 memset(&hdr, 0, sizeof(hdr)); 3499 hdr.h[0] = MAGICNO; 3500 hdr.h[1] = VERSIONNO; 3501 memcpy(hdr.h + 2, map->nmagic, nm); 3502 3503 if (write(fd, &hdr, sizeof(hdr)) != CAST(ssize_t, sizeof(hdr))) { 3504 file_error(ms, errno, "error writing `%s'", dbname); 3505 goto out2; 3506 } 3507 3508 for (i = 0; i < MAGIC_SETS; i++) { 3509 len = m * map->nmagic[i]; 3510 if (write(fd, map->magic[i], len) != CAST(ssize_t, len)) { 3511 file_error(ms, errno, "error writing `%s'", dbname); 3512 goto out2; 3513 } 3514 } 3515 3516 rv = 0; 3517 out2: 3518 if (fd != -1) 3519 (void)close(fd); 3520 out: 3521 apprentice_unmap(map); 3522 free(dbname); 3523 return rv; 3524 } 3525 3526 file_private const char ext[] = ".mgc"; 3527 /* 3528 * make a dbname 3529 */ 3530 file_private char * 3531 mkdbname(struct magic_set *ms, const char *fn, int strip) 3532 { 3533 const char *p, *q; 3534 char *buf; 3535 3536 if (strip) { 3537 if ((p = strrchr(fn, '/')) != NULL) 3538 fn = ++p; 3539 } 3540 3541 for (q = fn; *q; q++) 3542 continue; 3543 /* Look for .mgc */ 3544 for (p = ext + sizeof(ext) - 1; p >= ext && q >= fn; p--, q--) 3545 if (*p != *q) 3546 break; 3547 3548 /* Did not find .mgc, restore q */ 3549 if (p >= ext) 3550 for (q = fn; *q; q++) 3551 continue; 3552 3553 q++; 3554 /* Compatibility with old code that looked in .mime */ 3555 if (ms->flags & MAGIC_MIME) { 3556 if (asprintf(&buf, "%.*s.mime%s", CAST(int, q - fn), fn, ext) 3557 < 0) 3558 return NULL; 3559 if (access(buf, R_OK) != -1) { 3560 ms->flags &= MAGIC_MIME_TYPE; 3561 return buf; 3562 } 3563 free(buf); 3564 } 3565 if (asprintf(&buf, "%.*s%s", CAST(int, q - fn), fn, ext) < 0) 3566 return NULL; 3567 3568 /* Compatibility with old code that looked in .mime */ 3569 if (strstr(fn, ".mime") != NULL) 3570 ms->flags &= MAGIC_MIME_TYPE; 3571 return buf; 3572 } 3573 3574 /* 3575 * Byteswap an mmap'ed file if needed 3576 */ 3577 file_private void 3578 byteswap(struct magic *magic, uint32_t nmagic) 3579 { 3580 uint32_t i; 3581 for (i = 0; i < nmagic; i++) 3582 bs1(&magic[i]); 3583 } 3584 3585 file_protected uintmax_t 3586 file_varint2uintmax_t(const unsigned char *us, int t, size_t *l) 3587 { 3588 uintmax_t x = 0; 3589 const unsigned char *c; 3590 if (t == FILE_LEVARINT) { 3591 for (c = us; *c; c++) { 3592 if ((*c & 0x80) == 0) 3593 break; 3594 } 3595 if (l) 3596 *l = c - us + 1; 3597 for (; c >= us; c--) { 3598 x |= *c & 0x7f; 3599 x <<= 7; 3600 } 3601 } else { 3602 for (c = us; *c; c++) { 3603 x |= *c & 0x7f; 3604 if ((*c & 0x80) == 0) 3605 break; 3606 x <<= 7; 3607 } 3608 if (l) 3609 *l = c - us + 1; 3610 } 3611 return x; 3612 } 3613 3614 3615 /* 3616 * byteswap a single magic entry 3617 */ 3618 file_private void 3619 bs1(struct magic *m) 3620 { 3621 m->flag = file_swap2(m->flag); 3622 m->offset = file_swap4(CAST(uint32_t, m->offset)); 3623 m->in_offset = file_swap4(CAST(uint32_t, m->in_offset)); 3624 m->lineno = file_swap4(CAST(uint32_t, m->lineno)); 3625 if (IS_STRING(m->type)) { 3626 m->str_range = file_swap4(m->str_range); 3627 m->str_flags = file_swap4(m->str_flags); 3628 } else { 3629 m->value.q = file_swap8(m->value.q); 3630 m->num_mask = file_swap8(m->num_mask); 3631 } 3632 } 3633 3634 file_protected size_t 3635 file_pstring_length_size(struct magic_set *ms, const struct magic *m) 3636 { 3637 switch (m->str_flags & PSTRING_LEN) { 3638 case PSTRING_1_LE: 3639 return 1; 3640 case PSTRING_2_LE: 3641 case PSTRING_2_BE: 3642 return 2; 3643 case PSTRING_4_LE: 3644 case PSTRING_4_BE: 3645 return 4; 3646 default: 3647 file_error(ms, 0, "corrupt magic file " 3648 "(bad pascal string length %d)", 3649 m->str_flags & PSTRING_LEN); 3650 return FILE_BADSIZE; 3651 } 3652 } 3653 3654 file_protected size_t 3655 file_pstring_get_length(struct magic_set *ms, const struct magic *m, 3656 const char *ss) 3657 { 3658 size_t len = 0; 3659 const unsigned char *s = RCAST(const unsigned char *, ss); 3660 unsigned int s3, s2, s1, s0; 3661 3662 switch (m->str_flags & PSTRING_LEN) { 3663 case PSTRING_1_LE: 3664 len = *s; 3665 break; 3666 case PSTRING_2_LE: 3667 s0 = s[0]; 3668 s1 = s[1]; 3669 len = (s1 << 8) | s0; 3670 break; 3671 case PSTRING_2_BE: 3672 s0 = s[0]; 3673 s1 = s[1]; 3674 len = (s0 << 8) | s1; 3675 break; 3676 case PSTRING_4_LE: 3677 s0 = s[0]; 3678 s1 = s[1]; 3679 s2 = s[2]; 3680 s3 = s[3]; 3681 len = (s3 << 24) | (s2 << 16) | (s1 << 8) | s0; 3682 break; 3683 case PSTRING_4_BE: 3684 s0 = s[0]; 3685 s1 = s[1]; 3686 s2 = s[2]; 3687 s3 = s[3]; 3688 len = (s0 << 24) | (s1 << 16) | (s2 << 8) | s3; 3689 break; 3690 default: 3691 file_error(ms, 0, "corrupt magic file " 3692 "(bad pascal string length %d)", 3693 m->str_flags & PSTRING_LEN); 3694 return FILE_BADSIZE; 3695 } 3696 3697 if (m->str_flags & PSTRING_LENGTH_INCLUDES_ITSELF) { 3698 size_t l = file_pstring_length_size(ms, m); 3699 if (l == FILE_BADSIZE) 3700 return l; 3701 len -= l; 3702 } 3703 3704 return len; 3705 } 3706 3707 file_protected int 3708 file_magicfind(struct magic_set *ms, const char *name, struct mlist *v) 3709 { 3710 uint32_t i, j; 3711 struct mlist *mlist, *ml; 3712 3713 mlist = ms->mlist[1]; 3714 3715 for (ml = mlist->next; ml != mlist; ml = ml->next) { 3716 struct magic *ma = ml->magic; 3717 for (i = 0; i < ml->nmagic; i++) { 3718 if (ma[i].type != FILE_NAME) 3719 continue; 3720 if (strcmp(ma[i].value.s, name) == 0) { 3721 v->magic = &ma[i]; 3722 v->magic_rxcomp = &(ml->magic_rxcomp[i]); 3723 for (j = i + 1; j < ml->nmagic; j++) 3724 if (ma[j].cont_level == 0) 3725 break; 3726 v->nmagic = j - i; 3727 return 0; 3728 } 3729 } 3730 } 3731 return -1; 3732 } 3733