magic.c revision 133359
1133359Sobrien/* 2133359Sobrien * Copyright (c) Christos Zoulas 2003. 3133359Sobrien * All Rights Reserved. 4133359Sobrien * 5133359Sobrien * Redistribution and use in source and binary forms, with or without 6133359Sobrien * modification, are permitted provided that the following conditions 7133359Sobrien * are met: 8133359Sobrien * 1. Redistributions of source code must retain the above copyright 9133359Sobrien * notice immediately at the beginning of the file, without modification, 10133359Sobrien * this list of conditions, and the following disclaimer. 11133359Sobrien * 2. Redistributions in binary form must reproduce the above copyright 12133359Sobrien * notice, this list of conditions and the following disclaimer in the 13133359Sobrien * documentation and/or other materials provided with the distribution. 14133359Sobrien * 3. The name of the author may not be used to endorse or promote products 15133359Sobrien * derived from this software without specific prior written permission. 16133359Sobrien * 17133359Sobrien * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 18133359Sobrien * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19133359Sobrien * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20133359Sobrien * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR 21133359Sobrien * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22133359Sobrien * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23133359Sobrien * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24133359Sobrien * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25133359Sobrien * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26133359Sobrien * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27133359Sobrien * SUCH DAMAGE. 28133359Sobrien */ 29133359Sobrien 30133359Sobrien#include "file.h" 31133359Sobrien#include "magic.h" 32133359Sobrien 33133359Sobrien#include <stdio.h> 34133359Sobrien#include <stdlib.h> 35133359Sobrien#include <unistd.h> 36133359Sobrien#include <string.h> 37133359Sobrien#include <sys/types.h> 38133359Sobrien#include <sys/param.h> /* for MAXPATHLEN */ 39133359Sobrien#include <sys/stat.h> 40133359Sobrien#include <fcntl.h> /* for open() */ 41133359Sobrien#ifdef QUICK 42133359Sobrien#include <sys/mman.h> 43133359Sobrien#endif 44133359Sobrien 45133359Sobrien#if defined(HAVE_UTIMES) 46133359Sobrien# include <sys/time.h> 47133359Sobrien#elif defined(HAVE_UTIME) 48133359Sobrien# if defined(HAVE_SYS_UTIME_H) 49133359Sobrien# include <sys/utime.h> 50133359Sobrien# elif defined(HAVE_UTIME_H) 51133359Sobrien# include <utime.h> 52133359Sobrien# endif 53133359Sobrien#endif 54133359Sobrien 55133359Sobrien#ifdef HAVE_UNISTD_H 56133359Sobrien#include <unistd.h> /* for read() */ 57133359Sobrien#endif 58133359Sobrien 59133359Sobrien#ifdef HAVE_LOCALE_H 60133359Sobrien#include <locale.h> 61133359Sobrien#endif 62133359Sobrien 63133359Sobrien#include <netinet/in.h> /* for byte swapping */ 64133359Sobrien 65133359Sobrien#include "patchlevel.h" 66133359Sobrien 67133359Sobrien#ifndef lint 68133359SobrienFILE_RCSID("@(#)$Id: magic.c,v 1.22 2004/07/24 19:55:17 christos Exp $") 69133359Sobrien#endif /* lint */ 70133359Sobrien 71133359Sobrien#ifdef __EMX__ 72133359Sobrienprivate char *apptypeName = NULL; 73133359Sobrienprotected int file_os2_apptype(struct magic_set *ms, const char *fn, 74133359Sobrien const void *buf, size_t nb); 75133359Sobrien#endif /* __EMX__ */ 76133359Sobrien 77133359Sobrienprivate void free_mlist(struct mlist *); 78133359Sobrienprivate void close_and_restore(const struct magic_set *, const char *, int, 79133359Sobrien const struct stat *); 80133359Sobrien 81133359Sobrienpublic struct magic_set * 82133359Sobrienmagic_open(int flags) 83133359Sobrien{ 84133359Sobrien struct magic_set *ms; 85133359Sobrien 86133359Sobrien if ((ms = malloc(sizeof(struct magic_set))) == NULL) 87133359Sobrien return NULL; 88133359Sobrien 89133359Sobrien if (magic_setflags(ms, flags) == -1) { 90133359Sobrien free(ms); 91133359Sobrien errno = EINVAL; 92133359Sobrien return NULL; 93133359Sobrien } 94133359Sobrien 95133359Sobrien ms->o.ptr = ms->o.buf = malloc(ms->o.size = 1024); 96133359Sobrien ms->o.len = 0; 97133359Sobrien if (ms->o.buf == NULL) { 98133359Sobrien free(ms); 99133359Sobrien return NULL; 100133359Sobrien } 101133359Sobrien ms->o.pbuf = malloc(ms->o.psize = 1024); 102133359Sobrien if (ms->o.pbuf == NULL) { 103133359Sobrien free(ms->o.buf); 104133359Sobrien free(ms); 105133359Sobrien return NULL; 106133359Sobrien } 107133359Sobrien ms->c.off = malloc((ms->c.len = 10) * sizeof(*ms->c.off)); 108133359Sobrien if (ms->c.off == NULL) { 109133359Sobrien free(ms->o.pbuf); 110133359Sobrien free(ms->o.buf); 111133359Sobrien free(ms); 112133359Sobrien return NULL; 113133359Sobrien } 114133359Sobrien ms->haderr = 0; 115133359Sobrien ms->error = -1; 116133359Sobrien ms->mlist = NULL; 117133359Sobrien return ms; 118133359Sobrien} 119133359Sobrien 120133359Sobrienprivate void 121133359Sobrienfree_mlist(struct mlist *mlist) 122133359Sobrien{ 123133359Sobrien struct mlist *ml; 124133359Sobrien 125133359Sobrien if (mlist == NULL) 126133359Sobrien return; 127133359Sobrien 128133359Sobrien for (ml = mlist->next; ml != mlist;) { 129133359Sobrien struct mlist *next = ml->next; 130133359Sobrien struct magic *mg = ml->magic; 131133359Sobrien file_delmagic(mg, ml->mapped, ml->nmagic); 132133359Sobrien free(ml); 133133359Sobrien ml = next; 134133359Sobrien } 135133359Sobrien free(ml); 136133359Sobrien} 137133359Sobrien 138133359Sobrienpublic void 139133359Sobrienmagic_close(ms) 140133359Sobrien struct magic_set *ms; 141133359Sobrien{ 142133359Sobrien free_mlist(ms->mlist); 143133359Sobrien free(ms->o.buf); 144133359Sobrien free(ms->c.off); 145133359Sobrien free(ms); 146133359Sobrien} 147133359Sobrien 148133359Sobrien/* 149133359Sobrien * load a magic file 150133359Sobrien */ 151133359Sobrienpublic int 152133359Sobrienmagic_load(struct magic_set *ms, const char *magicfile) 153133359Sobrien{ 154133359Sobrien struct mlist *ml = file_apprentice(ms, magicfile, FILE_LOAD); 155133359Sobrien if (ml) { 156133359Sobrien free_mlist(ms->mlist); 157133359Sobrien ms->mlist = ml; 158133359Sobrien return 0; 159133359Sobrien } 160133359Sobrien return -1; 161133359Sobrien} 162133359Sobrien 163133359Sobrienpublic int 164133359Sobrienmagic_compile(struct magic_set *ms, const char *magicfile) 165133359Sobrien{ 166133359Sobrien struct mlist *ml = file_apprentice(ms, magicfile, FILE_COMPILE); 167133359Sobrien free_mlist(ml); 168133359Sobrien return ml ? 0 : -1; 169133359Sobrien} 170133359Sobrien 171133359Sobrienpublic int 172133359Sobrienmagic_check(struct magic_set *ms, const char *magicfile) 173133359Sobrien{ 174133359Sobrien struct mlist *ml = file_apprentice(ms, magicfile, FILE_CHECK); 175133359Sobrien free_mlist(ml); 176133359Sobrien return ml ? 0 : -1; 177133359Sobrien} 178133359Sobrien 179133359Sobrienprivate void 180133359Sobrienclose_and_restore(const struct magic_set *ms, const char *name, int fd, 181133359Sobrien const struct stat *sb) 182133359Sobrien{ 183133359Sobrien (void) close(fd); 184133359Sobrien if (fd != STDIN_FILENO && (ms->flags & MAGIC_PRESERVE_ATIME) != 0) { 185133359Sobrien /* 186133359Sobrien * Try to restore access, modification times if read it. 187133359Sobrien * This is really *bad* because it will modify the status 188133359Sobrien * time of the file... And of course this will affect 189133359Sobrien * backup programs 190133359Sobrien */ 191133359Sobrien#ifdef HAVE_UTIMES 192133359Sobrien struct timeval utsbuf[2]; 193133359Sobrien utsbuf[0].tv_sec = sb->st_atime; 194133359Sobrien utsbuf[1].tv_sec = sb->st_mtime; 195133359Sobrien 196133359Sobrien (void) utimes(name, utsbuf); /* don't care if loses */ 197133359Sobrien#elif defined(HAVE_UTIME_H) || defined(HAVE_SYS_UTIME_H) 198133359Sobrien struct utimbuf utbuf; 199133359Sobrien 200133359Sobrien utbuf.actime = sb->st_atime; 201133359Sobrien utbuf.modtime = sb->st_mtime; 202133359Sobrien (void) utime(name, &utbuf); /* don't care if loses */ 203133359Sobrien#endif 204133359Sobrien } 205133359Sobrien} 206133359Sobrien 207133359Sobrien#ifndef COMPILE_ONLY 208133359Sobrien/* 209133359Sobrien * find type of named file 210133359Sobrien */ 211133359Sobrienpublic const char * 212133359Sobrienmagic_file(struct magic_set *ms, const char *inname) 213133359Sobrien{ 214133359Sobrien int fd = 0; 215133359Sobrien unsigned char buf[HOWMANY+1]; /* one extra for terminating '\0' */ 216133359Sobrien struct stat sb; 217133359Sobrien ssize_t nbytes = 0; /* number of bytes read from a datafile */ 218133359Sobrien 219133359Sobrien if (file_reset(ms) == -1) 220133359Sobrien return NULL; 221133359Sobrien 222133359Sobrien switch (file_fsmagic(ms, inname, &sb)) { 223133359Sobrien case -1: 224133359Sobrien return NULL; 225133359Sobrien case 0: 226133359Sobrien break; 227133359Sobrien default: 228133359Sobrien return file_getbuffer(ms); 229133359Sobrien } 230133359Sobrien 231133359Sobrien#ifndef STDIN_FILENO 232133359Sobrien#define STDIN_FILENO 0 233133359Sobrien#endif 234133359Sobrien if (inname == NULL) 235133359Sobrien fd = STDIN_FILENO; 236133359Sobrien else if ((fd = open(inname, O_RDONLY)) < 0) { 237133359Sobrien /* We cannot open it, but we were able to stat it. */ 238133359Sobrien if (sb.st_mode & 0222) 239133359Sobrien if (file_printf(ms, "writable, ") == -1) 240133359Sobrien return NULL; 241133359Sobrien if (sb.st_mode & 0111) 242133359Sobrien if (file_printf(ms, "executable, ") == -1) 243133359Sobrien return NULL; 244133359Sobrien if (S_ISREG(sb.st_mode)) 245133359Sobrien if (file_printf(ms, "regular file, ") == -1) 246133359Sobrien return NULL; 247133359Sobrien if (file_printf(ms, "no read permission") == -1) 248133359Sobrien return NULL; 249133359Sobrien return file_getbuffer(ms); 250133359Sobrien } 251133359Sobrien 252133359Sobrien /* 253133359Sobrien * try looking at the first HOWMANY bytes 254133359Sobrien */ 255133359Sobrien if ((nbytes = read(fd, (char *)buf, HOWMANY)) == -1) { 256133359Sobrien file_error(ms, errno, "cannot read `%s'", inname); 257133359Sobrien goto done; 258133359Sobrien } 259133359Sobrien 260133359Sobrien if (nbytes == 0) { 261133359Sobrien if (file_printf(ms, (ms->flags & MAGIC_MIME) ? 262133359Sobrien "application/x-empty" : "empty") == -1) 263133359Sobrien goto done; 264133359Sobrien goto gotit; 265133359Sobrien } else if (nbytes == 1) { 266133359Sobrien if (file_printf(ms, "very short file (no magic)") == -1) 267133359Sobrien goto done; 268133359Sobrien goto gotit; 269133359Sobrien } else { 270133359Sobrien buf[nbytes] = '\0'; /* null-terminate it */ 271133359Sobrien#ifdef __EMX__ 272133359Sobrien switch (file_os2_apptype(ms, inname, buf, nbytes)) { 273133359Sobrien case -1: 274133359Sobrien goto done; 275133359Sobrien case 0: 276133359Sobrien break; 277133359Sobrien default: 278133359Sobrien goto gotit; 279133359Sobrien } 280133359Sobrien#endif 281133359Sobrien if (file_buffer(ms, buf, (size_t)nbytes) == -1) 282133359Sobrien goto done; 283133359Sobrien#ifdef BUILTIN_ELF 284133359Sobrien if (nbytes > 5) { 285133359Sobrien /* 286133359Sobrien * We matched something in the file, so this *might* 287133359Sobrien * be an ELF file, and the file is at least 5 bytes 288133359Sobrien * long, so if it's an ELF file it has at least one 289133359Sobrien * byte past the ELF magic number - try extracting 290133359Sobrien * information from the ELF headers that cannot easily 291133359Sobrien * be extracted with rules in the magic file. 292133359Sobrien */ 293133359Sobrien file_tryelf(ms, fd, buf, (size_t)nbytes); 294133359Sobrien } 295133359Sobrien#endif 296133359Sobrien } 297133359Sobriengotit: 298133359Sobrien close_and_restore(ms, inname, fd, &sb); 299133359Sobrien return file_getbuffer(ms); 300133359Sobriendone: 301133359Sobrien close_and_restore(ms, inname, fd, &sb); 302133359Sobrien return NULL; 303133359Sobrien} 304133359Sobrien 305133359Sobrien 306133359Sobrienpublic const char * 307133359Sobrienmagic_buffer(struct magic_set *ms, const void *buf, size_t nb) 308133359Sobrien{ 309133359Sobrien if (file_reset(ms) == -1) 310133359Sobrien return NULL; 311133359Sobrien /* 312133359Sobrien * The main work is done here! 313133359Sobrien * We have the file name and/or the data buffer to be identified. 314133359Sobrien */ 315133359Sobrien if (file_buffer(ms, buf, nb) == -1) { 316133359Sobrien return NULL; 317133359Sobrien } 318133359Sobrien return file_getbuffer(ms); 319133359Sobrien} 320133359Sobrien#endif 321133359Sobrien 322133359Sobrienpublic const char * 323133359Sobrienmagic_error(struct magic_set *ms) 324133359Sobrien{ 325133359Sobrien return ms->haderr ? ms->o.buf : NULL; 326133359Sobrien} 327133359Sobrien 328133359Sobrienpublic int 329133359Sobrienmagic_errno(struct magic_set *ms) 330133359Sobrien{ 331133359Sobrien return ms->haderr ? ms->error : 0; 332133359Sobrien} 333133359Sobrien 334133359Sobrienpublic int 335133359Sobrienmagic_setflags(struct magic_set *ms, int flags) 336133359Sobrien{ 337133359Sobrien#if !defined(HAVE_UTIME) && !defined(HAVE_UTIMES) 338133359Sobrien if (flags & MAGIC_PRESERVE_ATIME) 339133359Sobrien return -1; 340133359Sobrien#endif 341133359Sobrien ms->flags = flags; 342133359Sobrien return 0; 343133359Sobrien} 344