softmagic.c revision 354939
1274116Sdteske/* 2274116Sdteske * Copyright (c) Ian F. Darwin 1986-1995. 3274116Sdteske * Software written by Ian F. Darwin and others; 4274116Sdteske * maintained 1995-present by Christos Zoulas and others. 5274116Sdteske * 6274116Sdteske * Redistribution and use in source and binary forms, with or without 7274116Sdteske * modification, are permitted provided that the following conditions 8274116Sdteske * are met: 9274116Sdteske * 1. Redistributions of source code must retain the above copyright 10274116Sdteske * notice immediately at the beginning of the file, without modification, 11274116Sdteske * this list of conditions, and the following disclaimer. 12274116Sdteske * 2. Redistributions in binary form must reproduce the above copyright 13274116Sdteske * notice, this list of conditions and the following disclaimer in the 14274116Sdteske * documentation and/or other materials provided with the distribution. 15274116Sdteske * 16274116Sdteske * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 17274116Sdteske * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18274116Sdteske * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19274116Sdteske * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR 20274116Sdteske * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21274116Sdteske * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22274116Sdteske * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23274116Sdteske * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24274116Sdteske * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25274116Sdteske * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26274116Sdteske * SUCH DAMAGE. 27274116Sdteske */ 28274116Sdteske/* 29274116Sdteske * softmagic - interpret variable magic from MAGIC 30274116Sdteske */ 31274116Sdteske 32274116Sdteske#include "file.h" 33274116Sdteske 34274116Sdteske#ifndef lint 35274116SdteskeFILE_RCSID("@(#)$File: softmagic.c,v 1.286 2019/05/17 02:24:59 christos Exp $") 36274116Sdteske#endif /* lint */ 37274116Sdteske 38274116Sdteske#include "magic.h" 39274116Sdteske#include <assert.h> 40274116Sdteske#include <string.h> 41274116Sdteske#include <ctype.h> 42274116Sdteske#include <stdlib.h> 43274116Sdteske#include <time.h> 44274116Sdteske#include "der.h" 45274116Sdteske 46274116Sdteskeprivate int match(struct magic_set *, struct magic *, uint32_t, 47274116Sdteske const struct buffer *, size_t, int, int, int, uint16_t *, 48274116Sdteske uint16_t *, int *, int *, int *, int *); 49274116Sdteskeprivate int mget(struct magic_set *, struct magic *, const struct buffer *, 50274116Sdteske const unsigned char *, size_t, 51274116Sdteske size_t, unsigned int, int, int, int, uint16_t *, 52274116Sdteske uint16_t *, int *, int *, int *, int *); 53274116Sdteskeprivate int msetoffset(struct magic_set *, struct magic *, struct buffer *, 54274116Sdteske const struct buffer *, size_t, unsigned int); 55274116Sdteskeprivate int magiccheck(struct magic_set *, struct magic *); 56274116Sdteskeprivate int32_t mprint(struct magic_set *, struct magic *); 57274116Sdteskeprivate int moffset(struct magic_set *, struct magic *, const struct buffer *, 58274116Sdteske int32_t *); 59274116Sdteskeprivate void mdebug(uint32_t, const char *, size_t); 60274116Sdteskeprivate int mcopy(struct magic_set *, union VALUETYPE *, int, int, 61274116Sdteske const unsigned char *, uint32_t, size_t, struct magic *); 62274116Sdteskeprivate int mconvert(struct magic_set *, struct magic *, int); 63274116Sdteskeprivate int print_sep(struct magic_set *, int); 64274116Sdteskeprivate int handle_annotation(struct magic_set *, struct magic *, int); 65274116Sdteskeprivate int cvt_8(union VALUETYPE *, const struct magic *); 66274116Sdteskeprivate int cvt_16(union VALUETYPE *, const struct magic *); 67274116Sdteskeprivate int cvt_32(union VALUETYPE *, const struct magic *); 68274116Sdteskeprivate int cvt_64(union VALUETYPE *, const struct magic *); 69274116Sdteske 70274116Sdteske#define OFFSET_OOB(n, o, i) ((n) < CAST(uint32_t, (o)) || (i) > ((n) - (o))) 71274116Sdteske#define BE64(p) ( \ 72274116Sdteske (CAST(uint64_t, (p)->hq[0])<<56)| \ 73274116Sdteske (CAST(uint64_t, (p)->hq[1])<<48)| \ 74274116Sdteske (CAST(uint64_t, (p)->hq[2])<<40)| \ 75274116Sdteske (CAST(uint64_t, (p)->hq[3])<<32)| \ 76274116Sdteske (CAST(uint64_t, (p)->hq[4])<<24)| \ 77274116Sdteske (CAST(uint64_t, (p)->hq[5])<<16)| \ 78274116Sdteske (CAST(uint64_t, (p)->hq[6])<<8)| \ 79274116Sdteske (CAST(uint64_t, (p)->hq[7]))) 80274116Sdteske#define LE64(p) ( \ 81274116Sdteske (CAST(uint64_t, (p)->hq[7])<<56)| \ 82274116Sdteske (CAST(uint64_t, (p)->hq[6])<<48)| \ 83274116Sdteske (CAST(uint64_t, (p)->hq[5])<<40)| \ 84274116Sdteske (CAST(uint64_t, (p)->hq[4])<<32)| \ 85274116Sdteske (CAST(uint64_t, (p)->hq[3])<<24)| \ 86274116Sdteske (CAST(uint64_t, (p)->hq[2])<<16)| \ 87274116Sdteske (CAST(uint64_t, (p)->hq[1])<<8)| \ 88274116Sdteske (CAST(uint64_t, (p)->hq[0]))) 89274116Sdteske#define LE32(p) ( \ 90274116Sdteske (CAST(uint32_t, (p)->hl[3])<<24)| \ 91274116Sdteske (CAST(uint32_t, (p)->hl[2])<<16)| \ 92274116Sdteske (CAST(uint32_t, (p)->hl[1])<<8)| \ 93274116Sdteske (CAST(uint32_t, (p)->hl[0]))) 94274116Sdteske#define BE32(p) ( \ 95274116Sdteske (CAST(uint32_t, (p)->hl[0])<<24)| \ 96274116Sdteske (CAST(uint32_t, (p)->hl[1])<<16)| \ 97274116Sdteske (CAST(uint32_t, (p)->hl[2])<<8)| \ 98274116Sdteske (CAST(uint32_t, (p)->hl[3]))) 99274116Sdteske#define ME32(p) ( \ 100274116Sdteske (CAST(uint32_t, (p)->hl[1])<<24)| \ 101274116Sdteske (CAST(uint32_t, (p)->hl[0])<<16)| \ 102274116Sdteske (CAST(uint32_t, (p)->hl[3])<<8)| \ 103274116Sdteske (CAST(uint32_t, (p)->hl[2]))) 104274116Sdteske 105274116Sdteske#define BE16(p) ((CAST(uint16_t, (p)->hs[0])<<8)|(CAST(uint16_t, (p)->hs[1]))) 106274116Sdteske#define LE16(p) ((CAST(uint16_t, (p)->hs[1])<<8)|(CAST(uint16_t, (p)->hs[0]))) 107274116Sdteske#define SEXT(s,v,p) ((s) ? \ 108274116Sdteske CAST(intmax_t, CAST(int##v##_t, p)) : \ 109274116Sdteske CAST(intmax_t, CAST(uint##v##_t, p))) 110274116Sdteske 111274116Sdteske/* 112274116Sdteske * softmagic - lookup one file in parsed, in-memory copy of database 113274116Sdteske * Passed the name and FILE * of one file to be typed. 114274116Sdteske */ 115274116Sdteske/*ARGSUSED1*/ /* nbytes passed for regularity, maybe need later */ 116274116Sdteskeprotected int 117274116Sdteskefile_softmagic(struct magic_set *ms, const struct buffer *b, 118274116Sdteske uint16_t *indir_count, uint16_t *name_count, int mode, int text) 119274116Sdteske{ 120274116Sdteske struct mlist *ml; 121274116Sdteske int rv, printed_something = 0, need_separator = 0; 122274116Sdteske uint16_t nc, ic; 123274116Sdteske 124274116Sdteske if (name_count == NULL) { 125274116Sdteske nc = 0; 126274116Sdteske name_count = &nc; 127274116Sdteske } 128274116Sdteske if (indir_count == NULL) { 129274116Sdteske ic = 0; 130274116Sdteske indir_count = ⁣ 131274116Sdteske } 132274116Sdteske 133274116Sdteske for (ml = ms->mlist[0]->next; ml != ms->mlist[0]; ml = ml->next) 134274116Sdteske if ((rv = match(ms, ml->magic, ml->nmagic, b, 0, mode, 135274116Sdteske text, 0, indir_count, name_count, 136274116Sdteske &printed_something, &need_separator, NULL, NULL)) != 0) 137274116Sdteske return rv; 138274116Sdteske 139274116Sdteske return 0; 140274116Sdteske} 141274116Sdteske 142274116Sdteske#define FILE_FMTDEBUG 143274116Sdteske#ifdef FILE_FMTDEBUG 144274116Sdteske#define F(a, b, c) file_fmtcheck((a), (b), (c), __FILE__, __LINE__) 145274116Sdteske 146274116Sdteskeprivate const char * __attribute__((__format_arg__(3))) 147274116Sdteskefile_fmtcheck(struct magic_set *ms, const char *desc, const char *def, 148274116Sdteske const char *file, size_t line) 149274116Sdteske{ 150274116Sdteske const char *ptr; 151274116Sdteske 152274116Sdteske if (strchr(desc, '%') == NULL) 153274116Sdteske return desc; 154274116Sdteske 155274116Sdteske ptr = fmtcheck(desc, def); 156274116Sdteske if (ptr == def) 157274116Sdteske file_magerror(ms, 158274116Sdteske "%s, %" SIZE_T_FORMAT "u: format `%s' does not match" 159274116Sdteske " with `%s'", file, line, desc, def); 160274116Sdteske return ptr; 161274116Sdteske} 162274116Sdteske#else 163274116Sdteske#define F(a, b, c) fmtcheck((b), (c)) 164274116Sdteske#endif 165274116Sdteske 166274116Sdteske/* 167274116Sdteske * Go through the whole list, stopping if you find a match. Process all 168274116Sdteske * the continuations of that match before returning. 169274116Sdteske * 170274116Sdteske * We support multi-level continuations: 171274116Sdteske * 172274116Sdteske * At any time when processing a successful top-level match, there is a 173274116Sdteske * current continuation level; it represents the level of the last 174274116Sdteske * successfully matched continuation. 175274116Sdteske * 176274116Sdteske * Continuations above that level are skipped as, if we see one, it 177274116Sdteske * means that the continuation that controls them - i.e, the 178274116Sdteske * lower-level continuation preceding them - failed to match. 179274116Sdteske * 180274116Sdteske * Continuations below that level are processed as, if we see one, 181274116Sdteske * it means we've finished processing or skipping higher-level 182274116Sdteske * continuations under the control of a successful or unsuccessful 183274116Sdteske * lower-level continuation, and are now seeing the next lower-level 184274116Sdteske * continuation and should process it. The current continuation 185274116Sdteske * level reverts to the level of the one we're seeing. 186274116Sdteske * 187274116Sdteske * Continuations at the current level are processed as, if we see 188274116Sdteske * one, there's no lower-level continuation that may have failed. 189274116Sdteske * 190274116Sdteske * If a continuation matches, we bump the current continuation level 191274116Sdteske * so that higher-level continuations are processed. 192274116Sdteske */ 193274116Sdteskeprivate int 194274116Sdteskematch(struct magic_set *ms, struct magic *magic, uint32_t nmagic, 195274116Sdteske const struct buffer *b, size_t offset, int mode, int text, 196274116Sdteske int flip, uint16_t *indir_count, uint16_t *name_count, 197274116Sdteske int *printed_something, int *need_separator, int *returnval, 198274116Sdteske int *found_match) 199274116Sdteske{ 200274116Sdteske uint32_t magindex = 0; 201274116Sdteske unsigned int cont_level = 0; 202274116Sdteske int found_matchv = 0; /* if a match is found it is set to 1*/ 203274116Sdteske int returnvalv = 0, e; 204274116Sdteske int firstline = 1; /* a flag to print X\n X\n- X */ 205274116Sdteske struct buffer bb; 206274116Sdteske int print = (ms->flags & MAGIC_NODESC) == 0; 207274116Sdteske 208274116Sdteske /* 209274116Sdteske * returnval can be 0 if a match is found, but there was no 210274116Sdteske * annotation to be printed. 211274116Sdteske */ 212274116Sdteske if (returnval == NULL) 213274116Sdteske returnval = &returnvalv; 214274116Sdteske if (found_match == NULL) 215274116Sdteske found_match = &found_matchv; 216274116Sdteske 217274116Sdteske if (file_check_mem(ms, cont_level) == -1) 218274116Sdteske return -1; 219274116Sdteske 220274116Sdteske for (magindex = 0; magindex < nmagic; magindex++) { 221274116Sdteske int flush = 0; 222274116Sdteske struct magic *m = &magic[magindex]; 223274116Sdteske 224274116Sdteske if (m->type != FILE_NAME) 225274116Sdteske if ((IS_STRING(m->type) && 226274116Sdteske#define FLT (STRING_BINTEST | STRING_TEXTTEST) 227274116Sdteske ((text && (m->str_flags & FLT) == STRING_BINTEST) || 228274116Sdteske (!text && (m->str_flags & FLT) == STRING_TEXTTEST))) || 229274116Sdteske (m->flag & mode) != mode) { 230274116Sdteskeflush: 231274116Sdteske /* Skip sub-tests */ 232274116Sdteske while (magindex < nmagic - 1 && 233274116Sdteske magic[magindex + 1].cont_level != 0) 234274116Sdteske magindex++; 235274116Sdteske cont_level = 0; 236274116Sdteske continue; /* Skip to next top-level test*/ 237274116Sdteske } 238274116Sdteske 239274116Sdteske if (msetoffset(ms, m, &bb, b, offset, cont_level) == -1) 240274116Sdteske goto flush; 241274116Sdteske ms->line = m->lineno; 242274116Sdteske 243274116Sdteske /* if main entry matches, print it... */ 244274116Sdteske switch (mget(ms, m, b, CAST(const unsigned char *, bb.fbuf), 245274116Sdteske bb.flen, offset, cont_level, 246274116Sdteske mode, text, flip, indir_count, name_count, 247274116Sdteske printed_something, need_separator, returnval, found_match)) 248274116Sdteske { 249274116Sdteske case -1: 250274116Sdteske return -1; 251274116Sdteske case 0: 252274116Sdteske flush = m->reln != '!'; 253274116Sdteske break; 254274116Sdteske default: 255274116Sdteske if (m->type == FILE_INDIRECT) { 256274116Sdteske *found_match = 1; 257274116Sdteske *returnval = 1; 258274116Sdteske } 259274116Sdteske 260274116Sdteske switch (magiccheck(ms, m)) { 261274116Sdteske case -1: 262274116Sdteske return -1; 263274116Sdteske case 0: 264274116Sdteske flush++; 265274116Sdteske break; 266274116Sdteske default: 267274116Sdteske flush = 0; 268274116Sdteske break; 269274116Sdteske } 270274116Sdteske break; 271274116Sdteske } 272274116Sdteske if (flush) { 273274116Sdteske /* 274274116Sdteske * main entry didn't match, 275274116Sdteske * flush its continuations 276274116Sdteske */ 277274116Sdteske goto flush; 278274116Sdteske } 279274116Sdteske 280274116Sdteske if (*m->desc) 281274116Sdteske *found_match = 1; 282274116Sdteske 283274116Sdteske if ((e = handle_annotation(ms, m, firstline)) != 0) 284274116Sdteske { 285274116Sdteske *need_separator = 1; 286274116Sdteske *printed_something = 1; 287274116Sdteske *returnval = 1; 288274116Sdteske return e; 289274116Sdteske } 290274116Sdteske 291274116Sdteske /* 292274116Sdteske * If we are going to print something, we'll need to print 293274116Sdteske * a blank before we print something else. 294274116Sdteske */ 295274116Sdteske if (print && *m->desc) { 296274116Sdteske *need_separator = 1; 297274116Sdteske *printed_something = 1; 298274116Sdteske *returnval = 1; 299274116Sdteske if (print_sep(ms, firstline) == -1) 300274116Sdteske return -1; 301274116Sdteske if (mprint(ms, m) == -1) 302274116Sdteske return -1; 303274116Sdteske } 304274116Sdteske 305274116Sdteske switch (moffset(ms, m, &bb, &ms->c.li[cont_level].off)) { 306274116Sdteske case -1: 307274116Sdteske case 0: 308274116Sdteske goto flush; 309274116Sdteske default: 310274116Sdteske break; 311274116Sdteske } 312274116Sdteske 313274116Sdteske /* and any continuations that match */ 314274116Sdteske if (file_check_mem(ms, ++cont_level) == -1) 315274116Sdteske return -1; 316274116Sdteske 317274116Sdteske while (magindex + 1 < nmagic && 318274116Sdteske magic[magindex + 1].cont_level != 0) { 319274116Sdteske m = &magic[++magindex]; 320274116Sdteske ms->line = m->lineno; /* for messages */ 321274116Sdteske 322274116Sdteske if (cont_level < m->cont_level) 323274116Sdteske continue; 324274116Sdteske if (cont_level > m->cont_level) { 325274116Sdteske /* 326274116Sdteske * We're at the end of the level 327274116Sdteske * "cont_level" continuations. 328274116Sdteske */ 329274116Sdteske cont_level = m->cont_level; 330274116Sdteske } 331274116Sdteske if (msetoffset(ms, m, &bb, b, offset, cont_level) == -1) 332274116Sdteske goto flush; 333274116Sdteske if (m->flag & OFFADD) { 334274116Sdteske ms->offset += 335274116Sdteske ms->c.li[cont_level - 1].off; 336274116Sdteske } 337274116Sdteske 338274116Sdteske#ifdef ENABLE_CONDITIONALS 339274116Sdteske if (m->cond == COND_ELSE || 340274116Sdteske m->cond == COND_ELIF) { 341274116Sdteske if (ms->c.li[cont_level].last_match == 1) 342274116Sdteske continue; 343274116Sdteske } 344274116Sdteske#endif 345274116Sdteske switch (mget(ms, m, b, CAST(const unsigned char *, 346274116Sdteske bb.fbuf), bb.flen, offset, 347274116Sdteske cont_level, mode, text, flip, indir_count, 348274116Sdteske name_count, printed_something, need_separator, 349274116Sdteske returnval, found_match)) { 350274116Sdteske case -1: 351274116Sdteske return -1; 352274116Sdteske case 0: 353274116Sdteske if (m->reln != '!') 354274116Sdteske continue; 355274116Sdteske flush = 1; 356274116Sdteske break; 357274116Sdteske default: 358274116Sdteske if (m->type == FILE_INDIRECT) { 359274116Sdteske *found_match = 1; 360274116Sdteske *returnval = 1; 361274116Sdteske } 362274116Sdteske flush = 0; 363274116Sdteske break; 364274116Sdteske } 365274116Sdteske 366274116Sdteske switch (flush ? 1 : magiccheck(ms, m)) { 367274116Sdteske case -1: 368274116Sdteske return -1; 369274116Sdteske case 0: 370274116Sdteske#ifdef ENABLE_CONDITIONALS 371274116Sdteske ms->c.li[cont_level].last_match = 0; 372274116Sdteske#endif 373274116Sdteske break; 374274116Sdteske default: 375274116Sdteske#ifdef ENABLE_CONDITIONALS 376274116Sdteske ms->c.li[cont_level].last_match = 1; 377274116Sdteske#endif 378274116Sdteske if (m->type == FILE_CLEAR) 379274116Sdteske ms->c.li[cont_level].got_match = 0; 380274116Sdteske else if (ms->c.li[cont_level].got_match) { 381274116Sdteske if (m->type == FILE_DEFAULT) 382274116Sdteske break; 383274116Sdteske } else 384274116Sdteske ms->c.li[cont_level].got_match = 1; 385274116Sdteske 386274116Sdteske if (*m->desc) 387274116Sdteske *found_match = 1; 388274116Sdteske 389274116Sdteske if ((e = handle_annotation(ms, m, firstline)) 390274116Sdteske != 0) { 391274116Sdteske *need_separator = 1; 392274116Sdteske *printed_something = 1; 393274116Sdteske *returnval = 1; 394274116Sdteske return e; 395274116Sdteske } 396274116Sdteske if (print && *m->desc) { 397274116Sdteske /* 398274116Sdteske * This continuation matched. Print 399274116Sdteske * its message, with a blank before it 400274116Sdteske * if the previous item printed and 401274116Sdteske * this item isn't empty. 402274116Sdteske */ 403274116Sdteske /* 404274116Sdteske * If we are going to print something, 405274116Sdteske * make sure that we have a separator 406274116Sdteske * first. 407274116Sdteske */ 408274116Sdteske if (!*printed_something) { 409274116Sdteske *printed_something = 1; 410274116Sdteske if (print_sep(ms, firstline) 411274116Sdteske == -1) 412274116Sdteske return -1; 413274116Sdteske } 414274116Sdteske /* space if previous printed */ 415274116Sdteske if (*need_separator 416274116Sdteske && (m->flag & NOSPACE) == 0) { 417274116Sdteske if (file_printf(ms, " ") == -1) 418274116Sdteske return -1; 419274116Sdteske } 420274116Sdteske *returnval = 1; 421274116Sdteske *need_separator = 0; 422274116Sdteske if (mprint(ms, m) == -1) 423274116Sdteske return -1; 424274116Sdteske *need_separator = 1; 425274116Sdteske } 426274116Sdteske 427274116Sdteske switch (moffset(ms, m, &bb, 428274116Sdteske &ms->c.li[cont_level].off)) { 429274116Sdteske case -1: 430274116Sdteske case 0: 431274116Sdteske flush = 1; 432274116Sdteske cont_level--; 433274116Sdteske break; 434274116Sdteske default: 435274116Sdteske break; 436274116Sdteske } 437274116Sdteske 438274116Sdteske /* 439274116Sdteske * If we see any continuations 440274116Sdteske * at a higher level, 441274116Sdteske * process them. 442274116Sdteske */ 443274116Sdteske if (file_check_mem(ms, ++cont_level) == -1) 444274116Sdteske return -1; 445274116Sdteske break; 446274116Sdteske } 447274116Sdteske } 448274116Sdteske if (*printed_something) { 449274116Sdteske firstline = 0; 450274116Sdteske } 451274116Sdteske if (*found_match) { 452274116Sdteske if ((ms->flags & MAGIC_CONTINUE) == 0) 453274116Sdteske return *returnval; /* don't keep searching */ 454274116Sdteske // So that we print a separator 455274116Sdteske *printed_something = 0; 456274116Sdteske firstline = 0; 457274116Sdteske } 458274116Sdteske cont_level = 0; 459274116Sdteske } 460274116Sdteske return *returnval; /* This is hit if -k is set or there is no match */ 461274116Sdteske} 462274116Sdteske 463274116Sdteskeprivate int 464274116Sdteskecheck_fmt(struct magic_set *ms, const char *fmt) 465274116Sdteske{ 466274116Sdteske file_regex_t rx; 467274116Sdteske int rc, rv = -1; 468274116Sdteske 469274116Sdteske if (strchr(fmt, '%') == NULL) 470274116Sdteske return 0; 471274116Sdteske 472274116Sdteske rc = file_regcomp(&rx, "%[-0-9\\.]*s", REG_EXTENDED|REG_NOSUB); 473274116Sdteske if (rc) { 474274116Sdteske file_regerror(&rx, rc, ms); 475274116Sdteske } else { 476274116Sdteske rc = file_regexec(&rx, fmt, 0, 0, 0); 477274116Sdteske rv = !rc; 478274116Sdteske } 479274116Sdteske file_regfree(&rx); 480274116Sdteske return rv; 481274116Sdteske} 482274116Sdteske 483274116Sdteske#if !defined(HAVE_STRNDUP) || defined(__aiws__) 484274116Sdteske# ifdef __aiws__ 485274116Sdteske# define strndup aix_strndup /* aix is broken */ 486274116Sdteske# endif 487274116Sdteskechar *strndup(const char *, size_t); 488274116Sdteske 489274116Sdteskechar * 490274116Sdteskestrndup(const char *str, size_t n) 491274116Sdteske{ 492274116Sdteske size_t len; 493274116Sdteske char *copy; 494274116Sdteske 495274116Sdteske for (len = 0; len < n && str[len]; len++) 496274116Sdteske continue; 497274116Sdteske if ((copy = malloc(len + 1)) == NULL) 498274116Sdteske return NULL; 499274116Sdteske (void)memcpy(copy, str, len); 500274116Sdteske copy[len] = '\0'; 501274116Sdteske return copy; 502274116Sdteske} 503274116Sdteske#endif /* HAVE_STRNDUP */ 504274116Sdteske 505274116Sdteskestatic int 506274116Sdteskevarexpand(struct magic_set *ms, char *buf, size_t len, const char *str) 507274116Sdteske{ 508274116Sdteske const char *ptr, *sptr, *e, *t, *ee, *et; 509274116Sdteske size_t l; 510274116Sdteske 511274116Sdteske for (sptr = str; (ptr = strstr(sptr, "${")) != NULL;) { 512274116Sdteske l = CAST(size_t, ptr - sptr); 513274116Sdteske if (l >= len) 514274116Sdteske return -1; 515274116Sdteske memcpy(buf, sptr, l); 516274116Sdteske buf += l; 517274116Sdteske len -= l; 518274116Sdteske ptr += 2; 519274116Sdteske if (!*ptr || ptr[1] != '?') 520274116Sdteske return -1; 521274116Sdteske for (et = t = ptr + 2; *et && *et != ':'; et++) 522274116Sdteske continue; 523274116Sdteske if (*et != ':') 524274116Sdteske return -1; 525274116Sdteske for (ee = e = et + 1; *ee && *ee != '}'; ee++) 526274116Sdteske continue; 527274116Sdteske if (*ee != '}') 528274116Sdteske return -1; 529274116Sdteske switch (*ptr) { 530274116Sdteske case 'x': 531274116Sdteske if (ms->mode & 0111) { 532274116Sdteske ptr = t; 533274116Sdteske l = et - t; 534274116Sdteske } else { 535274116Sdteske ptr = e; 536274116Sdteske l = ee - e; 537274116Sdteske } 538274116Sdteske break; 539274116Sdteske default: 540274116Sdteske return -1; 541274116Sdteske } 542274116Sdteske if (l >= len) 543274116Sdteske return -1; 544274116Sdteske memcpy(buf, ptr, l); 545274116Sdteske buf += l; 546274116Sdteske len -= l; 547274116Sdteske sptr = ee + 1; 548274116Sdteske } 549274116Sdteske 550274116Sdteske l = strlen(sptr); 551274116Sdteske if (l >= len) 552274116Sdteske return -1; 553274116Sdteske 554274116Sdteske memcpy(buf, sptr, l); 555274116Sdteske buf[l] = '\0'; 556274116Sdteske return 0; 557274116Sdteske} 558274116Sdteske 559274116Sdteske 560274116Sdteskeprivate int32_t 561274116Sdteskemprint(struct magic_set *ms, struct magic *m) 562274116Sdteske{ 563274116Sdteske uint64_t v; 564274116Sdteske float vf; 565274116Sdteske double vd; 566274116Sdteske int64_t t = 0; 567274116Sdteske char buf[128], tbuf[26], sbuf[512], ebuf[512]; 568274116Sdteske const char *desc; 569274116Sdteske union VALUETYPE *p = &ms->ms_value; 570274116Sdteske 571274116Sdteske if (varexpand(ms, ebuf, sizeof(ebuf), m->desc) == -1) 572274116Sdteske desc = m->desc; 573274116Sdteske else 574274116Sdteske desc = ebuf; 575274116Sdteske 576274116Sdteske switch (m->type) { 577274116Sdteske case FILE_BYTE: 578274116Sdteske v = file_signextend(ms, m, CAST(uint64_t, p->b)); 579274116Sdteske switch (check_fmt(ms, desc)) { 580274116Sdteske case -1: 581274116Sdteske return -1; 582274116Sdteske case 1: 583274116Sdteske (void)snprintf(buf, sizeof(buf), "%d", 584274116Sdteske CAST(unsigned char, v)); 585274116Sdteske if (file_printf(ms, F(ms, desc, "%s"), buf) == -1) 586274116Sdteske return -1; 587274116Sdteske break; 588274116Sdteske default: 589274116Sdteske if (file_printf(ms, F(ms, desc, "%d"), 590274116Sdteske CAST(unsigned char, v)) == -1) 591274116Sdteske return -1; 592274116Sdteske break; 593274116Sdteske } 594274116Sdteske t = ms->offset + sizeof(char); 595274116Sdteske break; 596274116Sdteske 597274116Sdteske case FILE_SHORT: 598274116Sdteske case FILE_BESHORT: 599274116Sdteske case FILE_LESHORT: 600274116Sdteske v = file_signextend(ms, m, CAST(uint64_t, p->h)); 601274116Sdteske switch (check_fmt(ms, desc)) { 602274116Sdteske case -1: 603274116Sdteske return -1; 604274116Sdteske case 1: 605274116Sdteske (void)snprintf(buf, sizeof(buf), "%u", 606274116Sdteske CAST(unsigned short, v)); 607274116Sdteske if (file_printf(ms, F(ms, desc, "%s"), buf) == -1) 608274116Sdteske return -1; 609274116Sdteske break; 610274116Sdteske default: 611274116Sdteske if (file_printf(ms, F(ms, desc, "%u"), 612274116Sdteske CAST(unsigned short, v)) == -1) 613274116Sdteske return -1; 614274116Sdteske break; 615274116Sdteske } 616274116Sdteske t = ms->offset + sizeof(short); 617274116Sdteske break; 618274116Sdteske 619274116Sdteske case FILE_LONG: 620274116Sdteske case FILE_BELONG: 621274116Sdteske case FILE_LELONG: 622274116Sdteske case FILE_MELONG: 623274116Sdteske v = file_signextend(ms, m, CAST(uint64_t, p->l)); 624274116Sdteske switch (check_fmt(ms, desc)) { 625274116Sdteske case -1: 626274116Sdteske return -1; 627274116Sdteske case 1: 628274116Sdteske (void)snprintf(buf, sizeof(buf), "%u", 629274116Sdteske CAST(uint32_t, v)); 630274116Sdteske if (file_printf(ms, F(ms, desc, "%s"), buf) == -1) 631274116Sdteske return -1; 632274116Sdteske break; 633274116Sdteske default: 634274116Sdteske if (file_printf(ms, F(ms, desc, "%u"), 635274116Sdteske CAST(uint32_t, v)) == -1) 636274116Sdteske return -1; 637274116Sdteske break; 638274116Sdteske } 639274116Sdteske t = ms->offset + sizeof(int32_t); 640274116Sdteske break; 641274116Sdteske 642274116Sdteske case FILE_QUAD: 643274116Sdteske case FILE_BEQUAD: 644274116Sdteske case FILE_LEQUAD: 645274116Sdteske v = file_signextend(ms, m, p->q); 646274116Sdteske switch (check_fmt(ms, desc)) { 647274116Sdteske case -1: 648274116Sdteske return -1; 649274116Sdteske case 1: 650274116Sdteske (void)snprintf(buf, sizeof(buf), "%" INT64_T_FORMAT "u", 651274116Sdteske CAST(unsigned long long, v)); 652274116Sdteske if (file_printf(ms, F(ms, desc, "%s"), buf) == -1) 653274116Sdteske return -1; 654274116Sdteske break; 655274116Sdteske default: 656274116Sdteske if (file_printf(ms, F(ms, desc, "%" INT64_T_FORMAT "u"), 657274116Sdteske CAST(unsigned long long, v)) == -1) 658274116Sdteske return -1; 659274116Sdteske break; 660274116Sdteske } 661274116Sdteske t = ms->offset + sizeof(int64_t); 662274116Sdteske break; 663274116Sdteske 664274116Sdteske case FILE_STRING: 665274116Sdteske case FILE_PSTRING: 666274116Sdteske case FILE_BESTRING16: 667274116Sdteske case FILE_LESTRING16: 668274116Sdteske if (m->reln == '=' || m->reln == '!') { 669274116Sdteske if (file_printf(ms, F(ms, desc, "%s"), 670274116Sdteske file_printable(sbuf, sizeof(sbuf), m->value.s, 671274116Sdteske sizeof(m->value.s))) == -1) 672274116Sdteske return -1; 673274116Sdteske t = ms->offset + m->vallen; 674274116Sdteske } 675274116Sdteske else { 676274116Sdteske char *str = p->s; 677274116Sdteske 678274116Sdteske /* compute t before we mangle the string? */ 679274116Sdteske t = ms->offset + strlen(str); 680274116Sdteske 681274116Sdteske if (*m->value.s == '\0') 682274116Sdteske str[strcspn(str, "\r\n")] = '\0'; 683274116Sdteske 684274116Sdteske if (m->str_flags & STRING_TRIM) { 685274116Sdteske char *last; 686274116Sdteske while (isspace(CAST(unsigned char, *str))) 687274116Sdteske str++; 688274116Sdteske last = str; 689274116Sdteske while (*last) 690274116Sdteske last++; 691274116Sdteske --last; 692274116Sdteske while (isspace(CAST(unsigned char, *last))) 693274116Sdteske last--; 694274116Sdteske *++last = '\0'; 695274116Sdteske } 696274116Sdteske 697274116Sdteske if (file_printf(ms, F(ms, desc, "%s"), 698274116Sdteske file_printable(sbuf, sizeof(sbuf), str, 699274116Sdteske sizeof(p->s) - (str - p->s))) == -1) 700274116Sdteske return -1; 701274116Sdteske 702274116Sdteske if (m->type == FILE_PSTRING) 703274116Sdteske t += file_pstring_length_size(m); 704274116Sdteske } 705274116Sdteske break; 706274116Sdteske 707274116Sdteske case FILE_DATE: 708274116Sdteske case FILE_BEDATE: 709274116Sdteske case FILE_LEDATE: 710274116Sdteske case FILE_MEDATE: 711274116Sdteske if (file_printf(ms, F(ms, desc, "%s"), 712274116Sdteske file_fmttime(p->l, 0, tbuf)) == -1) 713274116Sdteske return -1; 714274116Sdteske t = ms->offset + sizeof(uint32_t); 715274116Sdteske break; 716274116Sdteske 717274116Sdteske case FILE_LDATE: 718274116Sdteske case FILE_BELDATE: 719274116Sdteske case FILE_LELDATE: 720274116Sdteske case FILE_MELDATE: 721274116Sdteske if (file_printf(ms, F(ms, desc, "%s"), 722 file_fmttime(p->l, FILE_T_LOCAL, tbuf)) == -1) 723 return -1; 724 t = ms->offset + sizeof(uint32_t); 725 break; 726 727 case FILE_QDATE: 728 case FILE_BEQDATE: 729 case FILE_LEQDATE: 730 if (file_printf(ms, F(ms, desc, "%s"), 731 file_fmttime(p->q, 0, tbuf)) == -1) 732 return -1; 733 t = ms->offset + sizeof(uint64_t); 734 break; 735 736 case FILE_QLDATE: 737 case FILE_BEQLDATE: 738 case FILE_LEQLDATE: 739 if (file_printf(ms, F(ms, desc, "%s"), 740 file_fmttime(p->q, FILE_T_LOCAL, tbuf)) == -1) 741 return -1; 742 t = ms->offset + sizeof(uint64_t); 743 break; 744 745 case FILE_QWDATE: 746 case FILE_BEQWDATE: 747 case FILE_LEQWDATE: 748 if (file_printf(ms, F(ms, desc, "%s"), 749 file_fmttime(p->q, FILE_T_WINDOWS, tbuf)) == -1) 750 return -1; 751 t = ms->offset + sizeof(uint64_t); 752 break; 753 754 case FILE_FLOAT: 755 case FILE_BEFLOAT: 756 case FILE_LEFLOAT: 757 vf = p->f; 758 switch (check_fmt(ms, desc)) { 759 case -1: 760 return -1; 761 case 1: 762 (void)snprintf(buf, sizeof(buf), "%g", vf); 763 if (file_printf(ms, F(ms, desc, "%s"), buf) == -1) 764 return -1; 765 break; 766 default: 767 if (file_printf(ms, F(ms, desc, "%g"), vf) == -1) 768 return -1; 769 break; 770 } 771 t = ms->offset + sizeof(float); 772 break; 773 774 case FILE_DOUBLE: 775 case FILE_BEDOUBLE: 776 case FILE_LEDOUBLE: 777 vd = p->d; 778 switch (check_fmt(ms, desc)) { 779 case -1: 780 return -1; 781 case 1: 782 (void)snprintf(buf, sizeof(buf), "%g", vd); 783 if (file_printf(ms, F(ms, desc, "%s"), buf) == -1) 784 return -1; 785 break; 786 default: 787 if (file_printf(ms, F(ms, desc, "%g"), vd) == -1) 788 return -1; 789 break; 790 } 791 t = ms->offset + sizeof(double); 792 break; 793 794 case FILE_SEARCH: 795 case FILE_REGEX: { 796 char *cp; 797 int rval; 798 799 cp = strndup(RCAST(const char *, ms->search.s), 800 ms->search.rm_len); 801 if (cp == NULL) { 802 file_oomem(ms, ms->search.rm_len); 803 return -1; 804 } 805 rval = file_printf(ms, F(ms, desc, "%s"), 806 file_printable(sbuf, sizeof(sbuf), cp, ms->search.rm_len)); 807 free(cp); 808 809 if (rval == -1) 810 return -1; 811 812 if ((m->str_flags & REGEX_OFFSET_START)) 813 t = ms->search.offset; 814 else 815 t = ms->search.offset + ms->search.rm_len; 816 break; 817 } 818 819 case FILE_DEFAULT: 820 case FILE_CLEAR: 821 if (file_printf(ms, "%s", m->desc) == -1) 822 return -1; 823 t = ms->offset; 824 break; 825 826 case FILE_INDIRECT: 827 case FILE_USE: 828 case FILE_NAME: 829 t = ms->offset; 830 break; 831 case FILE_DER: 832 if (file_printf(ms, F(ms, desc, "%s"), 833 file_printable(sbuf, sizeof(sbuf), ms->ms_value.s, 834 sizeof(ms->ms_value.s))) == -1) 835 return -1; 836 t = ms->offset; 837 break; 838 default: 839 file_magerror(ms, "invalid m->type (%d) in mprint()", m->type); 840 return -1; 841 } 842 return CAST(int32_t, t); 843} 844 845private int 846moffset(struct magic_set *ms, struct magic *m, const struct buffer *b, 847 int32_t *op) 848{ 849 size_t nbytes = b->flen; 850 int32_t o; 851 852 switch (m->type) { 853 case FILE_BYTE: 854 o = CAST(int32_t, (ms->offset + sizeof(char))); 855 break; 856 857 case FILE_SHORT: 858 case FILE_BESHORT: 859 case FILE_LESHORT: 860 o = CAST(int32_t, (ms->offset + sizeof(short))); 861 break; 862 863 case FILE_LONG: 864 case FILE_BELONG: 865 case FILE_LELONG: 866 case FILE_MELONG: 867 o = CAST(int32_t, (ms->offset + sizeof(int32_t))); 868 break; 869 870 case FILE_QUAD: 871 case FILE_BEQUAD: 872 case FILE_LEQUAD: 873 o = CAST(int32_t, (ms->offset + sizeof(int64_t))); 874 break; 875 876 case FILE_STRING: 877 case FILE_PSTRING: 878 case FILE_BESTRING16: 879 case FILE_LESTRING16: 880 if (m->reln == '=' || m->reln == '!') { 881 o = ms->offset + m->vallen; 882 } else { 883 union VALUETYPE *p = &ms->ms_value; 884 885 if (*m->value.s == '\0') 886 p->s[strcspn(p->s, "\r\n")] = '\0'; 887 o = CAST(uint32_t, (ms->offset + strlen(p->s))); 888 if (m->type == FILE_PSTRING) 889 o += CAST(uint32_t, 890 file_pstring_length_size(m)); 891 } 892 break; 893 894 case FILE_DATE: 895 case FILE_BEDATE: 896 case FILE_LEDATE: 897 case FILE_MEDATE: 898 o = CAST(int32_t, (ms->offset + sizeof(uint32_t))); 899 break; 900 901 case FILE_LDATE: 902 case FILE_BELDATE: 903 case FILE_LELDATE: 904 case FILE_MELDATE: 905 o = CAST(int32_t, (ms->offset + sizeof(uint32_t))); 906 break; 907 908 case FILE_QDATE: 909 case FILE_BEQDATE: 910 case FILE_LEQDATE: 911 o = CAST(int32_t, (ms->offset + sizeof(uint64_t))); 912 break; 913 914 case FILE_QLDATE: 915 case FILE_BEQLDATE: 916 case FILE_LEQLDATE: 917 o = CAST(int32_t, (ms->offset + sizeof(uint64_t))); 918 break; 919 920 case FILE_FLOAT: 921 case FILE_BEFLOAT: 922 case FILE_LEFLOAT: 923 o = CAST(int32_t, (ms->offset + sizeof(float))); 924 break; 925 926 case FILE_DOUBLE: 927 case FILE_BEDOUBLE: 928 case FILE_LEDOUBLE: 929 o = CAST(int32_t, (ms->offset + sizeof(double))); 930 break; 931 932 case FILE_REGEX: 933 if ((m->str_flags & REGEX_OFFSET_START) != 0) 934 o = CAST(int32_t, ms->search.offset); 935 else 936 o = CAST(int32_t, 937 (ms->search.offset + ms->search.rm_len)); 938 break; 939 940 case FILE_SEARCH: 941 if ((m->str_flags & REGEX_OFFSET_START) != 0) 942 o = CAST(int32_t, ms->search.offset); 943 else 944 o = CAST(int32_t, (ms->search.offset + m->vallen)); 945 break; 946 947 case FILE_CLEAR: 948 case FILE_DEFAULT: 949 case FILE_INDIRECT: 950 o = ms->offset; 951 break; 952 953 case FILE_DER: 954 { 955 o = der_offs(ms, m, nbytes); 956 if (o == -1 || CAST(size_t, o) > nbytes) { 957 if ((ms->flags & MAGIC_DEBUG) != 0) { 958 (void)fprintf(stderr, 959 "Bad DER offset %d nbytes=%" 960 SIZE_T_FORMAT "u", o, nbytes); 961 } 962 *op = 0; 963 return 0; 964 } 965 break; 966 } 967 968 default: 969 o = 0; 970 break; 971 } 972 973 if (CAST(size_t, o) > nbytes) { 974#if 0 975 file_error(ms, 0, "Offset out of range %" SIZE_T_FORMAT 976 "u > %" SIZE_T_FORMAT "u", (size_t)o, nbytes); 977#endif 978 return -1; 979 } 980 *op = o; 981 return 1; 982} 983 984private uint32_t 985cvt_id3(struct magic_set *ms, uint32_t v) 986{ 987 v = ((((v >> 0) & 0x7f) << 0) | 988 (((v >> 8) & 0x7f) << 7) | 989 (((v >> 16) & 0x7f) << 14) | 990 (((v >> 24) & 0x7f) << 21)); 991 if ((ms->flags & MAGIC_DEBUG) != 0) 992 fprintf(stderr, "id3 offs=%u\n", v); 993 return v; 994} 995 996private int 997cvt_flip(int type, int flip) 998{ 999 if (flip == 0) 1000 return type; 1001 switch (type) { 1002 case FILE_BESHORT: 1003 return FILE_LESHORT; 1004 case FILE_BELONG: 1005 return FILE_LELONG; 1006 case FILE_BEDATE: 1007 return FILE_LEDATE; 1008 case FILE_BELDATE: 1009 return FILE_LELDATE; 1010 case FILE_BEQUAD: 1011 return FILE_LEQUAD; 1012 case FILE_BEQDATE: 1013 return FILE_LEQDATE; 1014 case FILE_BEQLDATE: 1015 return FILE_LEQLDATE; 1016 case FILE_BEQWDATE: 1017 return FILE_LEQWDATE; 1018 case FILE_LESHORT: 1019 return FILE_BESHORT; 1020 case FILE_LELONG: 1021 return FILE_BELONG; 1022 case FILE_LEDATE: 1023 return FILE_BEDATE; 1024 case FILE_LELDATE: 1025 return FILE_BELDATE; 1026 case FILE_LEQUAD: 1027 return FILE_BEQUAD; 1028 case FILE_LEQDATE: 1029 return FILE_BEQDATE; 1030 case FILE_LEQLDATE: 1031 return FILE_BEQLDATE; 1032 case FILE_LEQWDATE: 1033 return FILE_BEQWDATE; 1034 case FILE_BEFLOAT: 1035 return FILE_LEFLOAT; 1036 case FILE_LEFLOAT: 1037 return FILE_BEFLOAT; 1038 case FILE_BEDOUBLE: 1039 return FILE_LEDOUBLE; 1040 case FILE_LEDOUBLE: 1041 return FILE_BEDOUBLE; 1042 default: 1043 return type; 1044 } 1045} 1046#define DO_CVT(fld, type) \ 1047 if (m->num_mask) \ 1048 switch (m->mask_op & FILE_OPS_MASK) { \ 1049 case FILE_OPAND: \ 1050 p->fld &= CAST(type, m->num_mask); \ 1051 break; \ 1052 case FILE_OPOR: \ 1053 p->fld |= CAST(type, m->num_mask); \ 1054 break; \ 1055 case FILE_OPXOR: \ 1056 p->fld ^= CAST(type, m->num_mask); \ 1057 break; \ 1058 case FILE_OPADD: \ 1059 p->fld += CAST(type, m->num_mask); \ 1060 break; \ 1061 case FILE_OPMINUS: \ 1062 p->fld -= CAST(type, m->num_mask); \ 1063 break; \ 1064 case FILE_OPMULTIPLY: \ 1065 p->fld *= CAST(type, m->num_mask); \ 1066 break; \ 1067 case FILE_OPDIVIDE: \ 1068 if (CAST(type, m->num_mask) == 0) \ 1069 return -1; \ 1070 p->fld /= CAST(type, m->num_mask); \ 1071 break; \ 1072 case FILE_OPMODULO: \ 1073 if (CAST(type, m->num_mask) == 0) \ 1074 return -1; \ 1075 p->fld %= CAST(type, m->num_mask); \ 1076 break; \ 1077 } \ 1078 if (m->mask_op & FILE_OPINVERSE) \ 1079 p->fld = ~p->fld \ 1080 1081private int 1082cvt_8(union VALUETYPE *p, const struct magic *m) 1083{ 1084 DO_CVT(b, uint8_t); 1085 return 0; 1086} 1087 1088private int 1089cvt_16(union VALUETYPE *p, const struct magic *m) 1090{ 1091 DO_CVT(h, uint16_t); 1092 return 0; 1093} 1094 1095private int 1096cvt_32(union VALUETYPE *p, const struct magic *m) 1097{ 1098 DO_CVT(l, uint32_t); 1099 return 0; 1100} 1101 1102private int 1103cvt_64(union VALUETYPE *p, const struct magic *m) 1104{ 1105 DO_CVT(q, uint64_t); 1106 return 0; 1107} 1108 1109#define DO_CVT2(fld, type) \ 1110 if (m->num_mask) \ 1111 switch (m->mask_op & FILE_OPS_MASK) { \ 1112 case FILE_OPADD: \ 1113 p->fld += CAST(type, m->num_mask); \ 1114 break; \ 1115 case FILE_OPMINUS: \ 1116 p->fld -= CAST(type, m->num_mask); \ 1117 break; \ 1118 case FILE_OPMULTIPLY: \ 1119 p->fld *= CAST(type, m->num_mask); \ 1120 break; \ 1121 case FILE_OPDIVIDE: \ 1122 if (CAST(type, m->num_mask) == 0) \ 1123 return -1; \ 1124 p->fld /= CAST(type, m->num_mask); \ 1125 break; \ 1126 } \ 1127 1128private int 1129cvt_float(union VALUETYPE *p, const struct magic *m) 1130{ 1131 DO_CVT2(f, float); 1132 return 0; 1133} 1134 1135private int 1136cvt_double(union VALUETYPE *p, const struct magic *m) 1137{ 1138 DO_CVT2(d, double); 1139 return 0; 1140} 1141 1142/* 1143 * Convert the byte order of the data we are looking at 1144 * While we're here, let's apply the mask operation 1145 * (unless you have a better idea) 1146 */ 1147private int 1148mconvert(struct magic_set *ms, struct magic *m, int flip) 1149{ 1150 union VALUETYPE *p = &ms->ms_value; 1151 1152 switch (cvt_flip(m->type, flip)) { 1153 case FILE_BYTE: 1154 if (cvt_8(p, m) == -1) 1155 goto out; 1156 return 1; 1157 case FILE_SHORT: 1158 if (cvt_16(p, m) == -1) 1159 goto out; 1160 return 1; 1161 case FILE_LONG: 1162 case FILE_DATE: 1163 case FILE_LDATE: 1164 if (cvt_32(p, m) == -1) 1165 goto out; 1166 return 1; 1167 case FILE_QUAD: 1168 case FILE_QDATE: 1169 case FILE_QLDATE: 1170 case FILE_QWDATE: 1171 if (cvt_64(p, m) == -1) 1172 goto out; 1173 return 1; 1174 case FILE_STRING: 1175 case FILE_BESTRING16: 1176 case FILE_LESTRING16: { 1177 /* Null terminate and eat *trailing* return */ 1178 p->s[sizeof(p->s) - 1] = '\0'; 1179 return 1; 1180 } 1181 case FILE_PSTRING: { 1182 size_t sz = file_pstring_length_size(m); 1183 char *ptr1 = p->s, *ptr2 = ptr1 + sz; 1184 size_t len = file_pstring_get_length(m, ptr1); 1185 sz = sizeof(p->s) - sz; /* maximum length of string */ 1186 if (len >= sz) { 1187 /* 1188 * The size of the pascal string length (sz) 1189 * is 1, 2, or 4. We need at least 1 byte for NUL 1190 * termination, but we've already truncated the 1191 * string by p->s, so we need to deduct sz. 1192 * Because we can use one of the bytes of the length 1193 * after we shifted as NUL termination. 1194 */ 1195 len = sz; 1196 } 1197 while (len--) 1198 *ptr1++ = *ptr2++; 1199 *ptr1 = '\0'; 1200 return 1; 1201 } 1202 case FILE_BESHORT: 1203 p->h = CAST(short, BE16(p)); 1204 if (cvt_16(p, m) == -1) 1205 goto out; 1206 return 1; 1207 case FILE_BELONG: 1208 case FILE_BEDATE: 1209 case FILE_BELDATE: 1210 p->l = CAST(int32_t, BE32(p)); 1211 if (cvt_32(p, m) == -1) 1212 goto out; 1213 return 1; 1214 case FILE_BEQUAD: 1215 case FILE_BEQDATE: 1216 case FILE_BEQLDATE: 1217 case FILE_BEQWDATE: 1218 p->q = CAST(uint64_t, BE64(p)); 1219 if (cvt_64(p, m) == -1) 1220 goto out; 1221 return 1; 1222 case FILE_LESHORT: 1223 p->h = CAST(short, LE16(p)); 1224 if (cvt_16(p, m) == -1) 1225 goto out; 1226 return 1; 1227 case FILE_LELONG: 1228 case FILE_LEDATE: 1229 case FILE_LELDATE: 1230 p->l = CAST(int32_t, LE32(p)); 1231 if (cvt_32(p, m) == -1) 1232 goto out; 1233 return 1; 1234 case FILE_LEQUAD: 1235 case FILE_LEQDATE: 1236 case FILE_LEQLDATE: 1237 case FILE_LEQWDATE: 1238 p->q = CAST(uint64_t, LE64(p)); 1239 if (cvt_64(p, m) == -1) 1240 goto out; 1241 return 1; 1242 case FILE_MELONG: 1243 case FILE_MEDATE: 1244 case FILE_MELDATE: 1245 p->l = CAST(int32_t, ME32(p)); 1246 if (cvt_32(p, m) == -1) 1247 goto out; 1248 return 1; 1249 case FILE_FLOAT: 1250 if (cvt_float(p, m) == -1) 1251 goto out; 1252 return 1; 1253 case FILE_BEFLOAT: 1254 p->l = BE32(p); 1255 if (cvt_float(p, m) == -1) 1256 goto out; 1257 return 1; 1258 case FILE_LEFLOAT: 1259 p->l = LE32(p); 1260 if (cvt_float(p, m) == -1) 1261 goto out; 1262 return 1; 1263 case FILE_DOUBLE: 1264 if (cvt_double(p, m) == -1) 1265 goto out; 1266 return 1; 1267 case FILE_BEDOUBLE: 1268 p->q = BE64(p); 1269 if (cvt_double(p, m) == -1) 1270 goto out; 1271 return 1; 1272 case FILE_LEDOUBLE: 1273 p->q = LE64(p); 1274 if (cvt_double(p, m) == -1) 1275 goto out; 1276 return 1; 1277 case FILE_REGEX: 1278 case FILE_SEARCH: 1279 case FILE_DEFAULT: 1280 case FILE_CLEAR: 1281 case FILE_NAME: 1282 case FILE_USE: 1283 case FILE_DER: 1284 return 1; 1285 default: 1286 file_magerror(ms, "invalid type %d in mconvert()", m->type); 1287 return 0; 1288 } 1289out: 1290 file_magerror(ms, "zerodivide in mconvert()"); 1291 return 0; 1292} 1293 1294 1295private void 1296mdebug(uint32_t offset, const char *str, size_t len) 1297{ 1298 (void) fprintf(stderr, "mget/%" SIZE_T_FORMAT "u @%d: ", len, offset); 1299 file_showstr(stderr, str, len); 1300 (void) fputc('\n', stderr); 1301 (void) fputc('\n', stderr); 1302} 1303 1304private int 1305mcopy(struct magic_set *ms, union VALUETYPE *p, int type, int indir, 1306 const unsigned char *s, uint32_t offset, size_t nbytes, struct magic *m) 1307{ 1308 /* 1309 * Note: FILE_SEARCH and FILE_REGEX do not actually copy 1310 * anything, but setup pointers into the source 1311 */ 1312 if (indir == 0) { 1313 switch (type) { 1314 case FILE_DER: 1315 case FILE_SEARCH: 1316 if (offset > nbytes) 1317 offset = CAST(uint32_t, nbytes); 1318 ms->search.s = RCAST(const char *, s) + offset; 1319 ms->search.s_len = nbytes - offset; 1320 ms->search.offset = offset; 1321 return 0; 1322 1323 case FILE_REGEX: { 1324 const char *b; 1325 const char *c; 1326 const char *last; /* end of search region */ 1327 const char *buf; /* start of search region */ 1328 const char *end; 1329 size_t lines, linecnt, bytecnt; 1330 1331 if (s == NULL || nbytes < offset) { 1332 ms->search.s_len = 0; 1333 ms->search.s = NULL; 1334 return 0; 1335 } 1336 1337 if (m->str_flags & REGEX_LINE_COUNT) { 1338 linecnt = m->str_range; 1339 bytecnt = linecnt * 80; 1340 } else { 1341 linecnt = 0; 1342 bytecnt = m->str_range; 1343 } 1344 1345 if (bytecnt == 0 || bytecnt > nbytes - offset) 1346 bytecnt = nbytes - offset; 1347 if (bytecnt > ms->regex_max) 1348 bytecnt = ms->regex_max; 1349 1350 buf = RCAST(const char *, s) + offset; 1351 end = last = RCAST(const char *, s) + bytecnt + offset; 1352 /* mget() guarantees buf <= last */ 1353 for (lines = linecnt, b = buf; lines && b < end && 1354 ((b = CAST(const char *, 1355 memchr(c = b, '\n', CAST(size_t, (end - b))))) 1356 || (b = CAST(const char *, 1357 memchr(c, '\r', CAST(size_t, (end - c)))))); 1358 lines--, b++) { 1359 if (b < end - 1 && b[0] == '\r' && b[1] == '\n') 1360 b++; 1361 if (b < end - 1 && b[0] == '\n') 1362 b++; 1363 last = b; 1364 } 1365 if (lines) 1366 last = end; 1367 1368 ms->search.s = buf; 1369 ms->search.s_len = last - buf; 1370 ms->search.offset = offset; 1371 ms->search.rm_len = 0; 1372 return 0; 1373 } 1374 case FILE_BESTRING16: 1375 case FILE_LESTRING16: { 1376 const unsigned char *src = s + offset; 1377 const unsigned char *esrc = s + nbytes; 1378 char *dst = p->s; 1379 char *edst = &p->s[sizeof(p->s) - 1]; 1380 1381 if (type == FILE_BESTRING16) 1382 src++; 1383 1384 /* check that offset is within range */ 1385 if (offset >= nbytes) 1386 break; 1387 for (/*EMPTY*/; src < esrc; src += 2, dst++) { 1388 if (dst < edst) 1389 *dst = *src; 1390 else 1391 break; 1392 if (*dst == '\0') { 1393 if (type == FILE_BESTRING16 ? 1394 *(src - 1) != '\0' : 1395 ((src + 1 < esrc) && 1396 *(src + 1) != '\0')) 1397 *dst = ' '; 1398 } 1399 } 1400 *edst = '\0'; 1401 return 0; 1402 } 1403 case FILE_STRING: /* XXX - these two should not need */ 1404 case FILE_PSTRING: /* to copy anything, but do anyway. */ 1405 default: 1406 break; 1407 } 1408 } 1409 1410 if (offset >= nbytes) { 1411 (void)memset(p, '\0', sizeof(*p)); 1412 return 0; 1413 } 1414 if (nbytes - offset < sizeof(*p)) 1415 nbytes = nbytes - offset; 1416 else 1417 nbytes = sizeof(*p); 1418 1419 (void)memcpy(p, s + offset, nbytes); 1420 1421 /* 1422 * the usefulness of padding with zeroes eludes me, it 1423 * might even cause problems 1424 */ 1425 if (nbytes < sizeof(*p)) 1426 (void)memset(RCAST(char *, RCAST(void *, p)) + nbytes, '\0', 1427 sizeof(*p) - nbytes); 1428 return 0; 1429} 1430 1431private uint32_t 1432do_ops(struct magic *m, intmax_t lhs, intmax_t off) 1433{ 1434 intmax_t offset; 1435 if (off) { 1436 switch (m->in_op & FILE_OPS_MASK) { 1437 case FILE_OPAND: 1438 offset = lhs & off; 1439 break; 1440 case FILE_OPOR: 1441 offset = lhs | off; 1442 break; 1443 case FILE_OPXOR: 1444 offset = lhs ^ off; 1445 break; 1446 case FILE_OPADD: 1447 offset = lhs + off; 1448 break; 1449 case FILE_OPMINUS: 1450 offset = lhs - off; 1451 break; 1452 case FILE_OPMULTIPLY: 1453 offset = lhs * off; 1454 break; 1455 case FILE_OPDIVIDE: 1456 offset = lhs / off; 1457 break; 1458 case FILE_OPMODULO: 1459 offset = lhs % off; 1460 break; 1461 } 1462 } else 1463 offset = lhs; 1464 if (m->in_op & FILE_OPINVERSE) 1465 offset = ~offset; 1466 1467 return CAST(uint32_t, offset); 1468} 1469 1470private int 1471msetoffset(struct magic_set *ms, struct magic *m, struct buffer *bb, 1472 const struct buffer *b, size_t o, unsigned int cont_level) 1473{ 1474 if (m->offset < 0) { 1475 if (cont_level > 0) { 1476 if (m->flag & (OFFADD|INDIROFFADD)) 1477 goto normal; 1478#if 0 1479 file_error(ms, 0, "negative offset %d at continuation" 1480 "level %u", m->offset, cont_level); 1481 return -1; 1482#endif 1483 } 1484 if (buffer_fill(b) == -1) 1485 return -1; 1486 if (o != 0) { 1487 // Not yet! 1488 file_magerror(ms, "non zero offset %" SIZE_T_FORMAT 1489 "u at level %u", o, cont_level); 1490 return -1; 1491 } 1492 if (CAST(size_t, -m->offset) > b->elen) 1493 return -1; 1494 buffer_init(bb, -1, NULL, b->ebuf, b->elen); 1495 ms->eoffset = ms->offset = CAST(int32_t, b->elen + m->offset); 1496 } else { 1497 if (cont_level == 0) { 1498normal: 1499 // XXX: Pass real fd, then who frees bb? 1500 buffer_init(bb, -1, NULL, b->fbuf, b->flen); 1501 ms->offset = m->offset; 1502 ms->eoffset = 0; 1503 } else { 1504 ms->offset = ms->eoffset + m->offset; 1505 } 1506 } 1507 if ((ms->flags & MAGIC_DEBUG) != 0) { 1508 fprintf(stderr, "bb=[%p,%" SIZE_T_FORMAT "u], %d [b=%p,%" 1509 SIZE_T_FORMAT "u], [o=%#x, c=%d]\n", 1510 bb->fbuf, bb->flen, ms->offset, b->fbuf, b->flen, 1511 m->offset, cont_level); 1512 } 1513 return 0; 1514} 1515 1516private int 1517mget(struct magic_set *ms, struct magic *m, const struct buffer *b, 1518 const unsigned char *s, size_t nbytes, size_t o, unsigned int cont_level, 1519 int mode, int text, int flip, uint16_t *indir_count, uint16_t *name_count, 1520 int *printed_something, int *need_separator, int *returnval, 1521 int *found_match) 1522{ 1523 uint32_t offset = ms->offset; 1524 struct buffer bb; 1525 intmax_t lhs; 1526 file_pushbuf_t *pb; 1527 int rv, oneed_separator, in_type; 1528 char *rbuf; 1529 union VALUETYPE *p = &ms->ms_value; 1530 struct mlist ml; 1531 1532 if (*indir_count >= ms->indir_max) { 1533 file_error(ms, 0, "indirect count (%hu) exceeded", 1534 *indir_count); 1535 return -1; 1536 } 1537 1538 if (*name_count >= ms->name_max) { 1539 file_error(ms, 0, "name use count (%hu) exceeded", 1540 *name_count); 1541 return -1; 1542 } 1543 1544 1545 1546 if (mcopy(ms, p, m->type, m->flag & INDIR, s, 1547 CAST(uint32_t, offset + o), CAST(uint32_t, nbytes), m) == -1) 1548 return -1; 1549 1550 if ((ms->flags & MAGIC_DEBUG) != 0) { 1551 fprintf(stderr, "mget(type=%d, flag=%#x, offset=%u, o=%" 1552 SIZE_T_FORMAT "u, " "nbytes=%" SIZE_T_FORMAT 1553 "u, il=%hu, nc=%hu)\n", 1554 m->type, m->flag, offset, o, nbytes, 1555 *indir_count, *name_count); 1556 mdebug(offset, RCAST(char *, RCAST(void *, p)), 1557 sizeof(union VALUETYPE)); 1558#ifndef COMPILE_ONLY 1559 file_mdump(m); 1560#endif 1561 } 1562 1563 if (m->flag & INDIR) { 1564 intmax_t off = m->in_offset; 1565 const int sgn = m->in_op & FILE_OPSIGNED; 1566 if (m->in_op & FILE_OPINDIRECT) { 1567 const union VALUETYPE *q = CAST(const union VALUETYPE *, 1568 RCAST(const void *, s + offset + off)); 1569 switch (cvt_flip(m->in_type, flip)) { 1570 case FILE_BYTE: 1571 if (OFFSET_OOB(nbytes, offset + off, 1)) 1572 return 0; 1573 off = SEXT(sgn,8,q->b); 1574 break; 1575 case FILE_SHORT: 1576 if (OFFSET_OOB(nbytes, offset + off, 2)) 1577 return 0; 1578 off = SEXT(sgn,16,q->h); 1579 break; 1580 case FILE_BESHORT: 1581 if (OFFSET_OOB(nbytes, offset + off, 2)) 1582 return 0; 1583 off = SEXT(sgn,16,BE16(q)); 1584 break; 1585 case FILE_LESHORT: 1586 if (OFFSET_OOB(nbytes, offset + off, 2)) 1587 return 0; 1588 off = SEXT(sgn,16,LE16(q)); 1589 break; 1590 case FILE_LONG: 1591 if (OFFSET_OOB(nbytes, offset + off, 4)) 1592 return 0; 1593 off = SEXT(sgn,32,q->l); 1594 break; 1595 case FILE_BELONG: 1596 case FILE_BEID3: 1597 if (OFFSET_OOB(nbytes, offset + off, 4)) 1598 return 0; 1599 off = SEXT(sgn,32,BE32(q)); 1600 break; 1601 case FILE_LEID3: 1602 case FILE_LELONG: 1603 if (OFFSET_OOB(nbytes, offset + off, 4)) 1604 return 0; 1605 off = SEXT(sgn,32,LE32(q)); 1606 break; 1607 case FILE_MELONG: 1608 if (OFFSET_OOB(nbytes, offset + off, 4)) 1609 return 0; 1610 off = SEXT(sgn,32,ME32(q)); 1611 break; 1612 case FILE_BEQUAD: 1613 if (OFFSET_OOB(nbytes, offset + off, 8)) 1614 return 0; 1615 off = SEXT(sgn,64,BE64(q)); 1616 break; 1617 case FILE_LEQUAD: 1618 if (OFFSET_OOB(nbytes, offset + off, 8)) 1619 return 0; 1620 off = SEXT(sgn,64,LE64(q)); 1621 break; 1622 default: 1623 abort(); 1624 } 1625 if ((ms->flags & MAGIC_DEBUG) != 0) 1626 fprintf(stderr, "indirect offs=%jd\n", off); 1627 } 1628 switch (in_type = cvt_flip(m->in_type, flip)) { 1629 case FILE_BYTE: 1630 if (OFFSET_OOB(nbytes, offset, 1)) 1631 return 0; 1632 offset = do_ops(m, SEXT(sgn,8,p->b), off); 1633 break; 1634 case FILE_BESHORT: 1635 if (OFFSET_OOB(nbytes, offset, 2)) 1636 return 0; 1637 offset = do_ops(m, SEXT(sgn,16,BE16(p)), off); 1638 break; 1639 case FILE_LESHORT: 1640 if (OFFSET_OOB(nbytes, offset, 2)) 1641 return 0; 1642 offset = do_ops(m, SEXT(sgn,16,LE16(p)), off); 1643 break; 1644 case FILE_SHORT: 1645 if (OFFSET_OOB(nbytes, offset, 2)) 1646 return 0; 1647 offset = do_ops(m, SEXT(sgn,16,p->h), off); 1648 break; 1649 case FILE_BELONG: 1650 case FILE_BEID3: 1651 if (OFFSET_OOB(nbytes, offset, 4)) 1652 return 0; 1653 lhs = BE32(p); 1654 if (in_type == FILE_BEID3) 1655 lhs = cvt_id3(ms, CAST(uint32_t, lhs)); 1656 offset = do_ops(m, SEXT(sgn,32,lhs), off); 1657 break; 1658 case FILE_LELONG: 1659 case FILE_LEID3: 1660 if (OFFSET_OOB(nbytes, offset, 4)) 1661 return 0; 1662 lhs = LE32(p); 1663 if (in_type == FILE_LEID3) 1664 lhs = cvt_id3(ms, CAST(uint32_t, lhs)); 1665 offset = do_ops(m, SEXT(sgn,32,lhs), off); 1666 break; 1667 case FILE_MELONG: 1668 if (OFFSET_OOB(nbytes, offset, 4)) 1669 return 0; 1670 offset = do_ops(m, SEXT(sgn,32,ME32(p)), off); 1671 break; 1672 case FILE_LONG: 1673 if (OFFSET_OOB(nbytes, offset, 4)) 1674 return 0; 1675 offset = do_ops(m, SEXT(sgn,32,p->l), off); 1676 break; 1677 case FILE_LEQUAD: 1678 if (OFFSET_OOB(nbytes, offset, 8)) 1679 return 0; 1680 offset = do_ops(m, SEXT(sgn,64,LE64(p)), off); 1681 break; 1682 case FILE_BEQUAD: 1683 if (OFFSET_OOB(nbytes, offset, 8)) 1684 return 0; 1685 offset = do_ops(m, SEXT(sgn,64,BE64(p)), off); 1686 break; 1687 default: 1688 abort(); 1689 } 1690 1691 if (m->flag & INDIROFFADD) { 1692 offset += ms->c.li[cont_level-1].off; 1693 if (offset == 0) { 1694 if ((ms->flags & MAGIC_DEBUG) != 0) 1695 fprintf(stderr, 1696 "indirect *zero* offset\n"); 1697 return 0; 1698 } 1699 if ((ms->flags & MAGIC_DEBUG) != 0) 1700 fprintf(stderr, "indirect +offs=%u\n", offset); 1701 } 1702 if (mcopy(ms, p, m->type, 0, s, offset, nbytes, m) == -1) 1703 return -1; 1704 ms->offset = offset; 1705 1706 if ((ms->flags & MAGIC_DEBUG) != 0) { 1707 mdebug(offset, RCAST(char *, RCAST(void *, p)), 1708 sizeof(union VALUETYPE)); 1709#ifndef COMPILE_ONLY 1710 file_mdump(m); 1711#endif 1712 } 1713 } 1714 1715 /* Verify we have enough data to match magic type */ 1716 switch (m->type) { 1717 case FILE_BYTE: 1718 if (OFFSET_OOB(nbytes, offset, 1)) 1719 return 0; 1720 break; 1721 1722 case FILE_SHORT: 1723 case FILE_BESHORT: 1724 case FILE_LESHORT: 1725 if (OFFSET_OOB(nbytes, offset, 2)) 1726 return 0; 1727 break; 1728 1729 case FILE_LONG: 1730 case FILE_BELONG: 1731 case FILE_LELONG: 1732 case FILE_MELONG: 1733 case FILE_DATE: 1734 case FILE_BEDATE: 1735 case FILE_LEDATE: 1736 case FILE_MEDATE: 1737 case FILE_LDATE: 1738 case FILE_BELDATE: 1739 case FILE_LELDATE: 1740 case FILE_MELDATE: 1741 case FILE_FLOAT: 1742 case FILE_BEFLOAT: 1743 case FILE_LEFLOAT: 1744 if (OFFSET_OOB(nbytes, offset, 4)) 1745 return 0; 1746 break; 1747 1748 case FILE_DOUBLE: 1749 case FILE_BEDOUBLE: 1750 case FILE_LEDOUBLE: 1751 if (OFFSET_OOB(nbytes, offset, 8)) 1752 return 0; 1753 break; 1754 1755 case FILE_STRING: 1756 case FILE_PSTRING: 1757 case FILE_SEARCH: 1758 if (OFFSET_OOB(nbytes, offset, m->vallen)) 1759 return 0; 1760 break; 1761 1762 case FILE_REGEX: 1763 if (nbytes < offset) 1764 return 0; 1765 break; 1766 1767 case FILE_INDIRECT: 1768 if (m->str_flags & INDIRECT_RELATIVE) 1769 offset += CAST(uint32_t, o); 1770 if (offset == 0) 1771 return 0; 1772 1773 if (nbytes < offset) 1774 return 0; 1775 1776 if ((pb = file_push_buffer(ms)) == NULL) 1777 return -1; 1778 1779 (*indir_count)++; 1780 bb = *b; 1781 bb.fbuf = s + offset; 1782 bb.flen = nbytes - offset; 1783 rv = file_softmagic(ms, &bb, 1784 indir_count, name_count, BINTEST, text); 1785 1786 if ((ms->flags & MAGIC_DEBUG) != 0) 1787 fprintf(stderr, "indirect @offs=%u[%d]\n", offset, rv); 1788 1789 rbuf = file_pop_buffer(ms, pb); 1790 if (rbuf == NULL && ms->event_flags & EVENT_HAD_ERR) 1791 return -1; 1792 1793 if (rv == 1) { 1794 if ((ms->flags & MAGIC_NODESC) == 0 && 1795 file_printf(ms, F(ms, m->desc, "%u"), offset) == -1) 1796 { 1797 free(rbuf); 1798 return -1; 1799 } 1800 if (file_printf(ms, "%s", rbuf) == -1) { 1801 free(rbuf); 1802 return -1; 1803 } 1804 } 1805 free(rbuf); 1806 return rv; 1807 1808 case FILE_USE: 1809 if (nbytes < offset) 1810 return 0; 1811 rbuf = m->value.s; 1812 if (*rbuf == '^') { 1813 rbuf++; 1814 flip = !flip; 1815 } 1816 if (file_magicfind(ms, rbuf, &ml) == -1) { 1817 file_error(ms, 0, "cannot find entry `%s'", rbuf); 1818 return -1; 1819 } 1820 (*name_count)++; 1821 oneed_separator = *need_separator; 1822 if (m->flag & NOSPACE) 1823 *need_separator = 0; 1824 rv = match(ms, ml.magic, ml.nmagic, b, offset + o, 1825 mode, text, flip, indir_count, name_count, 1826 printed_something, need_separator, returnval, found_match); 1827 (*name_count)--; 1828 if (rv != 1) 1829 *need_separator = oneed_separator; 1830 return rv; 1831 1832 case FILE_NAME: 1833 if (ms->flags & MAGIC_NODESC) 1834 return 1; 1835 if (file_printf(ms, "%s", m->desc) == -1) 1836 return -1; 1837 return 1; 1838 case FILE_DER: 1839 case FILE_DEFAULT: /* nothing to check */ 1840 case FILE_CLEAR: 1841 default: 1842 break; 1843 } 1844 if (!mconvert(ms, m, flip)) 1845 return 0; 1846 return 1; 1847} 1848 1849private uint64_t 1850file_strncmp(const char *s1, const char *s2, size_t len, uint32_t flags) 1851{ 1852 /* 1853 * Convert the source args to unsigned here so that (1) the 1854 * compare will be unsigned as it is in strncmp() and (2) so 1855 * the ctype functions will work correctly without extra 1856 * casting. 1857 */ 1858 const unsigned char *a = RCAST(const unsigned char *, s1); 1859 const unsigned char *b = RCAST(const unsigned char *, s2); 1860 const unsigned char *eb = b + len; 1861 uint64_t v; 1862 1863 /* 1864 * What we want here is v = strncmp(s1, s2, len), 1865 * but ignoring any nulls. 1866 */ 1867 v = 0; 1868 if (0L == flags) { /* normal string: do it fast */ 1869 while (len-- > 0) 1870 if ((v = *b++ - *a++) != '\0') 1871 break; 1872 } 1873 else { /* combine the others */ 1874 while (len-- > 0) { 1875 if (b >= eb) { 1876 v = 1; 1877 break; 1878 } 1879 if ((flags & STRING_IGNORE_LOWERCASE) && 1880 islower(*a)) { 1881 if ((v = tolower(*b++) - *a++) != '\0') 1882 break; 1883 } 1884 else if ((flags & STRING_IGNORE_UPPERCASE) && 1885 isupper(*a)) { 1886 if ((v = toupper(*b++) - *a++) != '\0') 1887 break; 1888 } 1889 else if ((flags & STRING_COMPACT_WHITESPACE) && 1890 isspace(*a)) { 1891 a++; 1892 if (isspace(*b++)) { 1893 if (!isspace(*a)) 1894 while (b < eb && isspace(*b)) 1895 b++; 1896 } 1897 else { 1898 v = 1; 1899 break; 1900 } 1901 } 1902 else if ((flags & STRING_COMPACT_OPTIONAL_WHITESPACE) && 1903 isspace(*a)) { 1904 a++; 1905 while (b < eb && isspace(*b)) 1906 b++; 1907 } 1908 else { 1909 if ((v = *b++ - *a++) != '\0') 1910 break; 1911 } 1912 } 1913 } 1914 return v; 1915} 1916 1917private uint64_t 1918file_strncmp16(const char *a, const char *b, size_t len, uint32_t flags) 1919{ 1920 /* 1921 * XXX - The 16-bit string compare probably needs to be done 1922 * differently, especially if the flags are to be supported. 1923 * At the moment, I am unsure. 1924 */ 1925 flags = 0; 1926 return file_strncmp(a, b, len, flags); 1927} 1928 1929private int 1930magiccheck(struct magic_set *ms, struct magic *m) 1931{ 1932 uint64_t l = m->value.q; 1933 uint64_t v; 1934 float fl, fv; 1935 double dl, dv; 1936 int matched; 1937 union VALUETYPE *p = &ms->ms_value; 1938 1939 switch (m->type) { 1940 case FILE_BYTE: 1941 v = p->b; 1942 break; 1943 1944 case FILE_SHORT: 1945 case FILE_BESHORT: 1946 case FILE_LESHORT: 1947 v = p->h; 1948 break; 1949 1950 case FILE_LONG: 1951 case FILE_BELONG: 1952 case FILE_LELONG: 1953 case FILE_MELONG: 1954 case FILE_DATE: 1955 case FILE_BEDATE: 1956 case FILE_LEDATE: 1957 case FILE_MEDATE: 1958 case FILE_LDATE: 1959 case FILE_BELDATE: 1960 case FILE_LELDATE: 1961 case FILE_MELDATE: 1962 v = p->l; 1963 break; 1964 1965 case FILE_QUAD: 1966 case FILE_LEQUAD: 1967 case FILE_BEQUAD: 1968 case FILE_QDATE: 1969 case FILE_BEQDATE: 1970 case FILE_LEQDATE: 1971 case FILE_QLDATE: 1972 case FILE_BEQLDATE: 1973 case FILE_LEQLDATE: 1974 case FILE_QWDATE: 1975 case FILE_BEQWDATE: 1976 case FILE_LEQWDATE: 1977 v = p->q; 1978 break; 1979 1980 case FILE_FLOAT: 1981 case FILE_BEFLOAT: 1982 case FILE_LEFLOAT: 1983 fl = m->value.f; 1984 fv = p->f; 1985 switch (m->reln) { 1986 case 'x': 1987 matched = 1; 1988 break; 1989 1990 case '!': 1991 matched = fv != fl; 1992 break; 1993 1994 case '=': 1995 matched = fv == fl; 1996 break; 1997 1998 case '>': 1999 matched = fv > fl; 2000 break; 2001 2002 case '<': 2003 matched = fv < fl; 2004 break; 2005 2006 default: 2007 file_magerror(ms, "cannot happen with float: invalid relation `%c'", 2008 m->reln); 2009 return -1; 2010 } 2011 return matched; 2012 2013 case FILE_DOUBLE: 2014 case FILE_BEDOUBLE: 2015 case FILE_LEDOUBLE: 2016 dl = m->value.d; 2017 dv = p->d; 2018 switch (m->reln) { 2019 case 'x': 2020 matched = 1; 2021 break; 2022 2023 case '!': 2024 matched = dv != dl; 2025 break; 2026 2027 case '=': 2028 matched = dv == dl; 2029 break; 2030 2031 case '>': 2032 matched = dv > dl; 2033 break; 2034 2035 case '<': 2036 matched = dv < dl; 2037 break; 2038 2039 default: 2040 file_magerror(ms, "cannot happen with double: invalid relation `%c'", m->reln); 2041 return -1; 2042 } 2043 return matched; 2044 2045 case FILE_DEFAULT: 2046 case FILE_CLEAR: 2047 l = 0; 2048 v = 0; 2049 break; 2050 2051 case FILE_STRING: 2052 case FILE_PSTRING: 2053 l = 0; 2054 v = file_strncmp(m->value.s, p->s, CAST(size_t, m->vallen), 2055 m->str_flags); 2056 break; 2057 2058 case FILE_BESTRING16: 2059 case FILE_LESTRING16: 2060 l = 0; 2061 v = file_strncmp16(m->value.s, p->s, CAST(size_t, m->vallen), 2062 m->str_flags); 2063 break; 2064 2065 case FILE_SEARCH: { /* search ms->search.s for the string m->value.s */ 2066 size_t slen; 2067 size_t idx; 2068 2069 if (ms->search.s == NULL) 2070 return 0; 2071 2072 slen = MIN(m->vallen, sizeof(m->value.s)); 2073 l = 0; 2074 v = 0; 2075#ifdef HAVE_MEMMEM 2076 if (slen > 0 && m->str_flags == 0) { 2077 const char *found; 2078 idx = m->str_range + slen; 2079 if (m->str_range == 0 || ms->search.s_len < idx) 2080 idx = ms->search.s_len; 2081 found = CAST(const char *, memmem(ms->search.s, idx, 2082 m->value.s, slen)); 2083 if (!found) 2084 return 0; 2085 idx = found - ms->search.s; 2086 ms->search.offset += idx; 2087 ms->search.rm_len = ms->search.s_len - idx; 2088 break; 2089 } 2090#endif 2091 2092 for (idx = 0; m->str_range == 0 || idx < m->str_range; idx++) { 2093 if (slen + idx > ms->search.s_len) 2094 return 0; 2095 2096 v = file_strncmp(m->value.s, ms->search.s + idx, slen, 2097 m->str_flags); 2098 if (v == 0) { /* found match */ 2099 ms->search.offset += idx; 2100 ms->search.rm_len = ms->search.s_len - idx; 2101 break; 2102 } 2103 } 2104 break; 2105 } 2106 case FILE_REGEX: { 2107 int rc; 2108 file_regex_t rx; 2109 const char *search; 2110 2111 if (ms->search.s == NULL) 2112 return 0; 2113 2114 l = 0; 2115 rc = file_regcomp(&rx, m->value.s, 2116 REG_EXTENDED|REG_NEWLINE| 2117 ((m->str_flags & STRING_IGNORE_CASE) ? REG_ICASE : 0)); 2118 if (rc) { 2119 file_regerror(&rx, rc, ms); 2120 v = CAST(uint64_t, -1); 2121 } else { 2122 regmatch_t pmatch; 2123 size_t slen = ms->search.s_len; 2124 char *copy; 2125 if (slen != 0) { 2126 copy = CAST(char *, malloc(slen)); 2127 if (copy == NULL) { 2128 file_regfree(&rx); 2129 file_error(ms, errno, 2130 "can't allocate %" SIZE_T_FORMAT "u bytes", 2131 slen); 2132 return -1; 2133 } 2134 memcpy(copy, ms->search.s, slen); 2135 copy[--slen] = '\0'; 2136 search = copy; 2137 } else { 2138 search = CCAST(char *, ""); 2139 copy = NULL; 2140 } 2141 rc = file_regexec(&rx, RCAST(const char *, search), 2142 1, &pmatch, 0); 2143 free(copy); 2144 switch (rc) { 2145 case 0: 2146 ms->search.s += CAST(int, pmatch.rm_so); 2147 ms->search.offset += CAST(size_t, pmatch.rm_so); 2148 ms->search.rm_len = CAST(size_t, 2149 pmatch.rm_eo - pmatch.rm_so); 2150 v = 0; 2151 break; 2152 2153 case REG_NOMATCH: 2154 v = 1; 2155 break; 2156 2157 default: 2158 file_regerror(&rx, rc, ms); 2159 v = CAST(uint64_t, -1); 2160 break; 2161 } 2162 } 2163 file_regfree(&rx); 2164 if (v == CAST(uint64_t, -1)) 2165 return -1; 2166 break; 2167 } 2168 case FILE_INDIRECT: 2169 case FILE_USE: 2170 case FILE_NAME: 2171 return 1; 2172 case FILE_DER: 2173 matched = der_cmp(ms, m); 2174 if (matched == -1) { 2175 if ((ms->flags & MAGIC_DEBUG) != 0) { 2176 (void) fprintf(stderr, 2177 "EOF comparing DER entries"); 2178 } 2179 return 0; 2180 } 2181 return matched; 2182 default: 2183 file_magerror(ms, "invalid type %d in magiccheck()", m->type); 2184 return -1; 2185 } 2186 2187 v = file_signextend(ms, m, v); 2188 2189 switch (m->reln) { 2190 case 'x': 2191 if ((ms->flags & MAGIC_DEBUG) != 0) 2192 (void) fprintf(stderr, "%" INT64_T_FORMAT 2193 "u == *any* = 1\n", CAST(unsigned long long, v)); 2194 matched = 1; 2195 break; 2196 2197 case '!': 2198 matched = v != l; 2199 if ((ms->flags & MAGIC_DEBUG) != 0) 2200 (void) fprintf(stderr, "%" INT64_T_FORMAT "u != %" 2201 INT64_T_FORMAT "u = %d\n", 2202 CAST(unsigned long long, v), 2203 CAST(unsigned long long, l), matched); 2204 break; 2205 2206 case '=': 2207 matched = v == l; 2208 if ((ms->flags & MAGIC_DEBUG) != 0) 2209 (void) fprintf(stderr, "%" INT64_T_FORMAT "u == %" 2210 INT64_T_FORMAT "u = %d\n", 2211 CAST(unsigned long long, v), 2212 CAST(unsigned long long, l), matched); 2213 break; 2214 2215 case '>': 2216 if (m->flag & UNSIGNED) { 2217 matched = v > l; 2218 if ((ms->flags & MAGIC_DEBUG) != 0) 2219 (void) fprintf(stderr, "%" INT64_T_FORMAT 2220 "u > %" INT64_T_FORMAT "u = %d\n", 2221 CAST(unsigned long long, v), 2222 CAST(unsigned long long, l), matched); 2223 } 2224 else { 2225 matched = CAST(int64_t, v) > CAST(int64_t, l); 2226 if ((ms->flags & MAGIC_DEBUG) != 0) 2227 (void) fprintf(stderr, "%" INT64_T_FORMAT 2228 "d > %" INT64_T_FORMAT "d = %d\n", 2229 CAST(long long, v), 2230 CAST(long long, l), matched); 2231 } 2232 break; 2233 2234 case '<': 2235 if (m->flag & UNSIGNED) { 2236 matched = v < l; 2237 if ((ms->flags & MAGIC_DEBUG) != 0) 2238 (void) fprintf(stderr, "%" INT64_T_FORMAT 2239 "u < %" INT64_T_FORMAT "u = %d\n", 2240 CAST(unsigned long long, v), 2241 CAST(unsigned long long, l), matched); 2242 } 2243 else { 2244 matched = CAST(int64_t, v) < CAST(int64_t, l); 2245 if ((ms->flags & MAGIC_DEBUG) != 0) 2246 (void) fprintf(stderr, "%" INT64_T_FORMAT 2247 "d < %" INT64_T_FORMAT "d = %d\n", 2248 CAST(long long, v), 2249 CAST(long long, l), matched); 2250 } 2251 break; 2252 2253 case '&': 2254 matched = (v & l) == l; 2255 if ((ms->flags & MAGIC_DEBUG) != 0) 2256 (void) fprintf(stderr, "((%" INT64_T_FORMAT "x & %" 2257 INT64_T_FORMAT "x) == %" INT64_T_FORMAT 2258 "x) = %d\n", CAST(unsigned long long, v), 2259 CAST(unsigned long long, l), 2260 CAST(unsigned long long, l), 2261 matched); 2262 break; 2263 2264 case '^': 2265 matched = (v & l) != l; 2266 if ((ms->flags & MAGIC_DEBUG) != 0) 2267 (void) fprintf(stderr, "((%" INT64_T_FORMAT "x & %" 2268 INT64_T_FORMAT "x) != %" INT64_T_FORMAT 2269 "x) = %d\n", CAST(unsigned long long, v), 2270 CAST(unsigned long long, l), 2271 CAST(unsigned long long, l), matched); 2272 break; 2273 2274 default: 2275 file_magerror(ms, "cannot happen: invalid relation `%c'", 2276 m->reln); 2277 return -1; 2278 } 2279 2280 return matched; 2281} 2282 2283private int 2284handle_annotation(struct magic_set *ms, struct magic *m, int firstline) 2285{ 2286 if ((ms->flags & MAGIC_APPLE) && m->apple[0]) { 2287 if (print_sep(ms, firstline) == -1) 2288 return -1; 2289 if (file_printf(ms, "%.8s", m->apple) == -1) 2290 return -1; 2291 return 1; 2292 } 2293 if ((ms->flags & MAGIC_EXTENSION) && m->ext[0]) { 2294 if (print_sep(ms, firstline) == -1) 2295 return -1; 2296 if (file_printf(ms, "%s", m->ext) == -1) 2297 return -1; 2298 return 1; 2299 } 2300 if ((ms->flags & MAGIC_MIME_TYPE) && m->mimetype[0]) { 2301 char buf[1024]; 2302 const char *p; 2303 if (print_sep(ms, firstline) == -1) 2304 return -1; 2305 if (varexpand(ms, buf, sizeof(buf), m->mimetype) == -1) 2306 p = m->mimetype; 2307 else 2308 p = buf; 2309 if (file_printf(ms, "%s", p) == -1) 2310 return -1; 2311 return 1; 2312 } 2313 return 0; 2314} 2315 2316private int 2317print_sep(struct magic_set *ms, int firstline) 2318{ 2319 if (firstline) 2320 return 0; 2321 /* 2322 * we found another match 2323 * put a newline and '-' to do some simple formatting 2324 */ 2325 return file_separator(ms); 2326} 2327