magic.c revision 169942
1/* 2 * Copyright (c) Christos Zoulas 2003. 3 * All Rights Reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice immediately at the beginning of the file, without modification, 10 * this list of conditions, and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR 19 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25 * SUCH DAMAGE. 26 */ 27 28#include "file.h" 29#include "magic.h" 30 31#include <stdio.h> 32#include <stdlib.h> 33#include <unistd.h> 34#include <string.h> 35#include <sys/types.h> 36#include <sys/param.h> /* for MAXPATHLEN */ 37#include <sys/stat.h> 38#ifdef QUICK 39#include <sys/mman.h> 40#endif 41#include <limits.h> /* for PIPE_BUF */ 42 43#if defined(HAVE_UTIMES) 44# include <sys/time.h> 45#elif defined(HAVE_UTIME) 46# if defined(HAVE_SYS_UTIME_H) 47# include <sys/utime.h> 48# elif defined(HAVE_UTIME_H) 49# include <utime.h> 50# endif 51#endif 52 53#ifdef HAVE_UNISTD_H 54#include <unistd.h> /* for read() */ 55#endif 56 57#ifdef HAVE_LOCALE_H 58#include <locale.h> 59#endif 60 61#include <netinet/in.h> /* for byte swapping */ 62 63#include "patchlevel.h" 64 65#ifndef lint 66FILE_RCSID("@(#)$Id: magic.c,v 1.35 2006/10/31 19:37:17 christos Exp $") 67#endif /* lint */ 68 69#ifdef __EMX__ 70private char *apptypeName = NULL; 71protected int file_os2_apptype(struct magic_set *ms, const char *fn, 72 const void *buf, size_t nb); 73#endif /* __EMX__ */ 74 75private void free_mlist(struct mlist *); 76private void close_and_restore(const struct magic_set *, const char *, int, 77 const struct stat *); 78private int info_from_stat(struct magic_set *, mode_t); 79 80#ifndef STDIN_FILENO 81#define STDIN_FILENO 0 82#endif 83 84public struct magic_set * 85magic_open(int flags) 86{ 87 struct magic_set *ms; 88 89 if ((ms = malloc(sizeof(struct magic_set))) == NULL) 90 return NULL; 91 92 if (magic_setflags(ms, flags) == -1) { 93 errno = EINVAL; 94 goto free1; 95 } 96 97 ms->o.ptr = ms->o.buf = malloc(ms->o.size = 1024); 98 if (ms->o.buf == NULL) 99 goto free1; 100 101 ms->o.pbuf = malloc(ms->o.psize = 1024); 102 if (ms->o.pbuf == NULL) 103 goto free2; 104 105 ms->c.off = malloc((ms->c.len = 10) * sizeof(*ms->c.off)); 106 if (ms->c.off == NULL) 107 goto free3; 108 109 ms->o.len = 0; 110 ms->haderr = 0; 111 ms->error = -1; 112 ms->mlist = NULL; 113 return ms; 114free3: 115 free(ms->o.pbuf); 116free2: 117 free(ms->o.buf); 118free1: 119 free(ms); 120 return NULL; 121} 122 123private void 124free_mlist(struct mlist *mlist) 125{ 126 struct mlist *ml; 127 128 if (mlist == NULL) 129 return; 130 131 for (ml = mlist->next; ml != mlist;) { 132 struct mlist *next = ml->next; 133 struct magic *mg = ml->magic; 134 file_delmagic(mg, ml->mapped, ml->nmagic); 135 free(ml); 136 ml = next; 137 } 138 free(ml); 139} 140 141private int 142info_from_stat(struct magic_set *ms, mode_t md) 143{ 144 /* We cannot open it, but we were able to stat it. */ 145 if (md & 0222) 146 if (file_printf(ms, "writable, ") == -1) 147 return -1; 148 if (md & 0111) 149 if (file_printf(ms, "executable, ") == -1) 150 return -1; 151 if (S_ISREG(md)) 152 if (file_printf(ms, "regular file, ") == -1) 153 return -1; 154 if (file_printf(ms, "no read permission") == -1) 155 return -1; 156 return 0; 157} 158 159public void 160magic_close(struct magic_set *ms) 161{ 162 free_mlist(ms->mlist); 163 free(ms->o.pbuf); 164 free(ms->o.buf); 165 free(ms->c.off); 166 free(ms); 167} 168 169/* 170 * load a magic file 171 */ 172public int 173magic_load(struct magic_set *ms, const char *magicfile) 174{ 175 struct mlist *ml = file_apprentice(ms, magicfile, FILE_LOAD); 176 if (ml) { 177 free_mlist(ms->mlist); 178 ms->mlist = ml; 179 return 0; 180 } 181 return -1; 182} 183 184public int 185magic_compile(struct magic_set *ms, const char *magicfile) 186{ 187 struct mlist *ml = file_apprentice(ms, magicfile, FILE_COMPILE); 188 free_mlist(ml); 189 return ml ? 0 : -1; 190} 191 192public int 193magic_check(struct magic_set *ms, const char *magicfile) 194{ 195 struct mlist *ml = file_apprentice(ms, magicfile, FILE_CHECK); 196 free_mlist(ml); 197 return ml ? 0 : -1; 198} 199 200private void 201close_and_restore(const struct magic_set *ms, const char *name, int fd, 202 const struct stat *sb) 203{ 204 if (fd == STDIN_FILENO) 205 return; 206 (void) close(fd); 207 208 if ((ms->flags & MAGIC_PRESERVE_ATIME) != 0) { 209 /* 210 * Try to restore access, modification times if read it. 211 * This is really *bad* because it will modify the status 212 * time of the file... And of course this will affect 213 * backup programs 214 */ 215#ifdef HAVE_UTIMES 216 struct timeval utsbuf[2]; 217 utsbuf[0].tv_sec = sb->st_atime; 218 utsbuf[1].tv_sec = sb->st_mtime; 219 220 (void) utimes(name, utsbuf); /* don't care if loses */ 221#elif defined(HAVE_UTIME_H) || defined(HAVE_SYS_UTIME_H) 222 struct utimbuf utbuf; 223 224 utbuf.actime = sb->st_atime; 225 utbuf.modtime = sb->st_mtime; 226 (void) utime(name, &utbuf); /* don't care if loses */ 227#endif 228 } 229} 230 231#ifndef COMPILE_ONLY 232/* 233 * find type of named file 234 */ 235public const char * 236magic_file(struct magic_set *ms, const char *inname) 237{ 238 int fd = 0; 239 int rv = -1; 240 unsigned char *buf; 241 struct stat sb; 242 ssize_t nbytes = 0; /* number of bytes read from a datafile */ 243 int ispipe = 0; 244 245 /* 246 * one extra for terminating '\0', and 247 * some overlapping space for matches near EOF 248 */ 249#define SLOP (1 + sizeof(union VALUETYPE)) 250 if ((buf = malloc(HOWMANY + SLOP)) == NULL) 251 return NULL; 252 253 if (file_reset(ms) == -1) 254 goto done; 255 256 switch (file_fsmagic(ms, inname, &sb)) { 257 case -1: /* error */ 258 goto done; 259 case 0: /* nothing found */ 260 break; 261 default: /* matched it and printed type */ 262 rv = 0; 263 goto done; 264 } 265 266 if (inname == NULL) { 267 fd = STDIN_FILENO; 268 if (fstat(fd, &sb) == 0 && S_ISFIFO(sb.st_mode)) 269 ispipe = 1; 270 } else { 271 int flags = O_RDONLY|O_BINARY; 272 273 if (stat(inname, &sb) == 0 && S_ISFIFO(sb.st_mode)) { 274 flags |= O_NONBLOCK; 275 ispipe = 1; 276 } 277 278 errno = 0; 279 if ((fd = open(inname, flags)) < 0) { 280#ifdef __CYGWIN__ 281 char *tmp = alloca(strlen(inname) + 5); 282 (void)strcat(strcpy(tmp, inname), ".exe"); 283 if ((fd = open(tmp, flags)) < 0) { 284#endif 285 if (info_from_stat(ms, sb.st_mode) == -1) 286 goto done; 287 rv = 0; 288 goto done; 289#ifdef __CYGWIN__ 290 } 291#endif 292 } 293#ifdef O_NONBLOCK 294 if ((flags = fcntl(fd, F_GETFL)) != -1) { 295 flags &= ~O_NONBLOCK; 296 (void)fcntl(fd, F_SETFL, flags); 297 } 298#endif 299 } 300 301 /* 302 * try looking at the first HOWMANY bytes 303 */ 304 if (ispipe) { 305 ssize_t r = 0; 306 307 while ((r = sread(fd, (void *)&buf[nbytes], 308 (size_t)(HOWMANY - nbytes))) > 0) { 309 nbytes += r; 310 if (r < PIPE_BUF) break; 311 } 312 313 if (nbytes == 0) { 314 /* We can not read it, but we were able to stat it. */ 315 if (info_from_stat(ms, sb.st_mode) == -1) 316 goto done; 317 rv = 0; 318 goto done; 319 } 320 321 } else { 322 if ((nbytes = read(fd, (char *)buf, HOWMANY)) == -1) { 323 file_error(ms, errno, "cannot read `%s'", inname); 324 goto done; 325 } 326 } 327 328 if (nbytes == 0) { 329 if (file_printf(ms, (ms->flags & MAGIC_MIME) ? 330 "application/x-empty" : "empty") == -1) 331 goto done; 332 } else if (nbytes == 1) { 333 if (file_printf(ms, "very short file (no magic)") == -1) 334 goto done; 335 } else { 336 (void)memset(buf + nbytes, 0, SLOP); /* NUL terminate */ 337#ifdef __EMX__ 338 switch (file_os2_apptype(ms, inname, buf, nbytes)) { 339 case -1: 340 goto done; 341 case 0: 342 break; 343 default: 344 rv = 0; 345 goto done; 346 } 347#endif 348 if (file_buffer(ms, fd, buf, (size_t)nbytes) == -1) 349 goto done; 350#ifdef BUILTIN_ELF 351 if (nbytes > 5) { 352 /* 353 * We matched something in the file, so this *might* 354 * be an ELF file, and the file is at least 5 bytes 355 * long, so if it's an ELF file it has at least one 356 * byte past the ELF magic number - try extracting 357 * information from the ELF headers that cannot easily 358 * be extracted with rules in the magic file. 359 */ 360 file_tryelf(ms, fd, buf, (size_t)nbytes); 361 } 362#endif 363 } 364 rv = 0; 365done: 366 free(buf); 367 close_and_restore(ms, inname, fd, &sb); 368 return rv == 0 ? file_getbuffer(ms) : NULL; 369} 370 371 372public const char * 373magic_buffer(struct magic_set *ms, const void *buf, size_t nb) 374{ 375 if (file_reset(ms) == -1) 376 return NULL; 377 /* 378 * The main work is done here! 379 * We have the file name and/or the data buffer to be identified. 380 */ 381 if (file_buffer(ms, -1, buf, nb) == -1) { 382 return NULL; 383 } 384 return file_getbuffer(ms); 385} 386#endif 387 388public const char * 389magic_error(struct magic_set *ms) 390{ 391 return ms->haderr ? ms->o.buf : NULL; 392} 393 394public int 395magic_errno(struct magic_set *ms) 396{ 397 return ms->haderr ? ms->error : 0; 398} 399 400public int 401magic_setflags(struct magic_set *ms, int flags) 402{ 403#if !defined(HAVE_UTIME) && !defined(HAVE_UTIMES) 404 if (flags & MAGIC_PRESERVE_ATIME) 405 return -1; 406#endif 407 ms->flags = flags; 408 return 0; 409} 410