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