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