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