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