Annotation of src/usr.bin/file/magic.c, Revision 1.9
1.9 ! doug 1: /* $OpenBSD: magic.c,v 1.8 2009/10/27 23:59:37 deraadt Exp $ */
1.1 tedu 2: /*
3: * Copyright (c) Christos Zoulas 2003.
4: * All Rights Reserved.
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:
1.7 deraadt 29: #include <sys/types.h>
30: #include <sys/param.h> /* for MAXPATHLEN */
31: #include <sys/stat.h>
32:
1.1 tedu 33: #include "file.h"
34: #include "magic.h"
35:
36: #include <stdio.h>
37: #include <stdlib.h>
38: #include <unistd.h>
39: #include <string.h>
40: #ifdef QUICK
41: #include <sys/mman.h>
42: #endif
1.5 chl 43: #include <limits.h> /* for PIPE_BUF */
1.1 tedu 44:
1.5 chl 45: #if defined(HAVE_UTIMES)
46: # include <sys/time.h>
47: #elif defined(HAVE_UTIME)
1.1 tedu 48: # if defined(HAVE_SYS_UTIME_H)
49: # include <sys/utime.h>
50: # elif defined(HAVE_UTIME_H)
51: # include <utime.h>
52: # endif
53: #endif
54:
55: #ifdef HAVE_UNISTD_H
56: #include <unistd.h> /* for read() */
57: #endif
58:
59: #ifdef HAVE_LOCALE_H
60: #include <locale.h>
61: #endif
62:
63: #include <netinet/in.h> /* for byte swapping */
64:
65: #include "patchlevel.h"
66:
1.6 chl 67: #ifndef PIPE_BUF
68: /* Get the PIPE_BUF from pathconf */
69: #ifdef _PC_PIPE_BUF
70: #define PIPE_BUF pathconf(".", _PC_PIPE_BUF)
71: #else
72: #define PIPE_BUF 512
73: #endif
74: #endif
75:
1.1 tedu 76: #ifdef __EMX__
77: private char *apptypeName = NULL;
78: protected int file_os2_apptype(struct magic_set *ms, const char *fn,
79: const void *buf, size_t nb);
80: #endif /* __EMX__ */
81:
82: private void free_mlist(struct mlist *);
83: private void close_and_restore(const struct magic_set *, const char *, int,
84: const struct stat *);
1.5 chl 85: private int info_from_stat(struct magic_set *, mode_t);
1.6 chl 86: #ifndef COMPILE_ONLY
87: private const char *file_or_fd(struct magic_set *, const char *, int);
88: #endif
1.5 chl 89:
90: #ifndef STDIN_FILENO
91: #define STDIN_FILENO 0
92: #endif
1.1 tedu 93:
94: public struct magic_set *
95: magic_open(int flags)
96: {
97: struct magic_set *ms;
98:
1.5 chl 99: if ((ms = calloc((size_t)1, sizeof(struct magic_set))) == NULL)
1.1 tedu 100: return NULL;
101:
102: if (magic_setflags(ms, flags) == -1) {
103: errno = EINVAL;
1.6 chl 104: goto free;
1.1 tedu 105: }
106:
1.6 chl 107: ms->o.buf = ms->o.pbuf = NULL;
1.5 chl 108:
1.9 ! doug 109: ms->c.len = 10;
! 110: ms->c.li = reallocarray(NULL, ms->c.len, sizeof(*ms->c.li));
1.5 chl 111: if (ms->c.li == NULL)
1.6 chl 112: goto free;
1.5 chl 113:
1.1 tedu 114: ms->haderr = 0;
115: ms->error = -1;
116: ms->mlist = NULL;
1.5 chl 117: ms->file = "unknown";
118: ms->line = 0;
1.1 tedu 119: return ms;
1.6 chl 120: free:
1.5 chl 121: free(ms);
122: return NULL;
1.1 tedu 123: }
124:
125: private void
126: free_mlist(struct mlist *mlist)
127: {
128: struct mlist *ml;
129:
130: if (mlist == NULL)
131: return;
132:
133: for (ml = mlist->next; ml != mlist;) {
134: struct mlist *next = ml->next;
135: struct magic *mg = ml->magic;
136: file_delmagic(mg, ml->mapped, ml->nmagic);
137: free(ml);
138: ml = next;
139: }
140: free(ml);
141: }
142:
1.5 chl 143: private int
144: info_from_stat(struct magic_set *ms, mode_t md)
145: {
146: /* We cannot open it, but we were able to stat it. */
147: if (md & 0222)
148: if (file_printf(ms, "writable, ") == -1)
149: return -1;
150: if (md & 0111)
151: if (file_printf(ms, "executable, ") == -1)
152: return -1;
153: if (S_ISREG(md))
154: if (file_printf(ms, "regular file, ") == -1)
155: return -1;
156: if (file_printf(ms, "no read permission") == -1)
157: return -1;
158: return 0;
159: }
160:
1.1 tedu 161: public void
1.5 chl 162: magic_close(struct magic_set *ms)
1.1 tedu 163: {
164: free_mlist(ms->mlist);
1.5 chl 165: free(ms->o.pbuf);
1.1 tedu 166: free(ms->o.buf);
1.5 chl 167: free(ms->c.li);
1.1 tedu 168: free(ms);
169: }
170:
171: /*
172: * load a magic file
173: */
174: public int
175: magic_load(struct magic_set *ms, const char *magicfile)
176: {
177: struct mlist *ml = file_apprentice(ms, magicfile, FILE_LOAD);
178: if (ml) {
179: free_mlist(ms->mlist);
180: ms->mlist = ml;
181: return 0;
182: }
183: return -1;
184: }
185:
186: public int
187: magic_compile(struct magic_set *ms, const char *magicfile)
188: {
189: struct mlist *ml = file_apprentice(ms, magicfile, FILE_COMPILE);
190: free_mlist(ml);
191: return ml ? 0 : -1;
192: }
193:
194: public int
195: magic_check(struct magic_set *ms, const char *magicfile)
196: {
197: struct mlist *ml = file_apprentice(ms, magicfile, FILE_CHECK);
198: free_mlist(ml);
199: return ml ? 0 : -1;
200: }
201:
202: private void
203: close_and_restore(const struct magic_set *ms, const char *name, int fd,
204: const struct stat *sb)
205: {
1.5 chl 206: if (fd == STDIN_FILENO)
207: return;
1.1 tedu 208: (void) close(fd);
1.5 chl 209:
210: if ((ms->flags & MAGIC_PRESERVE_ATIME) != 0) {
1.1 tedu 211: /*
212: * Try to restore access, modification times if read it.
213: * This is really *bad* because it will modify the status
214: * time of the file... And of course this will affect
215: * backup programs
216: */
217: #ifdef HAVE_UTIMES
218: struct timeval utsbuf[2];
1.6 chl 219: (void)memset(utsbuf, 0, sizeof(utsbuf));
1.1 tedu 220: utsbuf[0].tv_sec = sb->st_atime;
221: utsbuf[1].tv_sec = sb->st_mtime;
222:
223: (void) utimes(name, utsbuf); /* don't care if loses */
224: #elif defined(HAVE_UTIME_H) || defined(HAVE_SYS_UTIME_H)
225: struct utimbuf utbuf;
226:
1.6 chl 227: (void)memset(utbuf, 0, sizeof(utbuf));
1.1 tedu 228: utbuf.actime = sb->st_atime;
229: utbuf.modtime = sb->st_mtime;
230: (void) utime(name, &utbuf); /* don't care if loses */
231: #endif
232: }
233: }
234:
1.5 chl 235: #ifndef COMPILE_ONLY
1.6 chl 236:
237: /*
238: * find type of descriptor
239: */
240: public const char *
241: magic_descriptor(struct magic_set *ms, int fd)
242: {
243: return file_or_fd(ms, NULL, fd);
244: }
245:
1.1 tedu 246: /*
247: * find type of named file
248: */
249: public const char *
250: magic_file(struct magic_set *ms, const char *inname)
251: {
1.6 chl 252: return file_or_fd(ms, inname, STDIN_FILENO);
253: }
254:
255: private const char *
256: file_or_fd(struct magic_set *ms, const char *inname, int fd)
257: {
1.5 chl 258: int rv = -1;
259: unsigned char *buf;
1.1 tedu 260: struct stat sb;
261: ssize_t nbytes = 0; /* number of bytes read from a datafile */
1.5 chl 262: int ispipe = 0;
263:
264: /*
265: * one extra for terminating '\0', and
266: * some overlapping space for matches near EOF
267: */
268: #define SLOP (1 + sizeof(union VALUETYPE))
269: if ((buf = malloc(HOWMANY + SLOP)) == NULL)
270: return NULL;
1.1 tedu 271:
272: if (file_reset(ms) == -1)
1.5 chl 273: goto done;
1.1 tedu 274:
275: switch (file_fsmagic(ms, inname, &sb)) {
1.5 chl 276: case -1: /* error */
277: goto done;
278: case 0: /* nothing found */
1.1 tedu 279: break;
1.5 chl 280: default: /* matched it and printed type */
281: rv = 0;
282: goto done;
1.1 tedu 283: }
284:
1.5 chl 285: if (inname == NULL) {
286: if (fstat(fd, &sb) == 0 && S_ISFIFO(sb.st_mode))
287: ispipe = 1;
288: } else {
289: int flags = O_RDONLY|O_BINARY;
290:
291: if (stat(inname, &sb) == 0 && S_ISFIFO(sb.st_mode)) {
292: flags |= O_NONBLOCK;
293: ispipe = 1;
294: }
295:
296: errno = 0;
297: if ((fd = open(inname, flags)) < 0) {
298: #ifdef __CYGWIN__
1.6 chl 299: /* FIXME: Do this with EXEEXT from autotools */
300: char *tmp = alloca(strlen(inname) + 5);
301: (void)strcat(strcpy(tmp, inname), ".exe");
302: if ((fd = open(tmp, flags)) < 0) {
1.5 chl 303: #endif
1.6 chl 304: fprintf(stderr, "couldn't open file\n");
305: if (info_from_stat(ms, sb.st_mode) == -1)
306: goto done;
307: rv = 0;
308: goto done;
1.5 chl 309: #ifdef __CYGWIN__
1.6 chl 310: }
1.5 chl 311: #endif
312: }
313: #ifdef O_NONBLOCK
314: if ((flags = fcntl(fd, F_GETFL)) != -1) {
315: flags &= ~O_NONBLOCK;
316: (void)fcntl(fd, F_SETFL, flags);
317: }
1.1 tedu 318: #endif
319: }
320:
321: /*
322: * try looking at the first HOWMANY bytes
323: */
1.5 chl 324: if (ispipe) {
325: ssize_t r = 0;
326:
327: while ((r = sread(fd, (void *)&buf[nbytes],
328: (size_t)(HOWMANY - nbytes), 1)) > 0) {
329: nbytes += r;
330: if (r < PIPE_BUF) break;
331: }
332:
333: if (nbytes == 0) {
334: /* We can not read it, but we were able to stat it. */
335: if (info_from_stat(ms, sb.st_mode) == -1)
336: goto done;
337: rv = 0;
338: goto done;
339: }
340:
341: } else {
342: if ((nbytes = read(fd, (char *)buf, HOWMANY)) == -1) {
343: file_error(ms, errno, "cannot read `%s'", inname);
344: goto done;
345: }
1.1 tedu 346: }
347:
1.6 chl 348: (void)memset(buf + nbytes, 0, SLOP); /* NUL terminate */
349: if (file_buffer(ms, fd, inname, buf, (size_t)nbytes) == -1)
350: goto done;
1.5 chl 351: rv = 0;
1.1 tedu 352: done:
1.5 chl 353: free(buf);
1.1 tedu 354: close_and_restore(ms, inname, fd, &sb);
1.5 chl 355: return rv == 0 ? file_getbuffer(ms) : NULL;
1.1 tedu 356: }
357:
358:
359: public const char *
360: magic_buffer(struct magic_set *ms, const void *buf, size_t nb)
361: {
362: if (file_reset(ms) == -1)
363: return NULL;
364: /*
365: * The main work is done here!
366: * We have the file name and/or the data buffer to be identified.
367: */
1.5 chl 368: if (file_buffer(ms, -1, NULL, buf, nb) == -1) {
1.1 tedu 369: return NULL;
370: }
371: return file_getbuffer(ms);
372: }
1.5 chl 373: #endif
1.1 tedu 374:
375: public const char *
376: magic_error(struct magic_set *ms)
377: {
378: return ms->haderr ? ms->o.buf : NULL;
379: }
380:
381: public int
382: magic_errno(struct magic_set *ms)
383: {
384: return ms->haderr ? ms->error : 0;
385: }
386:
387: public int
388: magic_setflags(struct magic_set *ms, int flags)
389: {
390: #if !defined(HAVE_UTIME) && !defined(HAVE_UTIMES)
391: if (flags & MAGIC_PRESERVE_ATIME)
392: return -1;
393: #endif
394: ms->flags = flags;
395: return 0;
396: }