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