1 /* $NetBSD: softmagic.c,v 1.11 2014/06/13 02:08:06 christos Exp $ */ 2 /* 3 * Copyright (c) Ian F. Darwin 1986-1995. 4 * Software written by Ian F. Darwin and others; 5 * maintained 1995-present by Christos Zoulas and others. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice immediately at the beginning of the file, without modification, 12 * this list of conditions, and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR 21 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27 * SUCH DAMAGE. 28 */ 29 /* 30 * softmagic - interpret variable magic from MAGIC 31 */ 32 33 #include "file.h" 34 35 #ifndef lint 36 #if 0 37 FILE_RCSID("@(#)$File: softmagic.c,v 1.191 2014/06/04 17:36:34 christos Exp $") 38 #else 39 __RCSID("$NetBSD: softmagic.c,v 1.11 2014/06/13 02:08:06 christos Exp $"); 40 #endif 41 #endif /* lint */ 42 43 #include "magic.h" 44 #include <assert.h> 45 #include <string.h> 46 #include <ctype.h> 47 #include <stdlib.h> 48 #include <time.h> 49 #if defined(HAVE_LOCALE_H) 50 #include <locale.h> 51 #endif 52 53 54 private int match(struct magic_set *, struct magic *, uint32_t, 55 const unsigned char *, size_t, size_t, int, int, int, int, int *, int *, 56 int *); 57 private int mget(struct magic_set *, const unsigned char *, 58 struct magic *, size_t, size_t, unsigned int, int, int, int, int, int *, 59 int *, int *); 60 private int magiccheck(struct magic_set *, struct magic *); 61 private int32_t mprint(struct magic_set *, struct magic *); 62 private int32_t moffset(struct magic_set *, struct magic *); 63 private void mdebug(uint32_t, const char *, size_t); 64 private int mcopy(struct magic_set *, union VALUETYPE *, int, int, 65 const unsigned char *, uint32_t, size_t, struct magic *); 66 private int mconvert(struct magic_set *, struct magic *, int); 67 private int print_sep(struct magic_set *, int); 68 private int handle_annotation(struct magic_set *, struct magic *); 69 private void cvt_8(union VALUETYPE *, const struct magic *); 70 private void cvt_16(union VALUETYPE *, const struct magic *); 71 private void cvt_32(union VALUETYPE *, const struct magic *); 72 private void cvt_64(union VALUETYPE *, const struct magic *); 73 74 #define OFFSET_OOB(n, o, i) ((n) < (o) || (i) > ((n) - (o))) 75 /* 76 * softmagic - lookup one file in parsed, in-memory copy of database 77 * Passed the name and FILE * of one file to be typed. 78 */ 79 /*ARGSUSED1*/ /* nbytes passed for regularity, maybe need later */ 80 protected int 81 file_softmagic(struct magic_set *ms, const unsigned char *buf, size_t nbytes, 82 size_t level, int mode, int text) 83 { 84 struct mlist *ml; 85 int rv, printed_something = 0, need_separator = 0; 86 for (ml = ms->mlist[0]->next; ml != ms->mlist[0]; ml = ml->next) 87 if ((rv = match(ms, ml->magic, ml->nmagic, buf, nbytes, 0, mode, 88 text, 0, level, &printed_something, &need_separator, 89 NULL)) != 0) 90 return rv; 91 92 return 0; 93 } 94 95 #define FILE_FMTDEBUG 96 #ifdef FILE_FMTDEBUG 97 #define F(a, b, c) file_fmtcheck((a), (b), (c), __FILE__, __LINE__) 98 99 private const char * __attribute__((__format_arg__(3))) 100 file_fmtcheck(struct magic_set *ms, const struct magic *m, const char *def, 101 const char *file, size_t line) 102 { 103 const char *ptr = fmtcheck(m->desc, def); 104 if (ptr == def) 105 file_magerror(ms, 106 "%s, %zu: format `%s' does not match with `%s'", 107 file, line, m->desc, def); 108 return ptr; 109 } 110 #else 111 #define F(a, b, c) fmtcheck((b)->desc, (c)) 112 #endif 113 114 /* 115 * Go through the whole list, stopping if you find a match. Process all 116 * the continuations of that match before returning. 117 * 118 * We support multi-level continuations: 119 * 120 * At any time when processing a successful top-level match, there is a 121 * current continuation level; it represents the level of the last 122 * successfully matched continuation. 123 * 124 * Continuations above that level are skipped as, if we see one, it 125 * means that the continuation that controls them - i.e, the 126 * lower-level continuation preceding them - failed to match. 127 * 128 * Continuations below that level are processed as, if we see one, 129 * it means we've finished processing or skipping higher-level 130 * continuations under the control of a successful or unsuccessful 131 * lower-level continuation, and are now seeing the next lower-level 132 * continuation and should process it. The current continuation 133 * level reverts to the level of the one we're seeing. 134 * 135 * Continuations at the current level are processed as, if we see 136 * one, there's no lower-level continuation that may have failed. 137 * 138 * If a continuation matches, we bump the current continuation level 139 * so that higher-level continuations are processed. 140 */ 141 private int 142 match(struct magic_set *ms, struct magic *magic, uint32_t nmagic, 143 const unsigned char *s, size_t nbytes, size_t offset, int mode, int text, 144 int flip, int recursion_level, int *printed_something, int *need_separator, 145 int *returnval) 146 { 147 uint32_t magindex = 0; 148 unsigned int cont_level = 0; 149 int returnvalv = 0, e; /* if a match is found it is set to 1*/ 150 int firstline = 1; /* a flag to print X\n X\n- X */ 151 int print = (ms->flags & (MAGIC_MIME|MAGIC_APPLE)) == 0; 152 153 if (returnval == NULL) 154 returnval = &returnvalv; 155 156 if (file_check_mem(ms, cont_level) == -1) 157 return -1; 158 159 for (magindex = 0; magindex < nmagic; magindex++) { 160 int flush = 0; 161 struct magic *m = &magic[magindex]; 162 163 if (m->type != FILE_NAME) 164 if ((IS_STRING(m->type) && 165 #define FLT (STRING_BINTEST | STRING_TEXTTEST) 166 ((text && (m->str_flags & FLT) == STRING_BINTEST) || 167 (!text && (m->str_flags & FLT) == STRING_TEXTTEST))) || 168 (m->flag & mode) != mode) { 169 /* Skip sub-tests */ 170 while (magindex + 1 < nmagic && 171 magic[magindex + 1].cont_level != 0 && 172 ++magindex) 173 continue; 174 continue; /* Skip to next top-level test*/ 175 } 176 177 ms->offset = m->offset; 178 ms->line = m->lineno; 179 180 /* if main entry matches, print it... */ 181 switch (mget(ms, s, m, nbytes, offset, cont_level, mode, text, 182 flip, recursion_level + 1, printed_something, 183 need_separator, returnval)) { 184 case -1: 185 return -1; 186 case 0: 187 flush = m->reln != '!'; 188 break; 189 default: 190 if (m->type == FILE_INDIRECT) 191 *returnval = 1; 192 193 switch (magiccheck(ms, m)) { 194 case -1: 195 return -1; 196 case 0: 197 flush++; 198 break; 199 default: 200 flush = 0; 201 break; 202 } 203 break; 204 } 205 if (flush) { 206 /* 207 * main entry didn't match, 208 * flush its continuations 209 */ 210 while (magindex < nmagic - 1 && 211 magic[magindex + 1].cont_level != 0) 212 magindex++; 213 continue; 214 } 215 216 if ((e = handle_annotation(ms, m)) != 0) { 217 *need_separator = 1; 218 *printed_something = 1; 219 *returnval = 1; 220 return e; 221 } 222 /* 223 * If we are going to print something, we'll need to print 224 * a blank before we print something else. 225 */ 226 if (*m->desc) { 227 *need_separator = 1; 228 *printed_something = 1; 229 if (print_sep(ms, firstline) == -1) 230 return -1; 231 } 232 233 234 if (print && mprint(ms, m) == -1) 235 return -1; 236 237 ms->c.li[cont_level].off = moffset(ms, m); 238 239 /* and any continuations that match */ 240 if (file_check_mem(ms, ++cont_level) == -1) 241 return -1; 242 243 while (++magindex < nmagic && 244 magic[magindex].cont_level != 0) { 245 m = &magic[magindex]; 246 ms->line = m->lineno; /* for messages */ 247 248 if (cont_level < m->cont_level) 249 continue; 250 if (cont_level > m->cont_level) { 251 /* 252 * We're at the end of the level 253 * "cont_level" continuations. 254 */ 255 cont_level = m->cont_level; 256 } 257 ms->offset = m->offset; 258 if (m->flag & OFFADD) { 259 ms->offset += 260 ms->c.li[cont_level - 1].off; 261 } 262 263 #ifdef ENABLE_CONDITIONALS 264 if (m->cond == COND_ELSE || 265 m->cond == COND_ELIF) { 266 if (ms->c.li[cont_level].last_match == 1) 267 continue; 268 } 269 #endif 270 switch (mget(ms, s, m, nbytes, offset, cont_level, mode, 271 text, flip, recursion_level + 1, printed_something, 272 need_separator, returnval)) { 273 case -1: 274 return -1; 275 case 0: 276 if (m->reln != '!') 277 continue; 278 flush = 1; 279 break; 280 default: 281 if (m->type == FILE_INDIRECT) 282 *returnval = 1; 283 flush = 0; 284 break; 285 } 286 287 switch (flush ? 1 : magiccheck(ms, m)) { 288 case -1: 289 return -1; 290 case 0: 291 #ifdef ENABLE_CONDITIONALS 292 ms->c.li[cont_level].last_match = 0; 293 #endif 294 break; 295 default: 296 #ifdef ENABLE_CONDITIONALS 297 ms->c.li[cont_level].last_match = 1; 298 #endif 299 if (m->type == FILE_CLEAR) 300 ms->c.li[cont_level].got_match = 0; 301 else if (ms->c.li[cont_level].got_match) { 302 if (m->type == FILE_DEFAULT) 303 break; 304 } else 305 ms->c.li[cont_level].got_match = 1; 306 if ((e = handle_annotation(ms, m)) != 0) { 307 *need_separator = 1; 308 *printed_something = 1; 309 *returnval = 1; 310 return e; 311 } 312 /* 313 * If we are going to print something, 314 * make sure that we have a separator first. 315 */ 316 if (*m->desc) { 317 if (!*printed_something) { 318 *printed_something = 1; 319 if (print_sep(ms, firstline) 320 == -1) 321 return -1; 322 } 323 } 324 /* 325 * This continuation matched. Print 326 * its message, with a blank before it 327 * if the previous item printed and 328 * this item isn't empty. 329 */ 330 /* space if previous printed */ 331 if (*need_separator 332 && ((m->flag & NOSPACE) == 0) 333 && *m->desc) { 334 if (print && 335 file_printf(ms, " ") == -1) 336 return -1; 337 *need_separator = 0; 338 } 339 if (print && mprint(ms, m) == -1) 340 return -1; 341 342 ms->c.li[cont_level].off = moffset(ms, m); 343 344 if (*m->desc) 345 *need_separator = 1; 346 347 /* 348 * If we see any continuations 349 * at a higher level, 350 * process them. 351 */ 352 if (file_check_mem(ms, ++cont_level) == -1) 353 return -1; 354 break; 355 } 356 } 357 if (*printed_something) { 358 firstline = 0; 359 if (print) 360 *returnval = 1; 361 } 362 if ((ms->flags & MAGIC_CONTINUE) == 0 && *printed_something) { 363 return *returnval; /* don't keep searching */ 364 } 365 } 366 return *returnval; /* This is hit if -k is set or there is no match */ 367 } 368 369 private int 370 check_fmt(struct magic_set *ms, struct magic *m) 371 { 372 file_regex_t rx; 373 int rc, rv = -1; 374 375 if (strchr(m->desc, '%') == NULL) 376 return 0; 377 378 rc = file_regcomp(&rx, "%[-0-9\\.]*s", REG_EXTENDED|REG_NOSUB); 379 if (rc) { 380 file_regerror(&rx, rc, ms); 381 } else { 382 rc = file_regexec(&rx, m->desc, 0, 0, 0); 383 rv = !rc; 384 } 385 file_regfree(&rx); 386 return rv; 387 } 388 389 #ifndef HAVE_STRNDUP 390 char * strndup(const char *, size_t); 391 392 char * 393 strndup(const char *str, size_t n) 394 { 395 size_t len; 396 char *copy; 397 398 for (len = 0; len < n && str[len]; len++) 399 continue; 400 if ((copy = malloc(len + 1)) == NULL) 401 return NULL; 402 (void)memcpy(copy, str, len); 403 copy[len] = '\0'; 404 return copy; 405 } 406 #endif /* HAVE_STRNDUP */ 407 408 private int32_t 409 mprint(struct magic_set *ms, struct magic *m) 410 { 411 uint64_t v; 412 float vf; 413 double vd; 414 int64_t t = 0; 415 char buf[128], tbuf[26]; 416 union VALUETYPE *p = &ms->ms_value; 417 418 switch (m->type) { 419 case FILE_BYTE: 420 v = file_signextend(ms, m, (uint64_t)p->b); 421 switch (check_fmt(ms, m)) { 422 case -1: 423 return -1; 424 case 1: 425 (void)snprintf(buf, sizeof(buf), "%d", 426 (unsigned char)v); 427 if (file_printf(ms, F(ms, m, "%s"), buf) == -1) 428 return -1; 429 break; 430 default: 431 if (file_printf(ms, F(ms, m, "%d"), 432 (unsigned char) v) == -1) 433 return -1; 434 break; 435 } 436 t = ms->offset + sizeof(char); 437 break; 438 439 case FILE_SHORT: 440 case FILE_BESHORT: 441 case FILE_LESHORT: 442 v = file_signextend(ms, m, (uint64_t)p->h); 443 switch (check_fmt(ms, m)) { 444 case -1: 445 return -1; 446 case 1: 447 (void)snprintf(buf, sizeof(buf), "%u", 448 (unsigned short)v); 449 if (file_printf(ms, F(ms, m, "%s"), buf) == -1) 450 return -1; 451 break; 452 default: 453 if (file_printf(ms, F(ms, m, "%u"), 454 (unsigned short) v) == -1) 455 return -1; 456 break; 457 } 458 t = ms->offset + sizeof(short); 459 break; 460 461 case FILE_LONG: 462 case FILE_BELONG: 463 case FILE_LELONG: 464 case FILE_MELONG: 465 v = file_signextend(ms, m, (uint64_t)p->l); 466 switch (check_fmt(ms, m)) { 467 case -1: 468 return -1; 469 case 1: 470 (void)snprintf(buf, sizeof(buf), "%u", (uint32_t) v); 471 if (file_printf(ms, F(ms, m, "%s"), buf) == -1) 472 return -1; 473 break; 474 default: 475 if (file_printf(ms, F(ms, m, "%u"), (uint32_t) v) == -1) 476 return -1; 477 break; 478 } 479 t = ms->offset + sizeof(int32_t); 480 break; 481 482 case FILE_QUAD: 483 case FILE_BEQUAD: 484 case FILE_LEQUAD: 485 v = file_signextend(ms, m, p->q); 486 switch (check_fmt(ms, m)) { 487 case -1: 488 return -1; 489 case 1: 490 (void)snprintf(buf, sizeof(buf), "%" INT64_T_FORMAT "u", 491 (unsigned long long)v); 492 if (file_printf(ms, F(ms, m, "%s"), buf) == -1) 493 return -1; 494 break; 495 default: 496 if (file_printf(ms, F(ms, m, "%" INT64_T_FORMAT "u"), 497 (unsigned long long) v) == -1) 498 return -1; 499 break; 500 } 501 t = ms->offset + sizeof(int64_t); 502 break; 503 504 case FILE_STRING: 505 case FILE_PSTRING: 506 case FILE_BESTRING16: 507 case FILE_LESTRING16: 508 if (m->reln == '=' || m->reln == '!') { 509 if (file_printf(ms, F(ms, m, "%s"), m->value.s) == -1) 510 return -1; 511 t = ms->offset + m->vallen; 512 } 513 else { 514 char *str = p->s; 515 516 /* compute t before we mangle the string? */ 517 t = ms->offset + strlen(str); 518 519 if (*m->value.s == '\0') 520 str[strcspn(str, "\n")] = '\0'; 521 522 if (m->str_flags & STRING_TRIM) { 523 char *last; 524 while (isspace((unsigned char)*str)) 525 str++; 526 last = str; 527 while (*last) 528 last++; 529 --last; 530 while (isspace((unsigned char)*last)) 531 last--; 532 *++last = '\0'; 533 } 534 535 if (file_printf(ms, F(ms, m, "%s"), str) == -1) 536 return -1; 537 538 if (m->type == FILE_PSTRING) 539 t += file_pstring_length_size(m); 540 } 541 break; 542 543 case FILE_DATE: 544 case FILE_BEDATE: 545 case FILE_LEDATE: 546 case FILE_MEDATE: 547 if (file_printf(ms, F(ms, m, "%s"), 548 file_fmttime(p->l + m->num_mask, FILE_T_LOCAL, tbuf)) == -1) 549 return -1; 550 t = ms->offset + sizeof(uint32_t); 551 break; 552 553 case FILE_LDATE: 554 case FILE_BELDATE: 555 case FILE_LELDATE: 556 case FILE_MELDATE: 557 if (file_printf(ms, F(ms, m, "%s"), 558 file_fmttime(p->l + m->num_mask, 0, tbuf)) == -1) 559 return -1; 560 t = ms->offset + sizeof(uint32_t); 561 break; 562 563 case FILE_QDATE: 564 case FILE_BEQDATE: 565 case FILE_LEQDATE: 566 if (file_printf(ms, F(ms, m, "%s"), 567 file_fmttime(p->q + m->num_mask, FILE_T_LOCAL, tbuf)) == -1) 568 return -1; 569 t = ms->offset + sizeof(uint64_t); 570 break; 571 572 case FILE_QLDATE: 573 case FILE_BEQLDATE: 574 case FILE_LEQLDATE: 575 if (file_printf(ms, F(ms, m, "%s"), 576 file_fmttime(p->q + m->num_mask, 0, tbuf)) == -1) 577 return -1; 578 t = ms->offset + sizeof(uint64_t); 579 break; 580 581 case FILE_QWDATE: 582 case FILE_BEQWDATE: 583 case FILE_LEQWDATE: 584 if (file_printf(ms, F(ms, m, "%s"), 585 file_fmttime(p->q + m->num_mask, FILE_T_WINDOWS, tbuf)) == -1) 586 return -1; 587 t = ms->offset + sizeof(uint64_t); 588 break; 589 590 case FILE_FLOAT: 591 case FILE_BEFLOAT: 592 case FILE_LEFLOAT: 593 vf = p->f; 594 switch (check_fmt(ms, m)) { 595 case -1: 596 return -1; 597 case 1: 598 (void)snprintf(buf, sizeof(buf), "%g", vf); 599 if (file_printf(ms, F(ms, m, "%s"), buf) == -1) 600 return -1; 601 break; 602 default: 603 if (file_printf(ms, F(ms, m, "%g"), vf) == -1) 604 return -1; 605 break; 606 } 607 t = ms->offset + sizeof(float); 608 break; 609 610 case FILE_DOUBLE: 611 case FILE_BEDOUBLE: 612 case FILE_LEDOUBLE: 613 vd = p->d; 614 switch (check_fmt(ms, m)) { 615 case -1: 616 return -1; 617 case 1: 618 (void)snprintf(buf, sizeof(buf), "%g", vd); 619 if (file_printf(ms, F(ms, m, "%s"), buf) == -1) 620 return -1; 621 break; 622 default: 623 if (file_printf(ms, F(ms, m, "%g"), vd) == -1) 624 return -1; 625 break; 626 } 627 t = ms->offset + sizeof(double); 628 break; 629 630 case FILE_REGEX: { 631 char *cp; 632 int rval; 633 634 cp = strndup((const char *)ms->search.s, ms->search.rm_len); 635 if (cp == NULL) { 636 file_oomem(ms, ms->search.rm_len); 637 return -1; 638 } 639 rval = file_printf(ms, F(ms, m, "%s"), cp); 640 free(cp); 641 642 if (rval == -1) 643 return -1; 644 645 if ((m->str_flags & REGEX_OFFSET_START)) 646 t = ms->search.offset; 647 else 648 t = ms->search.offset + ms->search.rm_len; 649 break; 650 } 651 652 case FILE_SEARCH: 653 if (file_printf(ms, F(ms, m, "%s"), m->value.s) == -1) 654 return -1; 655 if ((m->str_flags & REGEX_OFFSET_START)) 656 t = ms->search.offset; 657 else 658 t = ms->search.offset + m->vallen; 659 break; 660 661 case FILE_DEFAULT: 662 case FILE_CLEAR: 663 if (file_printf(ms, "%s", m->desc) == -1) 664 return -1; 665 t = ms->offset; 666 break; 667 668 case FILE_INDIRECT: 669 case FILE_USE: 670 case FILE_NAME: 671 t = ms->offset; 672 break; 673 674 default: 675 file_magerror(ms, "invalid m->type (%d) in mprint()", m->type); 676 return -1; 677 } 678 return (int32_t)t; 679 } 680 681 private int32_t 682 moffset(struct magic_set *ms, struct magic *m) 683 { 684 switch (m->type) { 685 case FILE_BYTE: 686 return CAST(int32_t, (ms->offset + sizeof(char))); 687 688 case FILE_SHORT: 689 case FILE_BESHORT: 690 case FILE_LESHORT: 691 return CAST(int32_t, (ms->offset + sizeof(short))); 692 693 case FILE_LONG: 694 case FILE_BELONG: 695 case FILE_LELONG: 696 case FILE_MELONG: 697 return CAST(int32_t, (ms->offset + sizeof(int32_t))); 698 699 case FILE_QUAD: 700 case FILE_BEQUAD: 701 case FILE_LEQUAD: 702 return CAST(int32_t, (ms->offset + sizeof(int64_t))); 703 704 case FILE_STRING: 705 case FILE_PSTRING: 706 case FILE_BESTRING16: 707 case FILE_LESTRING16: 708 if (m->reln == '=' || m->reln == '!') 709 return ms->offset + m->vallen; 710 else { 711 union VALUETYPE *p = &ms->ms_value; 712 uint32_t t; 713 714 if (*m->value.s == '\0') 715 p->s[strcspn(p->s, "\n")] = '\0'; 716 t = CAST(uint32_t, (ms->offset + strlen(p->s))); 717 if (m->type == FILE_PSTRING) 718 t += (uint32_t)file_pstring_length_size(m); 719 return t; 720 } 721 722 case FILE_DATE: 723 case FILE_BEDATE: 724 case FILE_LEDATE: 725 case FILE_MEDATE: 726 return CAST(int32_t, (ms->offset + sizeof(uint32_t))); 727 728 case FILE_LDATE: 729 case FILE_BELDATE: 730 case FILE_LELDATE: 731 case FILE_MELDATE: 732 return CAST(int32_t, (ms->offset + sizeof(uint32_t))); 733 734 case FILE_QDATE: 735 case FILE_BEQDATE: 736 case FILE_LEQDATE: 737 return CAST(int32_t, (ms->offset + sizeof(uint64_t))); 738 739 case FILE_QLDATE: 740 case FILE_BEQLDATE: 741 case FILE_LEQLDATE: 742 return CAST(int32_t, (ms->offset + sizeof(uint64_t))); 743 744 case FILE_FLOAT: 745 case FILE_BEFLOAT: 746 case FILE_LEFLOAT: 747 return CAST(int32_t, (ms->offset + sizeof(float))); 748 749 case FILE_DOUBLE: 750 case FILE_BEDOUBLE: 751 case FILE_LEDOUBLE: 752 return CAST(int32_t, (ms->offset + sizeof(double))); 753 754 case FILE_REGEX: 755 if ((m->str_flags & REGEX_OFFSET_START) != 0) 756 return CAST(int32_t, ms->search.offset); 757 else 758 return CAST(int32_t, (ms->search.offset + 759 ms->search.rm_len)); 760 761 case FILE_SEARCH: 762 if ((m->str_flags & REGEX_OFFSET_START) != 0) 763 return CAST(int32_t, ms->search.offset); 764 else 765 return CAST(int32_t, (ms->search.offset + m->vallen)); 766 767 case FILE_CLEAR: 768 case FILE_DEFAULT: 769 case FILE_INDIRECT: 770 return ms->offset; 771 772 default: 773 return 0; 774 } 775 } 776 777 private int 778 cvt_flip(int type, int flip) 779 { 780 if (flip == 0) 781 return type; 782 switch (type) { 783 case FILE_BESHORT: 784 return FILE_LESHORT; 785 case FILE_BELONG: 786 return FILE_LELONG; 787 case FILE_BEDATE: 788 return FILE_LEDATE; 789 case FILE_BELDATE: 790 return FILE_LELDATE; 791 case FILE_BEQUAD: 792 return FILE_LEQUAD; 793 case FILE_BEQDATE: 794 return FILE_LEQDATE; 795 case FILE_BEQLDATE: 796 return FILE_LEQLDATE; 797 case FILE_BEQWDATE: 798 return FILE_LEQWDATE; 799 case FILE_LESHORT: 800 return FILE_BESHORT; 801 case FILE_LELONG: 802 return FILE_BELONG; 803 case FILE_LEDATE: 804 return FILE_BEDATE; 805 case FILE_LELDATE: 806 return FILE_BELDATE; 807 case FILE_LEQUAD: 808 return FILE_BEQUAD; 809 case FILE_LEQDATE: 810 return FILE_BEQDATE; 811 case FILE_LEQLDATE: 812 return FILE_BEQLDATE; 813 case FILE_LEQWDATE: 814 return FILE_BEQWDATE; 815 case FILE_BEFLOAT: 816 return FILE_LEFLOAT; 817 case FILE_LEFLOAT: 818 return FILE_BEFLOAT; 819 case FILE_BEDOUBLE: 820 return FILE_LEDOUBLE; 821 case FILE_LEDOUBLE: 822 return FILE_BEDOUBLE; 823 default: 824 return type; 825 } 826 } 827 #define DO_CVT(fld, cast) \ 828 if (m->num_mask) \ 829 switch (m->mask_op & FILE_OPS_MASK) { \ 830 case FILE_OPAND: \ 831 p->fld &= cast m->num_mask; \ 832 break; \ 833 case FILE_OPOR: \ 834 p->fld |= cast m->num_mask; \ 835 break; \ 836 case FILE_OPXOR: \ 837 p->fld ^= cast m->num_mask; \ 838 break; \ 839 case FILE_OPADD: \ 840 p->fld += cast m->num_mask; \ 841 break; \ 842 case FILE_OPMINUS: \ 843 p->fld -= cast m->num_mask; \ 844 break; \ 845 case FILE_OPMULTIPLY: \ 846 p->fld *= cast m->num_mask; \ 847 break; \ 848 case FILE_OPDIVIDE: \ 849 p->fld /= cast m->num_mask; \ 850 break; \ 851 case FILE_OPMODULO: \ 852 p->fld %= cast m->num_mask; \ 853 break; \ 854 } \ 855 if (m->mask_op & FILE_OPINVERSE) \ 856 p->fld = ~p->fld \ 857 858 private void 859 cvt_8(union VALUETYPE *p, const struct magic *m) 860 { 861 DO_CVT(b, (uint8_t)); 862 } 863 864 private void 865 cvt_16(union VALUETYPE *p, const struct magic *m) 866 { 867 DO_CVT(h, (uint16_t)); 868 } 869 870 private void 871 cvt_32(union VALUETYPE *p, const struct magic *m) 872 { 873 DO_CVT(l, (uint32_t)); 874 } 875 876 private void 877 cvt_64(union VALUETYPE *p, const struct magic *m) 878 { 879 DO_CVT(q, (uint64_t)); 880 } 881 882 #define DO_CVT2(fld, cast) \ 883 if (m->num_mask) \ 884 switch (m->mask_op & FILE_OPS_MASK) { \ 885 case FILE_OPADD: \ 886 p->fld += cast m->num_mask; \ 887 break; \ 888 case FILE_OPMINUS: \ 889 p->fld -= cast m->num_mask; \ 890 break; \ 891 case FILE_OPMULTIPLY: \ 892 p->fld *= cast m->num_mask; \ 893 break; \ 894 case FILE_OPDIVIDE: \ 895 p->fld /= cast m->num_mask; \ 896 break; \ 897 } \ 898 899 private void 900 cvt_float(union VALUETYPE *p, const struct magic *m) 901 { 902 DO_CVT2(f, (float)); 903 } 904 905 private void 906 cvt_double(union VALUETYPE *p, const struct magic *m) 907 { 908 DO_CVT2(d, (double)); 909 } 910 911 /* 912 * Convert the byte order of the data we are looking at 913 * While we're here, let's apply the mask operation 914 * (unless you have a better idea) 915 */ 916 private int 917 mconvert(struct magic_set *ms, struct magic *m, int flip) 918 { 919 union VALUETYPE *p = &ms->ms_value; 920 uint8_t type; 921 922 switch (type = cvt_flip(m->type, flip)) { 923 case FILE_BYTE: 924 cvt_8(p, m); 925 return 1; 926 case FILE_SHORT: 927 cvt_16(p, m); 928 return 1; 929 case FILE_LONG: 930 case FILE_DATE: 931 case FILE_LDATE: 932 cvt_32(p, m); 933 return 1; 934 case FILE_QUAD: 935 case FILE_QDATE: 936 case FILE_QLDATE: 937 case FILE_QWDATE: 938 cvt_64(p, m); 939 return 1; 940 case FILE_STRING: 941 case FILE_BESTRING16: 942 case FILE_LESTRING16: { 943 /* Null terminate and eat *trailing* return */ 944 p->s[sizeof(p->s) - 1] = '\0'; 945 return 1; 946 } 947 case FILE_PSTRING: { 948 size_t sz = file_pstring_length_size(m); 949 char *ptr1 = p->s, *ptr2 = ptr1 + sz; 950 size_t len = file_pstring_get_length(m, ptr1); 951 if (len >= sizeof(p->s)) { 952 /* 953 * The size of the pascal string length (sz) 954 * is 1, 2, or 4. We need at least 1 byte for NUL 955 * termination, but we've already truncated the 956 * string by p->s, so we need to deduct sz. 957 */ 958 len = sizeof(p->s) - sz; 959 } 960 while (len--) 961 *ptr1++ = *ptr2++; 962 *ptr1 = '\0'; 963 return 1; 964 } 965 case FILE_BESHORT: 966 p->h = (short)((p->hs[0]<<8)|(p->hs[1])); 967 cvt_16(p, m); 968 return 1; 969 case FILE_BELONG: 970 case FILE_BEDATE: 971 case FILE_BELDATE: 972 p->l = (int32_t) 973 ((p->hl[0]<<24)|(p->hl[1]<<16)|(p->hl[2]<<8)|(p->hl[3])); 974 if (type == FILE_BELONG) 975 cvt_32(p, m); 976 return 1; 977 case FILE_BEQUAD: 978 case FILE_BEQDATE: 979 case FILE_BEQLDATE: 980 case FILE_BEQWDATE: 981 p->q = (uint64_t) 982 (((uint64_t)p->hq[0]<<56)|((uint64_t)p->hq[1]<<48)| 983 ((uint64_t)p->hq[2]<<40)|((uint64_t)p->hq[3]<<32)| 984 ((uint64_t)p->hq[4]<<24)|((uint64_t)p->hq[5]<<16)| 985 ((uint64_t)p->hq[6]<<8)|((uint64_t)p->hq[7])); 986 if (type == FILE_BEQUAD) 987 cvt_64(p, m); 988 return 1; 989 case FILE_LESHORT: 990 p->h = (short)((p->hs[1]<<8)|(p->hs[0])); 991 cvt_16(p, m); 992 return 1; 993 case FILE_LELONG: 994 case FILE_LEDATE: 995 case FILE_LELDATE: 996 p->l = (int32_t) 997 ((p->hl[3]<<24)|(p->hl[2]<<16)|(p->hl[1]<<8)|(p->hl[0])); 998 if (type == FILE_LELONG) 999 cvt_32(p, m); 1000 return 1; 1001 case FILE_LEQUAD: 1002 case FILE_LEQDATE: 1003 case FILE_LEQLDATE: 1004 case FILE_LEQWDATE: 1005 p->q = (uint64_t) 1006 (((uint64_t)p->hq[7]<<56)|((uint64_t)p->hq[6]<<48)| 1007 ((uint64_t)p->hq[5]<<40)|((uint64_t)p->hq[4]<<32)| 1008 ((uint64_t)p->hq[3]<<24)|((uint64_t)p->hq[2]<<16)| 1009 ((uint64_t)p->hq[1]<<8)|((uint64_t)p->hq[0])); 1010 if (type == FILE_LEQUAD) 1011 cvt_64(p, m); 1012 return 1; 1013 case FILE_MELONG: 1014 case FILE_MEDATE: 1015 case FILE_MELDATE: 1016 p->l = (int32_t) 1017 ((p->hl[1]<<24)|(p->hl[0]<<16)|(p->hl[3]<<8)|(p->hl[2])); 1018 if (type == FILE_MELONG) 1019 cvt_32(p, m); 1020 return 1; 1021 case FILE_FLOAT: 1022 cvt_float(p, m); 1023 return 1; 1024 case FILE_BEFLOAT: 1025 p->l = ((uint32_t)p->hl[0]<<24)|((uint32_t)p->hl[1]<<16)| 1026 ((uint32_t)p->hl[2]<<8) |((uint32_t)p->hl[3]); 1027 cvt_float(p, m); 1028 return 1; 1029 case FILE_LEFLOAT: 1030 p->l = ((uint32_t)p->hl[3]<<24)|((uint32_t)p->hl[2]<<16)| 1031 ((uint32_t)p->hl[1]<<8) |((uint32_t)p->hl[0]); 1032 cvt_float(p, m); 1033 return 1; 1034 case FILE_DOUBLE: 1035 cvt_double(p, m); 1036 return 1; 1037 case FILE_BEDOUBLE: 1038 p->q = ((uint64_t)p->hq[0]<<56)|((uint64_t)p->hq[1]<<48)| 1039 ((uint64_t)p->hq[2]<<40)|((uint64_t)p->hq[3]<<32)| 1040 ((uint64_t)p->hq[4]<<24)|((uint64_t)p->hq[5]<<16)| 1041 ((uint64_t)p->hq[6]<<8) |((uint64_t)p->hq[7]); 1042 cvt_double(p, m); 1043 return 1; 1044 case FILE_LEDOUBLE: 1045 p->q = ((uint64_t)p->hq[7]<<56)|((uint64_t)p->hq[6]<<48)| 1046 ((uint64_t)p->hq[5]<<40)|((uint64_t)p->hq[4]<<32)| 1047 ((uint64_t)p->hq[3]<<24)|((uint64_t)p->hq[2]<<16)| 1048 ((uint64_t)p->hq[1]<<8) |((uint64_t)p->hq[0]); 1049 cvt_double(p, m); 1050 return 1; 1051 case FILE_REGEX: 1052 case FILE_SEARCH: 1053 case FILE_DEFAULT: 1054 case FILE_CLEAR: 1055 case FILE_NAME: 1056 case FILE_USE: 1057 return 1; 1058 default: 1059 file_magerror(ms, "invalid type %d in mconvert()", m->type); 1060 return 0; 1061 } 1062 } 1063 1064 1065 private void 1066 mdebug(uint32_t offset, const char *str, size_t len) 1067 { 1068 (void) fprintf(stderr, "mget/%zu @%d: ", len, offset); 1069 file_showstr(stderr, str, len); 1070 (void) fputc('\n', stderr); 1071 (void) fputc('\n', stderr); 1072 } 1073 1074 private int 1075 mcopy(struct magic_set *ms, union VALUETYPE *p, int type, int indir, 1076 const unsigned char *s, uint32_t offset, size_t nbytes, struct magic *m) 1077 { 1078 /* 1079 * Note: FILE_SEARCH and FILE_REGEX do not actually copy 1080 * anything, but setup pointers into the source 1081 */ 1082 if (indir == 0) { 1083 switch (type) { 1084 case FILE_SEARCH: 1085 ms->search.s = RCAST(const char *, s) + offset; 1086 ms->search.s_len = nbytes - offset; 1087 ms->search.offset = offset; 1088 return 0; 1089 1090 case FILE_REGEX: { 1091 const char *b; 1092 const char *c; 1093 const char *last; /* end of search region */ 1094 const char *buf; /* start of search region */ 1095 const char *end; 1096 size_t lines, linecnt, bytecnt; 1097 1098 if (s == NULL) { 1099 ms->search.s_len = 0; 1100 ms->search.s = NULL; 1101 return 0; 1102 } 1103 1104 if (m->str_flags & REGEX_LINE_COUNT) { 1105 linecnt = m->str_range; 1106 bytecnt = linecnt * 80; 1107 } else { 1108 linecnt = 0; 1109 bytecnt = m->str_range; 1110 } 1111 1112 if (bytecnt == 0) 1113 bytecnt = 8192; 1114 if (bytecnt > nbytes) 1115 bytecnt = nbytes; 1116 1117 buf = RCAST(const char *, s) + offset; 1118 end = last = RCAST(const char *, s) + bytecnt; 1119 /* mget() guarantees buf <= last */ 1120 for (lines = linecnt, b = buf; lines && b < end && 1121 ((b = CAST(const char *, 1122 memchr(c = b, '\n', CAST(size_t, (end - b))))) 1123 || (b = CAST(const char *, 1124 memchr(c, '\r', CAST(size_t, (end - c)))))); 1125 lines--, b++) { 1126 last = b; 1127 if (b[0] == '\r' && b[1] == '\n') 1128 b++; 1129 } 1130 if (lines) 1131 last = RCAST(const char *, s) + bytecnt; 1132 1133 ms->search.s = buf; 1134 ms->search.s_len = last - buf; 1135 ms->search.offset = offset; 1136 ms->search.rm_len = 0; 1137 return 0; 1138 } 1139 case FILE_BESTRING16: 1140 case FILE_LESTRING16: { 1141 const unsigned char *src = s + offset; 1142 const unsigned char *esrc = s + nbytes; 1143 char *dst = p->s; 1144 char *edst = &p->s[sizeof(p->s) - 1]; 1145 1146 if (type == FILE_BESTRING16) 1147 src++; 1148 1149 /* check that offset is within range */ 1150 if (offset >= nbytes) 1151 break; 1152 for (/*EMPTY*/; src < esrc; src += 2, dst++) { 1153 if (dst < edst) 1154 *dst = *src; 1155 else 1156 break; 1157 if (*dst == '\0') { 1158 if (type == FILE_BESTRING16 ? 1159 *(src - 1) != '\0' : 1160 *(src + 1) != '\0') 1161 *dst = ' '; 1162 } 1163 } 1164 *edst = '\0'; 1165 return 0; 1166 } 1167 case FILE_STRING: /* XXX - these two should not need */ 1168 case FILE_PSTRING: /* to copy anything, but do anyway. */ 1169 default: 1170 break; 1171 } 1172 } 1173 1174 if (offset >= nbytes) { 1175 (void)memset(p, '\0', sizeof(*p)); 1176 return 0; 1177 } 1178 if (nbytes - offset < sizeof(*p)) 1179 nbytes = nbytes - offset; 1180 else 1181 nbytes = sizeof(*p); 1182 1183 (void)memcpy(p, s + offset, nbytes); 1184 1185 /* 1186 * the usefulness of padding with zeroes eludes me, it 1187 * might even cause problems 1188 */ 1189 if (nbytes < sizeof(*p)) 1190 (void)memset(((char *)(void *)p) + nbytes, '\0', 1191 sizeof(*p) - nbytes); 1192 return 0; 1193 } 1194 1195 private int 1196 mget(struct magic_set *ms, const unsigned char *s, struct magic *m, 1197 size_t nbytes, size_t o, unsigned int cont_level, int mode, int text, 1198 int flip, int recursion_level, int *printed_something, 1199 int *need_separator, int *returnval) 1200 { 1201 uint32_t soffset, offset = ms->offset; 1202 uint32_t lhs; 1203 int rv, oneed_separator, in_type; 1204 char *sbuf, *rbuf; 1205 union VALUETYPE *p = &ms->ms_value; 1206 struct mlist ml; 1207 1208 if (recursion_level >= 20) { 1209 file_error(ms, 0, "recursion nesting exceeded"); 1210 return -1; 1211 } 1212 1213 if (mcopy(ms, p, m->type, m->flag & INDIR, s, (uint32_t)(offset + o), 1214 (uint32_t)nbytes, m) == -1) 1215 return -1; 1216 1217 if ((ms->flags & MAGIC_DEBUG) != 0) { 1218 fprintf(stderr, "mget(type=%d, flag=%x, offset=%u, o=%zu, " 1219 "nbytes=%zu)\n", m->type, m->flag, offset, o, nbytes); 1220 mdebug(offset, (char *)(void *)p, sizeof(union VALUETYPE)); 1221 #ifndef COMPILE_ONLY 1222 file_mdump(m); 1223 #endif 1224 } 1225 1226 if (m->flag & INDIR) { 1227 int off = m->in_offset; 1228 if (m->in_op & FILE_OPINDIRECT) { 1229 const union VALUETYPE *q = CAST(const union VALUETYPE *, 1230 ((const void *)(s + offset + off))); 1231 switch (cvt_flip(m->in_type, flip)) { 1232 case FILE_BYTE: 1233 off = q->b; 1234 break; 1235 case FILE_SHORT: 1236 off = q->h; 1237 break; 1238 case FILE_BESHORT: 1239 off = (short)((q->hs[0]<<8)|(q->hs[1])); 1240 break; 1241 case FILE_LESHORT: 1242 off = (short)((q->hs[1]<<8)|(q->hs[0])); 1243 break; 1244 case FILE_LONG: 1245 off = q->l; 1246 break; 1247 case FILE_BELONG: 1248 case FILE_BEID3: 1249 off = (int32_t)((q->hl[0]<<24)|(q->hl[1]<<16)| 1250 (q->hl[2]<<8)|(q->hl[3])); 1251 break; 1252 case FILE_LEID3: 1253 case FILE_LELONG: 1254 off = (int32_t)((q->hl[3]<<24)|(q->hl[2]<<16)| 1255 (q->hl[1]<<8)|(q->hl[0])); 1256 break; 1257 case FILE_MELONG: 1258 off = (int32_t)((q->hl[1]<<24)|(q->hl[0]<<16)| 1259 (q->hl[3]<<8)|(q->hl[2])); 1260 break; 1261 } 1262 if ((ms->flags & MAGIC_DEBUG) != 0) 1263 fprintf(stderr, "indirect offs=%u\n", off); 1264 } 1265 switch (in_type = cvt_flip(m->in_type, flip)) { 1266 case FILE_BYTE: 1267 if (OFFSET_OOB(nbytes, offset, 1)) 1268 return 0; 1269 if (off) { 1270 switch (m->in_op & FILE_OPS_MASK) { 1271 case FILE_OPAND: 1272 offset = p->b & off; 1273 break; 1274 case FILE_OPOR: 1275 offset = p->b | off; 1276 break; 1277 case FILE_OPXOR: 1278 offset = p->b ^ off; 1279 break; 1280 case FILE_OPADD: 1281 offset = p->b + off; 1282 break; 1283 case FILE_OPMINUS: 1284 offset = p->b - off; 1285 break; 1286 case FILE_OPMULTIPLY: 1287 offset = p->b * off; 1288 break; 1289 case FILE_OPDIVIDE: 1290 offset = p->b / off; 1291 break; 1292 case FILE_OPMODULO: 1293 offset = p->b % off; 1294 break; 1295 } 1296 } else 1297 offset = p->b; 1298 if (m->in_op & FILE_OPINVERSE) 1299 offset = ~offset; 1300 break; 1301 case FILE_BESHORT: 1302 if (OFFSET_OOB(nbytes, offset, 2)) 1303 return 0; 1304 lhs = (p->hs[0] << 8) | p->hs[1]; 1305 if (off) { 1306 switch (m->in_op & FILE_OPS_MASK) { 1307 case FILE_OPAND: 1308 offset = lhs & off; 1309 break; 1310 case FILE_OPOR: 1311 offset = lhs | off; 1312 break; 1313 case FILE_OPXOR: 1314 offset = lhs ^ off; 1315 break; 1316 case FILE_OPADD: 1317 offset = lhs + off; 1318 break; 1319 case FILE_OPMINUS: 1320 offset = lhs - off; 1321 break; 1322 case FILE_OPMULTIPLY: 1323 offset = lhs * off; 1324 break; 1325 case FILE_OPDIVIDE: 1326 offset = lhs / off; 1327 break; 1328 case FILE_OPMODULO: 1329 offset = lhs % off; 1330 break; 1331 } 1332 } else 1333 offset = lhs; 1334 if (m->in_op & FILE_OPINVERSE) 1335 offset = ~offset; 1336 break; 1337 case FILE_LESHORT: 1338 if (OFFSET_OOB(nbytes, offset, 2)) 1339 return 0; 1340 lhs = (p->hs[1] << 8) | p->hs[0]; 1341 if (off) { 1342 switch (m->in_op & FILE_OPS_MASK) { 1343 case FILE_OPAND: 1344 offset = lhs & off; 1345 break; 1346 case FILE_OPOR: 1347 offset = lhs | off; 1348 break; 1349 case FILE_OPXOR: 1350 offset = lhs ^ off; 1351 break; 1352 case FILE_OPADD: 1353 offset = lhs + off; 1354 break; 1355 case FILE_OPMINUS: 1356 offset = lhs - off; 1357 break; 1358 case FILE_OPMULTIPLY: 1359 offset = lhs * off; 1360 break; 1361 case FILE_OPDIVIDE: 1362 offset = lhs / off; 1363 break; 1364 case FILE_OPMODULO: 1365 offset = lhs % off; 1366 break; 1367 } 1368 } else 1369 offset = lhs; 1370 if (m->in_op & FILE_OPINVERSE) 1371 offset = ~offset; 1372 break; 1373 case FILE_SHORT: 1374 if (OFFSET_OOB(nbytes, offset, 2)) 1375 return 0; 1376 if (off) { 1377 switch (m->in_op & FILE_OPS_MASK) { 1378 case FILE_OPAND: 1379 offset = p->h & off; 1380 break; 1381 case FILE_OPOR: 1382 offset = p->h | off; 1383 break; 1384 case FILE_OPXOR: 1385 offset = p->h ^ off; 1386 break; 1387 case FILE_OPADD: 1388 offset = p->h + off; 1389 break; 1390 case FILE_OPMINUS: 1391 offset = p->h - off; 1392 break; 1393 case FILE_OPMULTIPLY: 1394 offset = p->h * off; 1395 break; 1396 case FILE_OPDIVIDE: 1397 offset = p->h / off; 1398 break; 1399 case FILE_OPMODULO: 1400 offset = p->h % off; 1401 break; 1402 } 1403 } 1404 else 1405 offset = p->h; 1406 if (m->in_op & FILE_OPINVERSE) 1407 offset = ~offset; 1408 break; 1409 case FILE_BELONG: 1410 case FILE_BEID3: 1411 if (OFFSET_OOB(nbytes, offset, 4)) 1412 return 0; 1413 lhs = (p->hl[0] << 24) | (p->hl[1] << 16) | 1414 (p->hl[2] << 8) | p->hl[3]; 1415 if (off) { 1416 switch (m->in_op & FILE_OPS_MASK) { 1417 case FILE_OPAND: 1418 offset = lhs & off; 1419 break; 1420 case FILE_OPOR: 1421 offset = lhs | off; 1422 break; 1423 case FILE_OPXOR: 1424 offset = lhs ^ off; 1425 break; 1426 case FILE_OPADD: 1427 offset = lhs + off; 1428 break; 1429 case FILE_OPMINUS: 1430 offset = lhs - off; 1431 break; 1432 case FILE_OPMULTIPLY: 1433 offset = lhs * off; 1434 break; 1435 case FILE_OPDIVIDE: 1436 offset = lhs / off; 1437 break; 1438 case FILE_OPMODULO: 1439 offset = lhs % off; 1440 break; 1441 } 1442 } else 1443 offset = lhs; 1444 if (m->in_op & FILE_OPINVERSE) 1445 offset = ~offset; 1446 break; 1447 case FILE_LELONG: 1448 case FILE_LEID3: 1449 if (OFFSET_OOB(nbytes, offset, 4)) 1450 return 0; 1451 lhs = (p->hl[3] << 24) | (p->hl[2] << 16) | 1452 (p->hl[1] << 8) | p->hl[0]; 1453 if (off) { 1454 switch (m->in_op & FILE_OPS_MASK) { 1455 case FILE_OPAND: 1456 offset = lhs & off; 1457 break; 1458 case FILE_OPOR: 1459 offset = lhs | off; 1460 break; 1461 case FILE_OPXOR: 1462 offset = lhs ^ off; 1463 break; 1464 case FILE_OPADD: 1465 offset = lhs + off; 1466 break; 1467 case FILE_OPMINUS: 1468 offset = lhs - off; 1469 break; 1470 case FILE_OPMULTIPLY: 1471 offset = lhs * off; 1472 break; 1473 case FILE_OPDIVIDE: 1474 offset = lhs / off; 1475 break; 1476 case FILE_OPMODULO: 1477 offset = lhs % off; 1478 break; 1479 } 1480 } else 1481 offset = lhs; 1482 if (m->in_op & FILE_OPINVERSE) 1483 offset = ~offset; 1484 break; 1485 case FILE_MELONG: 1486 if (OFFSET_OOB(nbytes, offset, 4)) 1487 return 0; 1488 lhs = (p->hl[1] << 24) | (p->hl[0] << 16) | 1489 (p->hl[3] << 8) | p->hl[2]; 1490 if (off) { 1491 switch (m->in_op & FILE_OPS_MASK) { 1492 case FILE_OPAND: 1493 offset = lhs & off; 1494 break; 1495 case FILE_OPOR: 1496 offset = lhs | off; 1497 break; 1498 case FILE_OPXOR: 1499 offset = lhs ^ off; 1500 break; 1501 case FILE_OPADD: 1502 offset = lhs + off; 1503 break; 1504 case FILE_OPMINUS: 1505 offset = lhs - off; 1506 break; 1507 case FILE_OPMULTIPLY: 1508 offset = lhs * off; 1509 break; 1510 case FILE_OPDIVIDE: 1511 offset = lhs / off; 1512 break; 1513 case FILE_OPMODULO: 1514 offset = lhs % off; 1515 break; 1516 } 1517 } else 1518 offset = lhs; 1519 if (m->in_op & FILE_OPINVERSE) 1520 offset = ~offset; 1521 break; 1522 case FILE_LONG: 1523 if (OFFSET_OOB(nbytes, offset, 4)) 1524 return 0; 1525 if (off) { 1526 switch (m->in_op & FILE_OPS_MASK) { 1527 case FILE_OPAND: 1528 offset = p->l & off; 1529 break; 1530 case FILE_OPOR: 1531 offset = p->l | off; 1532 break; 1533 case FILE_OPXOR: 1534 offset = p->l ^ off; 1535 break; 1536 case FILE_OPADD: 1537 offset = p->l + off; 1538 break; 1539 case FILE_OPMINUS: 1540 offset = p->l - off; 1541 break; 1542 case FILE_OPMULTIPLY: 1543 offset = p->l * off; 1544 break; 1545 case FILE_OPDIVIDE: 1546 offset = p->l / off; 1547 break; 1548 case FILE_OPMODULO: 1549 offset = p->l % off; 1550 break; 1551 } 1552 } else 1553 offset = p->l; 1554 if (m->in_op & FILE_OPINVERSE) 1555 offset = ~offset; 1556 break; 1557 default: 1558 break; 1559 } 1560 1561 switch (in_type) { 1562 case FILE_LEID3: 1563 case FILE_BEID3: 1564 offset = ((((offset >> 0) & 0x7f) << 0) | 1565 (((offset >> 8) & 0x7f) << 7) | 1566 (((offset >> 16) & 0x7f) << 14) | 1567 (((offset >> 24) & 0x7f) << 21)) + 10; 1568 break; 1569 default: 1570 break; 1571 } 1572 1573 if (m->flag & INDIROFFADD) { 1574 offset += ms->c.li[cont_level-1].off; 1575 if (offset == 0) { 1576 if ((ms->flags & MAGIC_DEBUG) != 0) 1577 fprintf(stderr, 1578 "indirect *zero* offset\n"); 1579 return 0; 1580 } 1581 if ((ms->flags & MAGIC_DEBUG) != 0) 1582 fprintf(stderr, "indirect +offs=%u\n", offset); 1583 } 1584 if (mcopy(ms, p, m->type, 0, s, offset, nbytes, m) == -1) 1585 return -1; 1586 ms->offset = offset; 1587 1588 if ((ms->flags & MAGIC_DEBUG) != 0) { 1589 mdebug(offset, (char *)(void *)p, 1590 sizeof(union VALUETYPE)); 1591 #ifndef COMPILE_ONLY 1592 file_mdump(m); 1593 #endif 1594 } 1595 } 1596 1597 /* Verify we have enough data to match magic type */ 1598 switch (m->type) { 1599 case FILE_BYTE: 1600 if (OFFSET_OOB(nbytes, offset, 1)) 1601 return 0; 1602 break; 1603 1604 case FILE_SHORT: 1605 case FILE_BESHORT: 1606 case FILE_LESHORT: 1607 if (OFFSET_OOB(nbytes, offset, 2)) 1608 return 0; 1609 break; 1610 1611 case FILE_LONG: 1612 case FILE_BELONG: 1613 case FILE_LELONG: 1614 case FILE_MELONG: 1615 case FILE_DATE: 1616 case FILE_BEDATE: 1617 case FILE_LEDATE: 1618 case FILE_MEDATE: 1619 case FILE_LDATE: 1620 case FILE_BELDATE: 1621 case FILE_LELDATE: 1622 case FILE_MELDATE: 1623 case FILE_FLOAT: 1624 case FILE_BEFLOAT: 1625 case FILE_LEFLOAT: 1626 if (OFFSET_OOB(nbytes, offset, 4)) 1627 return 0; 1628 break; 1629 1630 case FILE_DOUBLE: 1631 case FILE_BEDOUBLE: 1632 case FILE_LEDOUBLE: 1633 if (OFFSET_OOB(nbytes, offset, 8)) 1634 return 0; 1635 break; 1636 1637 case FILE_STRING: 1638 case FILE_PSTRING: 1639 case FILE_SEARCH: 1640 if (OFFSET_OOB(nbytes, offset, m->vallen)) 1641 return 0; 1642 break; 1643 1644 case FILE_REGEX: 1645 if (nbytes < offset) 1646 return 0; 1647 break; 1648 1649 case FILE_INDIRECT: 1650 if (offset == 0) 1651 return 0; 1652 if (nbytes < offset) 1653 return 0; 1654 sbuf = ms->o.buf; 1655 soffset = ms->offset; 1656 ms->o.buf = NULL; 1657 ms->offset = 0; 1658 rv = file_softmagic(ms, s + offset, nbytes - offset, 1659 recursion_level, BINTEST, text); 1660 if ((ms->flags & MAGIC_DEBUG) != 0) 1661 fprintf(stderr, "indirect @offs=%u[%d]\n", offset, rv); 1662 rbuf = ms->o.buf; 1663 ms->o.buf = sbuf; 1664 ms->offset = soffset; 1665 if (rv == 1) { 1666 if ((ms->flags & (MAGIC_MIME|MAGIC_APPLE)) == 0 && 1667 file_printf(ms, F(ms, m, "%u"), offset) == -1) { 1668 free(rbuf); 1669 return -1; 1670 } 1671 if (file_printf(ms, "%s", rbuf) == -1) { 1672 free(rbuf); 1673 return -1; 1674 } 1675 } 1676 free(rbuf); 1677 return rv; 1678 1679 case FILE_USE: 1680 if (nbytes < offset) 1681 return 0; 1682 sbuf = m->value.s; 1683 if (*sbuf == '^') { 1684 sbuf++; 1685 flip = !flip; 1686 } 1687 if (file_magicfind(ms, sbuf, &ml) == -1) { 1688 file_error(ms, 0, "cannot find entry `%s'", sbuf); 1689 return -1; 1690 } 1691 1692 oneed_separator = *need_separator; 1693 if (m->flag & NOSPACE) 1694 *need_separator = 0; 1695 rv = match(ms, ml.magic, ml.nmagic, s, nbytes, offset + o, 1696 mode, text, flip, recursion_level, printed_something, 1697 need_separator, returnval); 1698 if (rv != 1) 1699 *need_separator = oneed_separator; 1700 return rv; 1701 1702 case FILE_NAME: 1703 if (file_printf(ms, "%s", m->desc) == -1) 1704 return -1; 1705 return 1; 1706 case FILE_DEFAULT: /* nothing to check */ 1707 case FILE_CLEAR: 1708 default: 1709 break; 1710 } 1711 if (!mconvert(ms, m, flip)) 1712 return 0; 1713 return 1; 1714 } 1715 1716 private uint64_t 1717 file_strncmp(const char *s1, const char *s2, size_t len, uint32_t flags) 1718 { 1719 /* 1720 * Convert the source args to unsigned here so that (1) the 1721 * compare will be unsigned as it is in strncmp() and (2) so 1722 * the ctype functions will work correctly without extra 1723 * casting. 1724 */ 1725 const unsigned char *a = (const unsigned char *)s1; 1726 const unsigned char *b = (const unsigned char *)s2; 1727 uint64_t v; 1728 1729 /* 1730 * What we want here is v = strncmp(s1, s2, len), 1731 * but ignoring any nulls. 1732 */ 1733 v = 0; 1734 if (0L == flags) { /* normal string: do it fast */ 1735 while (len-- > 0) 1736 if ((v = *b++ - *a++) != '\0') 1737 break; 1738 } 1739 else { /* combine the others */ 1740 while (len-- > 0) { 1741 if ((flags & STRING_IGNORE_LOWERCASE) && 1742 islower(*a)) { 1743 if ((v = tolower(*b++) - *a++) != '\0') 1744 break; 1745 } 1746 else if ((flags & STRING_IGNORE_UPPERCASE) && 1747 isupper(*a)) { 1748 if ((v = toupper(*b++) - *a++) != '\0') 1749 break; 1750 } 1751 else if ((flags & STRING_COMPACT_WHITESPACE) && 1752 isspace(*a)) { 1753 a++; 1754 if (isspace(*b++)) { 1755 if (!isspace(*a)) 1756 while (isspace(*b)) 1757 b++; 1758 } 1759 else { 1760 v = 1; 1761 break; 1762 } 1763 } 1764 else if ((flags & STRING_COMPACT_OPTIONAL_WHITESPACE) && 1765 isspace(*a)) { 1766 a++; 1767 while (isspace(*b)) 1768 b++; 1769 } 1770 else { 1771 if ((v = *b++ - *a++) != '\0') 1772 break; 1773 } 1774 } 1775 } 1776 return v; 1777 } 1778 1779 private uint64_t 1780 file_strncmp16(const char *a, const char *b, size_t len, uint32_t flags) 1781 { 1782 /* 1783 * XXX - The 16-bit string compare probably needs to be done 1784 * differently, especially if the flags are to be supported. 1785 * At the moment, I am unsure. 1786 */ 1787 flags = 0; 1788 return file_strncmp(a, b, len, flags); 1789 } 1790 1791 private int 1792 magiccheck(struct magic_set *ms, struct magic *m) 1793 { 1794 uint64_t l = m->value.q; 1795 uint64_t v; 1796 float fl, fv; 1797 double dl, dv; 1798 int matched; 1799 union VALUETYPE *p = &ms->ms_value; 1800 1801 switch (m->type) { 1802 case FILE_BYTE: 1803 v = p->b; 1804 break; 1805 1806 case FILE_SHORT: 1807 case FILE_BESHORT: 1808 case FILE_LESHORT: 1809 v = p->h; 1810 break; 1811 1812 case FILE_LONG: 1813 case FILE_BELONG: 1814 case FILE_LELONG: 1815 case FILE_MELONG: 1816 case FILE_DATE: 1817 case FILE_BEDATE: 1818 case FILE_LEDATE: 1819 case FILE_MEDATE: 1820 case FILE_LDATE: 1821 case FILE_BELDATE: 1822 case FILE_LELDATE: 1823 case FILE_MELDATE: 1824 v = p->l; 1825 break; 1826 1827 case FILE_QUAD: 1828 case FILE_LEQUAD: 1829 case FILE_BEQUAD: 1830 case FILE_QDATE: 1831 case FILE_BEQDATE: 1832 case FILE_LEQDATE: 1833 case FILE_QLDATE: 1834 case FILE_BEQLDATE: 1835 case FILE_LEQLDATE: 1836 case FILE_QWDATE: 1837 case FILE_BEQWDATE: 1838 case FILE_LEQWDATE: 1839 v = p->q; 1840 break; 1841 1842 case FILE_FLOAT: 1843 case FILE_BEFLOAT: 1844 case FILE_LEFLOAT: 1845 fl = m->value.f; 1846 fv = p->f; 1847 switch (m->reln) { 1848 case 'x': 1849 matched = 1; 1850 break; 1851 1852 case '!': 1853 matched = fv != fl; 1854 break; 1855 1856 case '=': 1857 matched = fv == fl; 1858 break; 1859 1860 case '>': 1861 matched = fv > fl; 1862 break; 1863 1864 case '<': 1865 matched = fv < fl; 1866 break; 1867 1868 default: 1869 file_magerror(ms, "cannot happen with float: invalid relation `%c'", 1870 m->reln); 1871 return -1; 1872 } 1873 return matched; 1874 1875 case FILE_DOUBLE: 1876 case FILE_BEDOUBLE: 1877 case FILE_LEDOUBLE: 1878 dl = m->value.d; 1879 dv = p->d; 1880 switch (m->reln) { 1881 case 'x': 1882 matched = 1; 1883 break; 1884 1885 case '!': 1886 matched = dv != dl; 1887 break; 1888 1889 case '=': 1890 matched = dv == dl; 1891 break; 1892 1893 case '>': 1894 matched = dv > dl; 1895 break; 1896 1897 case '<': 1898 matched = dv < dl; 1899 break; 1900 1901 default: 1902 file_magerror(ms, "cannot happen with double: invalid relation `%c'", m->reln); 1903 return -1; 1904 } 1905 return matched; 1906 1907 case FILE_DEFAULT: 1908 case FILE_CLEAR: 1909 l = 0; 1910 v = 0; 1911 break; 1912 1913 case FILE_STRING: 1914 case FILE_PSTRING: 1915 l = 0; 1916 v = file_strncmp(m->value.s, p->s, (size_t)m->vallen, m->str_flags); 1917 break; 1918 1919 case FILE_BESTRING16: 1920 case FILE_LESTRING16: 1921 l = 0; 1922 v = file_strncmp16(m->value.s, p->s, (size_t)m->vallen, m->str_flags); 1923 break; 1924 1925 case FILE_SEARCH: { /* search ms->search.s for the string m->value.s */ 1926 size_t slen; 1927 size_t idx; 1928 1929 if (ms->search.s == NULL) 1930 return 0; 1931 1932 slen = MIN(m->vallen, sizeof(m->value.s)); 1933 l = 0; 1934 v = 0; 1935 1936 for (idx = 0; m->str_range == 0 || idx < m->str_range; idx++) { 1937 if (slen + idx > ms->search.s_len) 1938 break; 1939 1940 v = file_strncmp(m->value.s, ms->search.s + idx, slen, 1941 m->str_flags); 1942 if (v == 0) { /* found match */ 1943 ms->search.offset += idx; 1944 break; 1945 } 1946 } 1947 break; 1948 } 1949 case FILE_REGEX: { 1950 int rc; 1951 file_regex_t rx; 1952 1953 if (ms->search.s == NULL) 1954 return 0; 1955 1956 l = 0; 1957 rc = file_regcomp(&rx, m->value.s, 1958 REG_EXTENDED|REG_NEWLINE| 1959 ((m->str_flags & STRING_IGNORE_CASE) ? REG_ICASE : 0)); 1960 if (rc) { 1961 file_regerror(&rx, rc, ms); 1962 v = (uint64_t)-1; 1963 } else { 1964 regmatch_t pmatch[1]; 1965 size_t slen = ms->search.s_len; 1966 #ifndef REG_STARTEND 1967 #define REG_STARTEND 0 1968 char c; 1969 if (slen != 0) 1970 slen--; 1971 c = ms->search.s[slen]; 1972 ((char *)(intptr_t)ms->search.s)[slen] = '\0'; 1973 #else 1974 pmatch[0].rm_so = 0; 1975 pmatch[0].rm_eo = slen; 1976 #endif 1977 rc = file_regexec(&rx, (const char *)ms->search.s, 1978 1, pmatch, REG_STARTEND); 1979 #if REG_STARTEND == 0 1980 ((char *)(intptr_t)ms->search.s)[l] = c; 1981 #endif 1982 switch (rc) { 1983 case 0: 1984 ms->search.s += (int)pmatch[0].rm_so; 1985 ms->search.offset += (size_t)pmatch[0].rm_so; 1986 ms->search.rm_len = 1987 (size_t)(pmatch[0].rm_eo - pmatch[0].rm_so); 1988 v = 0; 1989 break; 1990 1991 case REG_NOMATCH: 1992 v = 1; 1993 break; 1994 1995 default: 1996 file_regerror(&rx, rc, ms); 1997 v = (uint64_t)-1; 1998 break; 1999 } 2000 } 2001 file_regfree(&rx); 2002 if (v == (uint64_t)-1) 2003 return -1; 2004 break; 2005 } 2006 case FILE_INDIRECT: 2007 case FILE_USE: 2008 case FILE_NAME: 2009 return 1; 2010 default: 2011 file_magerror(ms, "invalid type %d in magiccheck()", m->type); 2012 return -1; 2013 } 2014 2015 v = file_signextend(ms, m, v); 2016 2017 switch (m->reln) { 2018 case 'x': 2019 if ((ms->flags & MAGIC_DEBUG) != 0) 2020 (void) fprintf(stderr, "%" INT64_T_FORMAT 2021 "u == *any* = 1\n", (unsigned long long)v); 2022 matched = 1; 2023 break; 2024 2025 case '!': 2026 matched = v != l; 2027 if ((ms->flags & MAGIC_DEBUG) != 0) 2028 (void) fprintf(stderr, "%" INT64_T_FORMAT "u != %" 2029 INT64_T_FORMAT "u = %d\n", (unsigned long long)v, 2030 (unsigned long long)l, matched); 2031 break; 2032 2033 case '=': 2034 matched = v == l; 2035 if ((ms->flags & MAGIC_DEBUG) != 0) 2036 (void) fprintf(stderr, "%" INT64_T_FORMAT "u == %" 2037 INT64_T_FORMAT "u = %d\n", (unsigned long long)v, 2038 (unsigned long long)l, matched); 2039 break; 2040 2041 case '>': 2042 if (m->flag & UNSIGNED) { 2043 matched = v > l; 2044 if ((ms->flags & MAGIC_DEBUG) != 0) 2045 (void) fprintf(stderr, "%" INT64_T_FORMAT 2046 "u > %" INT64_T_FORMAT "u = %d\n", 2047 (unsigned long long)v, 2048 (unsigned long long)l, matched); 2049 } 2050 else { 2051 matched = (int64_t) v > (int64_t) l; 2052 if ((ms->flags & MAGIC_DEBUG) != 0) 2053 (void) fprintf(stderr, "%" INT64_T_FORMAT 2054 "d > %" INT64_T_FORMAT "d = %d\n", 2055 (long long)v, (long long)l, matched); 2056 } 2057 break; 2058 2059 case '<': 2060 if (m->flag & UNSIGNED) { 2061 matched = v < l; 2062 if ((ms->flags & MAGIC_DEBUG) != 0) 2063 (void) fprintf(stderr, "%" INT64_T_FORMAT 2064 "u < %" INT64_T_FORMAT "u = %d\n", 2065 (unsigned long long)v, 2066 (unsigned long long)l, matched); 2067 } 2068 else { 2069 matched = (int64_t) v < (int64_t) l; 2070 if ((ms->flags & MAGIC_DEBUG) != 0) 2071 (void) fprintf(stderr, "%" INT64_T_FORMAT 2072 "d < %" INT64_T_FORMAT "d = %d\n", 2073 (long long)v, (long long)l, matched); 2074 } 2075 break; 2076 2077 case '&': 2078 matched = (v & l) == l; 2079 if ((ms->flags & MAGIC_DEBUG) != 0) 2080 (void) fprintf(stderr, "((%" INT64_T_FORMAT "x & %" 2081 INT64_T_FORMAT "x) == %" INT64_T_FORMAT 2082 "x) = %d\n", (unsigned long long)v, 2083 (unsigned long long)l, (unsigned long long)l, 2084 matched); 2085 break; 2086 2087 case '^': 2088 matched = (v & l) != l; 2089 if ((ms->flags & MAGIC_DEBUG) != 0) 2090 (void) fprintf(stderr, "((%" INT64_T_FORMAT "x & %" 2091 INT64_T_FORMAT "x) != %" INT64_T_FORMAT 2092 "x) = %d\n", (unsigned long long)v, 2093 (unsigned long long)l, (unsigned long long)l, 2094 matched); 2095 break; 2096 2097 default: 2098 file_magerror(ms, "cannot happen: invalid relation `%c'", 2099 m->reln); 2100 return -1; 2101 } 2102 2103 return matched; 2104 } 2105 2106 private int 2107 handle_annotation(struct magic_set *ms, struct magic *m) 2108 { 2109 if (ms->flags & MAGIC_APPLE) { 2110 if (file_printf(ms, "%.8s", m->apple) == -1) 2111 return -1; 2112 return 1; 2113 } 2114 if ((ms->flags & MAGIC_MIME_TYPE) && m->mimetype[0]) { 2115 if (file_printf(ms, "%s", m->mimetype) == -1) 2116 return -1; 2117 return 1; 2118 } 2119 return 0; 2120 } 2121 2122 private int 2123 print_sep(struct magic_set *ms, int firstline) 2124 { 2125 if (ms->flags & MAGIC_MIME) 2126 return 0; 2127 if (firstline) 2128 return 0; 2129 /* 2130 * we found another match 2131 * put a newline and '-' to do some simple formatting 2132 */ 2133 return file_printf(ms, "\n- "); 2134 } 2135