1 /* $NetBSD: softmagic.c,v 1.6 2012/04/07 17:30:56 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.6 2012/04/07 17:30:56 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 int rv; 1032 char *sbuf, *rbuf; 1033 union VALUETYPE *p = &ms->ms_value; 1034 1035 if (mcopy(ms, p, m->type, m->flag & INDIR, s, offset, nbytes, count) == -1) 1036 return -1; 1037 1038 if ((ms->flags & MAGIC_DEBUG) != 0) { 1039 mdebug(offset, (char *)(void *)p, sizeof(union VALUETYPE)); 1040 #ifndef COMPILE_ONLY 1041 file_mdump(m); 1042 #endif 1043 } 1044 1045 if (m->flag & INDIR) { 1046 int off = m->in_offset; 1047 if (m->in_op & FILE_OPINDIRECT) { 1048 const union VALUETYPE *q = CAST(const union VALUETYPE *, 1049 ((const void *)(s + offset + off))); 1050 switch (m->in_type) { 1051 case FILE_BYTE: 1052 off = q->b; 1053 break; 1054 case FILE_SHORT: 1055 off = q->h; 1056 break; 1057 case FILE_BESHORT: 1058 off = (short)((q->hs[0]<<8)|(q->hs[1])); 1059 break; 1060 case FILE_LESHORT: 1061 off = (short)((q->hs[1]<<8)|(q->hs[0])); 1062 break; 1063 case FILE_LONG: 1064 off = q->l; 1065 break; 1066 case FILE_BELONG: 1067 case FILE_BEID3: 1068 off = (int32_t)((q->hl[0]<<24)|(q->hl[1]<<16)| 1069 (q->hl[2]<<8)|(q->hl[3])); 1070 break; 1071 case FILE_LEID3: 1072 case FILE_LELONG: 1073 off = (int32_t)((q->hl[3]<<24)|(q->hl[2]<<16)| 1074 (q->hl[1]<<8)|(q->hl[0])); 1075 break; 1076 case FILE_MELONG: 1077 off = (int32_t)((q->hl[1]<<24)|(q->hl[0]<<16)| 1078 (q->hl[3]<<8)|(q->hl[2])); 1079 break; 1080 } 1081 if ((ms->flags & MAGIC_DEBUG) != 0) 1082 fprintf(stderr, "indirect offs=%u\n", off); 1083 } 1084 switch (m->in_type) { 1085 case FILE_BYTE: 1086 if (nbytes < (offset + 1)) 1087 return 0; 1088 if (off) { 1089 switch (m->in_op & FILE_OPS_MASK) { 1090 case FILE_OPAND: 1091 offset = p->b & off; 1092 break; 1093 case FILE_OPOR: 1094 offset = p->b | off; 1095 break; 1096 case FILE_OPXOR: 1097 offset = p->b ^ off; 1098 break; 1099 case FILE_OPADD: 1100 offset = p->b + off; 1101 break; 1102 case FILE_OPMINUS: 1103 offset = p->b - off; 1104 break; 1105 case FILE_OPMULTIPLY: 1106 offset = p->b * off; 1107 break; 1108 case FILE_OPDIVIDE: 1109 offset = p->b / off; 1110 break; 1111 case FILE_OPMODULO: 1112 offset = p->b % off; 1113 break; 1114 } 1115 } else 1116 offset = p->b; 1117 if (m->in_op & FILE_OPINVERSE) 1118 offset = ~offset; 1119 break; 1120 case FILE_BESHORT: 1121 if (nbytes < (offset + 2)) 1122 return 0; 1123 if (off) { 1124 switch (m->in_op & FILE_OPS_MASK) { 1125 case FILE_OPAND: 1126 offset = (short)((p->hs[0]<<8)| 1127 (p->hs[1])) & 1128 off; 1129 break; 1130 case FILE_OPOR: 1131 offset = (short)((p->hs[0]<<8)| 1132 (p->hs[1])) | 1133 off; 1134 break; 1135 case FILE_OPXOR: 1136 offset = (short)((p->hs[0]<<8)| 1137 (p->hs[1])) ^ 1138 off; 1139 break; 1140 case FILE_OPADD: 1141 offset = (short)((p->hs[0]<<8)| 1142 (p->hs[1])) + 1143 off; 1144 break; 1145 case FILE_OPMINUS: 1146 offset = (short)((p->hs[0]<<8)| 1147 (p->hs[1])) - 1148 off; 1149 break; 1150 case FILE_OPMULTIPLY: 1151 offset = (short)((p->hs[0]<<8)| 1152 (p->hs[1])) * 1153 off; 1154 break; 1155 case FILE_OPDIVIDE: 1156 offset = (short)((p->hs[0]<<8)| 1157 (p->hs[1])) / 1158 off; 1159 break; 1160 case FILE_OPMODULO: 1161 offset = (short)((p->hs[0]<<8)| 1162 (p->hs[1])) % 1163 off; 1164 break; 1165 } 1166 } else 1167 offset = (short)((p->hs[0]<<8)| 1168 (p->hs[1])); 1169 if (m->in_op & FILE_OPINVERSE) 1170 offset = ~offset; 1171 break; 1172 case FILE_LESHORT: 1173 if (nbytes < (offset + 2)) 1174 return 0; 1175 if (off) { 1176 switch (m->in_op & FILE_OPS_MASK) { 1177 case FILE_OPAND: 1178 offset = (short)((p->hs[1]<<8)| 1179 (p->hs[0])) & 1180 off; 1181 break; 1182 case FILE_OPOR: 1183 offset = (short)((p->hs[1]<<8)| 1184 (p->hs[0])) | 1185 off; 1186 break; 1187 case FILE_OPXOR: 1188 offset = (short)((p->hs[1]<<8)| 1189 (p->hs[0])) ^ 1190 off; 1191 break; 1192 case FILE_OPADD: 1193 offset = (short)((p->hs[1]<<8)| 1194 (p->hs[0])) + 1195 off; 1196 break; 1197 case FILE_OPMINUS: 1198 offset = (short)((p->hs[1]<<8)| 1199 (p->hs[0])) - 1200 off; 1201 break; 1202 case FILE_OPMULTIPLY: 1203 offset = (short)((p->hs[1]<<8)| 1204 (p->hs[0])) * 1205 off; 1206 break; 1207 case FILE_OPDIVIDE: 1208 offset = (short)((p->hs[1]<<8)| 1209 (p->hs[0])) / 1210 off; 1211 break; 1212 case FILE_OPMODULO: 1213 offset = (short)((p->hs[1]<<8)| 1214 (p->hs[0])) % 1215 off; 1216 break; 1217 } 1218 } else 1219 offset = (short)((p->hs[1]<<8)| 1220 (p->hs[0])); 1221 if (m->in_op & FILE_OPINVERSE) 1222 offset = ~offset; 1223 break; 1224 case FILE_SHORT: 1225 if (nbytes < (offset + 2)) 1226 return 0; 1227 if (off) { 1228 switch (m->in_op & FILE_OPS_MASK) { 1229 case FILE_OPAND: 1230 offset = p->h & off; 1231 break; 1232 case FILE_OPOR: 1233 offset = p->h | off; 1234 break; 1235 case FILE_OPXOR: 1236 offset = p->h ^ off; 1237 break; 1238 case FILE_OPADD: 1239 offset = p->h + off; 1240 break; 1241 case FILE_OPMINUS: 1242 offset = p->h - off; 1243 break; 1244 case FILE_OPMULTIPLY: 1245 offset = p->h * off; 1246 break; 1247 case FILE_OPDIVIDE: 1248 offset = p->h / off; 1249 break; 1250 case FILE_OPMODULO: 1251 offset = p->h % off; 1252 break; 1253 } 1254 } 1255 else 1256 offset = p->h; 1257 if (m->in_op & FILE_OPINVERSE) 1258 offset = ~offset; 1259 break; 1260 case FILE_BELONG: 1261 case FILE_BEID3: 1262 if (nbytes < (offset + 4)) 1263 return 0; 1264 if (off) { 1265 switch (m->in_op & FILE_OPS_MASK) { 1266 case FILE_OPAND: 1267 offset = (int32_t)((p->hl[0]<<24)| 1268 (p->hl[1]<<16)| 1269 (p->hl[2]<<8)| 1270 (p->hl[3])) & 1271 off; 1272 break; 1273 case FILE_OPOR: 1274 offset = (int32_t)((p->hl[0]<<24)| 1275 (p->hl[1]<<16)| 1276 (p->hl[2]<<8)| 1277 (p->hl[3])) | 1278 off; 1279 break; 1280 case FILE_OPXOR: 1281 offset = (int32_t)((p->hl[0]<<24)| 1282 (p->hl[1]<<16)| 1283 (p->hl[2]<<8)| 1284 (p->hl[3])) ^ 1285 off; 1286 break; 1287 case FILE_OPADD: 1288 offset = (int32_t)((p->hl[0]<<24)| 1289 (p->hl[1]<<16)| 1290 (p->hl[2]<<8)| 1291 (p->hl[3])) + 1292 off; 1293 break; 1294 case FILE_OPMINUS: 1295 offset = (int32_t)((p->hl[0]<<24)| 1296 (p->hl[1]<<16)| 1297 (p->hl[2]<<8)| 1298 (p->hl[3])) - 1299 off; 1300 break; 1301 case FILE_OPMULTIPLY: 1302 offset = (int32_t)((p->hl[0]<<24)| 1303 (p->hl[1]<<16)| 1304 (p->hl[2]<<8)| 1305 (p->hl[3])) * 1306 off; 1307 break; 1308 case FILE_OPDIVIDE: 1309 offset = (int32_t)((p->hl[0]<<24)| 1310 (p->hl[1]<<16)| 1311 (p->hl[2]<<8)| 1312 (p->hl[3])) / 1313 off; 1314 break; 1315 case FILE_OPMODULO: 1316 offset = (int32_t)((p->hl[0]<<24)| 1317 (p->hl[1]<<16)| 1318 (p->hl[2]<<8)| 1319 (p->hl[3])) % 1320 off; 1321 break; 1322 } 1323 } else 1324 offset = (int32_t)((p->hl[0]<<24)| 1325 (p->hl[1]<<16)| 1326 (p->hl[2]<<8)| 1327 (p->hl[3])); 1328 if (m->in_op & FILE_OPINVERSE) 1329 offset = ~offset; 1330 break; 1331 case FILE_LELONG: 1332 case FILE_LEID3: 1333 if (nbytes < (offset + 4)) 1334 return 0; 1335 if (off) { 1336 switch (m->in_op & FILE_OPS_MASK) { 1337 case FILE_OPAND: 1338 offset = (int32_t)((p->hl[3]<<24)| 1339 (p->hl[2]<<16)| 1340 (p->hl[1]<<8)| 1341 (p->hl[0])) & 1342 off; 1343 break; 1344 case FILE_OPOR: 1345 offset = (int32_t)((p->hl[3]<<24)| 1346 (p->hl[2]<<16)| 1347 (p->hl[1]<<8)| 1348 (p->hl[0])) | 1349 off; 1350 break; 1351 case FILE_OPXOR: 1352 offset = (int32_t)((p->hl[3]<<24)| 1353 (p->hl[2]<<16)| 1354 (p->hl[1]<<8)| 1355 (p->hl[0])) ^ 1356 off; 1357 break; 1358 case FILE_OPADD: 1359 offset = (int32_t)((p->hl[3]<<24)| 1360 (p->hl[2]<<16)| 1361 (p->hl[1]<<8)| 1362 (p->hl[0])) + 1363 off; 1364 break; 1365 case FILE_OPMINUS: 1366 offset = (int32_t)((p->hl[3]<<24)| 1367 (p->hl[2]<<16)| 1368 (p->hl[1]<<8)| 1369 (p->hl[0])) - 1370 off; 1371 break; 1372 case FILE_OPMULTIPLY: 1373 offset = (int32_t)((p->hl[3]<<24)| 1374 (p->hl[2]<<16)| 1375 (p->hl[1]<<8)| 1376 (p->hl[0])) * 1377 off; 1378 break; 1379 case FILE_OPDIVIDE: 1380 offset = (int32_t)((p->hl[3]<<24)| 1381 (p->hl[2]<<16)| 1382 (p->hl[1]<<8)| 1383 (p->hl[0])) / 1384 off; 1385 break; 1386 case FILE_OPMODULO: 1387 offset = (int32_t)((p->hl[3]<<24)| 1388 (p->hl[2]<<16)| 1389 (p->hl[1]<<8)| 1390 (p->hl[0])) % 1391 off; 1392 break; 1393 } 1394 } else 1395 offset = (int32_t)((p->hl[3]<<24)| 1396 (p->hl[2]<<16)| 1397 (p->hl[1]<<8)| 1398 (p->hl[0])); 1399 if (m->in_op & FILE_OPINVERSE) 1400 offset = ~offset; 1401 break; 1402 case FILE_MELONG: 1403 if (nbytes < (offset + 4)) 1404 return 0; 1405 if (off) { 1406 switch (m->in_op & FILE_OPS_MASK) { 1407 case FILE_OPAND: 1408 offset = (int32_t)((p->hl[1]<<24)| 1409 (p->hl[0]<<16)| 1410 (p->hl[3]<<8)| 1411 (p->hl[2])) & 1412 off; 1413 break; 1414 case FILE_OPOR: 1415 offset = (int32_t)((p->hl[1]<<24)| 1416 (p->hl[0]<<16)| 1417 (p->hl[3]<<8)| 1418 (p->hl[2])) | 1419 off; 1420 break; 1421 case FILE_OPXOR: 1422 offset = (int32_t)((p->hl[1]<<24)| 1423 (p->hl[0]<<16)| 1424 (p->hl[3]<<8)| 1425 (p->hl[2])) ^ 1426 off; 1427 break; 1428 case FILE_OPADD: 1429 offset = (int32_t)((p->hl[1]<<24)| 1430 (p->hl[0]<<16)| 1431 (p->hl[3]<<8)| 1432 (p->hl[2])) + 1433 off; 1434 break; 1435 case FILE_OPMINUS: 1436 offset = (int32_t)((p->hl[1]<<24)| 1437 (p->hl[0]<<16)| 1438 (p->hl[3]<<8)| 1439 (p->hl[2])) - 1440 off; 1441 break; 1442 case FILE_OPMULTIPLY: 1443 offset = (int32_t)((p->hl[1]<<24)| 1444 (p->hl[0]<<16)| 1445 (p->hl[3]<<8)| 1446 (p->hl[2])) * 1447 off; 1448 break; 1449 case FILE_OPDIVIDE: 1450 offset = (int32_t)((p->hl[1]<<24)| 1451 (p->hl[0]<<16)| 1452 (p->hl[3]<<8)| 1453 (p->hl[2])) / 1454 off; 1455 break; 1456 case FILE_OPMODULO: 1457 offset = (int32_t)((p->hl[1]<<24)| 1458 (p->hl[0]<<16)| 1459 (p->hl[3]<<8)| 1460 (p->hl[2])) % 1461 off; 1462 break; 1463 } 1464 } else 1465 offset = (int32_t)((p->hl[1]<<24)| 1466 (p->hl[0]<<16)| 1467 (p->hl[3]<<8)| 1468 (p->hl[2])); 1469 if (m->in_op & FILE_OPINVERSE) 1470 offset = ~offset; 1471 break; 1472 case FILE_LONG: 1473 if (nbytes < (offset + 4)) 1474 return 0; 1475 if (off) { 1476 switch (m->in_op & FILE_OPS_MASK) { 1477 case FILE_OPAND: 1478 offset = p->l & off; 1479 break; 1480 case FILE_OPOR: 1481 offset = p->l | off; 1482 break; 1483 case FILE_OPXOR: 1484 offset = p->l ^ off; 1485 break; 1486 case FILE_OPADD: 1487 offset = p->l + off; 1488 break; 1489 case FILE_OPMINUS: 1490 offset = p->l - off; 1491 break; 1492 case FILE_OPMULTIPLY: 1493 offset = p->l * off; 1494 break; 1495 case FILE_OPDIVIDE: 1496 offset = p->l / off; 1497 break; 1498 case FILE_OPMODULO: 1499 offset = p->l % off; 1500 break; 1501 } 1502 } else 1503 offset = p->l; 1504 if (m->in_op & FILE_OPINVERSE) 1505 offset = ~offset; 1506 break; 1507 } 1508 1509 switch (m->in_type) { 1510 case FILE_LEID3: 1511 case FILE_BEID3: 1512 offset = ((((offset >> 0) & 0x7f) << 0) | 1513 (((offset >> 8) & 0x7f) << 7) | 1514 (((offset >> 16) & 0x7f) << 14) | 1515 (((offset >> 24) & 0x7f) << 21)) + 10; 1516 break; 1517 default: 1518 break; 1519 } 1520 1521 if (m->flag & INDIROFFADD) { 1522 offset += ms->c.li[cont_level-1].off; 1523 if ((ms->flags & MAGIC_DEBUG) != 0) 1524 fprintf(stderr, "indirect +offs=%u\n", offset); 1525 } 1526 if (mcopy(ms, p, m->type, 0, s, offset, nbytes, count) == -1) 1527 return -1; 1528 ms->offset = offset; 1529 1530 if ((ms->flags & MAGIC_DEBUG) != 0) { 1531 mdebug(offset, (char *)(void *)p, 1532 sizeof(union VALUETYPE)); 1533 #ifndef COMPILE_ONLY 1534 file_mdump(m); 1535 #endif 1536 } 1537 } 1538 1539 /* Verify we have enough data to match magic type */ 1540 switch (m->type) { 1541 case FILE_BYTE: 1542 if (nbytes < (offset + 1)) /* should alway be true */ 1543 return 0; 1544 break; 1545 1546 case FILE_SHORT: 1547 case FILE_BESHORT: 1548 case FILE_LESHORT: 1549 if (nbytes < (offset + 2)) 1550 return 0; 1551 break; 1552 1553 case FILE_LONG: 1554 case FILE_BELONG: 1555 case FILE_LELONG: 1556 case FILE_MELONG: 1557 case FILE_DATE: 1558 case FILE_BEDATE: 1559 case FILE_LEDATE: 1560 case FILE_MEDATE: 1561 case FILE_LDATE: 1562 case FILE_BELDATE: 1563 case FILE_LELDATE: 1564 case FILE_MELDATE: 1565 case FILE_FLOAT: 1566 case FILE_BEFLOAT: 1567 case FILE_LEFLOAT: 1568 if (nbytes < (offset + 4)) 1569 return 0; 1570 break; 1571 1572 case FILE_DOUBLE: 1573 case FILE_BEDOUBLE: 1574 case FILE_LEDOUBLE: 1575 if (nbytes < (offset + 8)) 1576 return 0; 1577 break; 1578 1579 case FILE_STRING: 1580 case FILE_PSTRING: 1581 case FILE_SEARCH: 1582 if (nbytes < (offset + m->vallen)) 1583 return 0; 1584 break; 1585 1586 case FILE_REGEX: 1587 if (nbytes < offset) 1588 return 0; 1589 break; 1590 1591 case FILE_INDIRECT: 1592 if (nbytes < offset) 1593 return 0; 1594 sbuf = ms->o.buf; 1595 ms->o.buf = NULL; 1596 rv = file_softmagic(ms, s + offset, nbytes - offset, 1597 BINTEST, text); 1598 if ((ms->flags & MAGIC_DEBUG) != 0) 1599 fprintf(stderr, "indirect @offs=%u[%d]\n", offset, rv); 1600 if (rv == 1) { 1601 rbuf = ms->o.buf; 1602 ms->o.buf = sbuf; 1603 if ((ms->flags & (MAGIC_MIME|MAGIC_APPLE)) == 0 && 1604 file_printf(ms, m->desc, offset) == -1) 1605 return -1; 1606 if (file_printf(ms, "%s", rbuf) == -1) 1607 return -1; 1608 free(rbuf); 1609 } else 1610 ms->o.buf = sbuf; 1611 return rv; 1612 1613 case FILE_DEFAULT: /* nothing to check */ 1614 default: 1615 break; 1616 } 1617 if (!mconvert(ms, m)) 1618 return 0; 1619 return 1; 1620 } 1621 1622 private uint64_t 1623 file_strncmp(const char *s1, const char *s2, size_t len, uint32_t flags) 1624 { 1625 /* 1626 * Convert the source args to unsigned here so that (1) the 1627 * compare will be unsigned as it is in strncmp() and (2) so 1628 * the ctype functions will work correctly without extra 1629 * casting. 1630 */ 1631 const unsigned char *a = (const unsigned char *)s1; 1632 const unsigned char *b = (const unsigned char *)s2; 1633 uint64_t v; 1634 1635 /* 1636 * What we want here is v = strncmp(s1, s2, len), 1637 * but ignoring any nulls. 1638 */ 1639 v = 0; 1640 if (0L == flags) { /* normal string: do it fast */ 1641 while (len-- > 0) 1642 if ((v = *b++ - *a++) != '\0') 1643 break; 1644 } 1645 else { /* combine the others */ 1646 while (len-- > 0) { 1647 if ((flags & STRING_IGNORE_LOWERCASE) && 1648 islower(*a)) { 1649 if ((v = tolower(*b++) - *a++) != '\0') 1650 break; 1651 } 1652 else if ((flags & STRING_IGNORE_UPPERCASE) && 1653 isupper(*a)) { 1654 if ((v = toupper(*b++) - *a++) != '\0') 1655 break; 1656 } 1657 else if ((flags & STRING_COMPACT_WHITESPACE) && 1658 isspace(*a)) { 1659 a++; 1660 if (isspace(*b++)) { 1661 if (!isspace(*a)) 1662 while (isspace(*b)) 1663 b++; 1664 } 1665 else { 1666 v = 1; 1667 break; 1668 } 1669 } 1670 else if ((flags & STRING_COMPACT_OPTIONAL_WHITESPACE) && 1671 isspace(*a)) { 1672 a++; 1673 while (isspace(*b)) 1674 b++; 1675 } 1676 else { 1677 if ((v = *b++ - *a++) != '\0') 1678 break; 1679 } 1680 } 1681 } 1682 return v; 1683 } 1684 1685 private uint64_t 1686 file_strncmp16(const char *a, const char *b, size_t len, uint32_t flags) 1687 { 1688 /* 1689 * XXX - The 16-bit string compare probably needs to be done 1690 * differently, especially if the flags are to be supported. 1691 * At the moment, I am unsure. 1692 */ 1693 flags = 0; 1694 return file_strncmp(a, b, len, flags); 1695 } 1696 1697 private int 1698 magiccheck(struct magic_set *ms, struct magic *m) 1699 { 1700 uint64_t l = m->value.q; 1701 uint64_t v; 1702 float fl, fv; 1703 double dl, dv; 1704 int matched; 1705 union VALUETYPE *p = &ms->ms_value; 1706 1707 switch (m->type) { 1708 case FILE_BYTE: 1709 v = p->b; 1710 break; 1711 1712 case FILE_SHORT: 1713 case FILE_BESHORT: 1714 case FILE_LESHORT: 1715 v = p->h; 1716 break; 1717 1718 case FILE_LONG: 1719 case FILE_BELONG: 1720 case FILE_LELONG: 1721 case FILE_MELONG: 1722 case FILE_DATE: 1723 case FILE_BEDATE: 1724 case FILE_LEDATE: 1725 case FILE_MEDATE: 1726 case FILE_LDATE: 1727 case FILE_BELDATE: 1728 case FILE_LELDATE: 1729 case FILE_MELDATE: 1730 v = p->l; 1731 break; 1732 1733 case FILE_QUAD: 1734 case FILE_LEQUAD: 1735 case FILE_BEQUAD: 1736 case FILE_QDATE: 1737 case FILE_BEQDATE: 1738 case FILE_LEQDATE: 1739 case FILE_QLDATE: 1740 case FILE_BEQLDATE: 1741 case FILE_LEQLDATE: 1742 v = p->q; 1743 break; 1744 1745 case FILE_FLOAT: 1746 case FILE_BEFLOAT: 1747 case FILE_LEFLOAT: 1748 fl = m->value.f; 1749 fv = p->f; 1750 switch (m->reln) { 1751 case 'x': 1752 matched = 1; 1753 break; 1754 1755 case '!': 1756 matched = fv != fl; 1757 break; 1758 1759 case '=': 1760 matched = fv == fl; 1761 break; 1762 1763 case '>': 1764 matched = fv > fl; 1765 break; 1766 1767 case '<': 1768 matched = fv < fl; 1769 break; 1770 1771 default: 1772 matched = 0; 1773 file_magerror(ms, "cannot happen with float: invalid relation `%c'", 1774 m->reln); 1775 return -1; 1776 } 1777 return matched; 1778 1779 case FILE_DOUBLE: 1780 case FILE_BEDOUBLE: 1781 case FILE_LEDOUBLE: 1782 dl = m->value.d; 1783 dv = p->d; 1784 switch (m->reln) { 1785 case 'x': 1786 matched = 1; 1787 break; 1788 1789 case '!': 1790 matched = dv != dl; 1791 break; 1792 1793 case '=': 1794 matched = dv == dl; 1795 break; 1796 1797 case '>': 1798 matched = dv > dl; 1799 break; 1800 1801 case '<': 1802 matched = dv < dl; 1803 break; 1804 1805 default: 1806 matched = 0; 1807 file_magerror(ms, "cannot happen with double: invalid relation `%c'", m->reln); 1808 return -1; 1809 } 1810 return matched; 1811 1812 case FILE_DEFAULT: 1813 l = 0; 1814 v = 0; 1815 break; 1816 1817 case FILE_STRING: 1818 case FILE_PSTRING: 1819 l = 0; 1820 v = file_strncmp(m->value.s, p->s, (size_t)m->vallen, m->str_flags); 1821 break; 1822 1823 case FILE_BESTRING16: 1824 case FILE_LESTRING16: 1825 l = 0; 1826 v = file_strncmp16(m->value.s, p->s, (size_t)m->vallen, m->str_flags); 1827 break; 1828 1829 case FILE_SEARCH: { /* search ms->search.s for the string m->value.s */ 1830 size_t slen; 1831 size_t idx; 1832 1833 if (ms->search.s == NULL) 1834 return 0; 1835 1836 slen = MIN(m->vallen, sizeof(m->value.s)); 1837 l = 0; 1838 v = 0; 1839 1840 for (idx = 0; m->str_range == 0 || idx < m->str_range; idx++) { 1841 if (slen + idx > ms->search.s_len) 1842 break; 1843 1844 v = file_strncmp(m->value.s, ms->search.s + idx, slen, m->str_flags); 1845 if (v == 0) { /* found match */ 1846 ms->search.offset += idx; 1847 break; 1848 } 1849 } 1850 break; 1851 } 1852 case FILE_REGEX: { 1853 int rc; 1854 regex_t rx; 1855 char errmsg[512]; 1856 1857 if (ms->search.s == NULL) 1858 return 0; 1859 1860 l = 0; 1861 rc = regcomp(&rx, m->value.s, 1862 REG_EXTENDED|REG_NEWLINE| 1863 ((m->str_flags & STRING_IGNORE_CASE) ? REG_ICASE : 0)); 1864 if (rc) { 1865 (void)regerror(rc, &rx, errmsg, sizeof(errmsg)); 1866 file_magerror(ms, "regex error %d, (%s)", 1867 rc, errmsg); 1868 v = (uint64_t)-1; 1869 } 1870 else { 1871 regmatch_t pmatch[1]; 1872 #ifndef REG_STARTEND 1873 #define REG_STARTEND 0 1874 size_t l = ms->search.s_len - 1; 1875 char c = ms->search.s[l]; 1876 ((char *)(intptr_t)ms->search.s)[l] = '\0'; 1877 #else 1878 pmatch[0].rm_so = 0; 1879 pmatch[0].rm_eo = ms->search.s_len; 1880 #endif 1881 rc = regexec(&rx, (const char *)ms->search.s, 1882 1, pmatch, REG_STARTEND); 1883 #if REG_STARTEND == 0 1884 ((char *)(intptr_t)ms->search.s)[l] = c; 1885 #endif 1886 switch (rc) { 1887 case 0: 1888 ms->search.s += (int)pmatch[0].rm_so; 1889 ms->search.offset += (size_t)pmatch[0].rm_so; 1890 ms->search.rm_len = 1891 (size_t)(pmatch[0].rm_eo - pmatch[0].rm_so); 1892 v = 0; 1893 break; 1894 1895 case REG_NOMATCH: 1896 v = 1; 1897 break; 1898 1899 default: 1900 (void)regerror(rc, &rx, errmsg, sizeof(errmsg)); 1901 file_magerror(ms, "regexec error %d, (%s)", 1902 rc, errmsg); 1903 v = (uint64_t)-1; 1904 break; 1905 } 1906 regfree(&rx); 1907 } 1908 if (v == (uint64_t)-1) 1909 return -1; 1910 break; 1911 } 1912 case FILE_INDIRECT: 1913 return 1; 1914 default: 1915 file_magerror(ms, "invalid type %d in magiccheck()", m->type); 1916 return -1; 1917 } 1918 1919 v = file_signextend(ms, m, v); 1920 1921 switch (m->reln) { 1922 case 'x': 1923 if ((ms->flags & MAGIC_DEBUG) != 0) 1924 (void) fprintf(stderr, "%" INT64_T_FORMAT 1925 "u == *any* = 1\n", (unsigned long long)v); 1926 matched = 1; 1927 break; 1928 1929 case '!': 1930 matched = v != l; 1931 if ((ms->flags & MAGIC_DEBUG) != 0) 1932 (void) fprintf(stderr, "%" INT64_T_FORMAT "u != %" 1933 INT64_T_FORMAT "u = %d\n", (unsigned long long)v, 1934 (unsigned long long)l, matched); 1935 break; 1936 1937 case '=': 1938 matched = v == l; 1939 if ((ms->flags & MAGIC_DEBUG) != 0) 1940 (void) fprintf(stderr, "%" INT64_T_FORMAT "u == %" 1941 INT64_T_FORMAT "u = %d\n", (unsigned long long)v, 1942 (unsigned long long)l, matched); 1943 break; 1944 1945 case '>': 1946 if (m->flag & UNSIGNED) { 1947 matched = v > l; 1948 if ((ms->flags & MAGIC_DEBUG) != 0) 1949 (void) fprintf(stderr, "%" INT64_T_FORMAT 1950 "u > %" INT64_T_FORMAT "u = %d\n", 1951 (unsigned long long)v, 1952 (unsigned long long)l, matched); 1953 } 1954 else { 1955 matched = (int64_t) v > (int64_t) l; 1956 if ((ms->flags & MAGIC_DEBUG) != 0) 1957 (void) fprintf(stderr, "%" INT64_T_FORMAT 1958 "d > %" INT64_T_FORMAT "d = %d\n", 1959 (long long)v, (long long)l, matched); 1960 } 1961 break; 1962 1963 case '<': 1964 if (m->flag & UNSIGNED) { 1965 matched = v < l; 1966 if ((ms->flags & MAGIC_DEBUG) != 0) 1967 (void) fprintf(stderr, "%" INT64_T_FORMAT 1968 "u < %" INT64_T_FORMAT "u = %d\n", 1969 (unsigned long long)v, 1970 (unsigned long long)l, matched); 1971 } 1972 else { 1973 matched = (int64_t) v < (int64_t) l; 1974 if ((ms->flags & MAGIC_DEBUG) != 0) 1975 (void) fprintf(stderr, "%" INT64_T_FORMAT 1976 "d < %" INT64_T_FORMAT "d = %d\n", 1977 (long long)v, (long long)l, matched); 1978 } 1979 break; 1980 1981 case '&': 1982 matched = (v & l) == l; 1983 if ((ms->flags & MAGIC_DEBUG) != 0) 1984 (void) fprintf(stderr, "((%" INT64_T_FORMAT "x & %" 1985 INT64_T_FORMAT "x) == %" INT64_T_FORMAT 1986 "x) = %d\n", (unsigned long long)v, 1987 (unsigned long long)l, (unsigned long long)l, 1988 matched); 1989 break; 1990 1991 case '^': 1992 matched = (v & l) != l; 1993 if ((ms->flags & MAGIC_DEBUG) != 0) 1994 (void) fprintf(stderr, "((%" INT64_T_FORMAT "x & %" 1995 INT64_T_FORMAT "x) != %" INT64_T_FORMAT 1996 "x) = %d\n", (unsigned long long)v, 1997 (unsigned long long)l, (unsigned long long)l, 1998 matched); 1999 break; 2000 2001 default: 2002 matched = 0; 2003 file_magerror(ms, "cannot happen: invalid relation `%c'", 2004 m->reln); 2005 return -1; 2006 } 2007 2008 return matched; 2009 } 2010 2011 private int 2012 handle_annotation(struct magic_set *ms, struct magic *m) 2013 { 2014 if (ms->flags & MAGIC_APPLE) { 2015 if (file_printf(ms, "%.8s", m->apple) == -1) 2016 return -1; 2017 return 1; 2018 } 2019 if ((ms->flags & MAGIC_MIME_TYPE) && m->mimetype[0]) { 2020 if (file_printf(ms, "%s", m->mimetype) == -1) 2021 return -1; 2022 return 1; 2023 } 2024 return 0; 2025 } 2026 2027 private int 2028 print_sep(struct magic_set *ms, int firstline) 2029 { 2030 if (ms->flags & MAGIC_MIME) 2031 return 0; 2032 if (firstline) 2033 return 0; 2034 /* 2035 * we found another match 2036 * put a newline and '-' to do some simple formatting 2037 */ 2038 return file_printf(ms, "\n- "); 2039 } 2040