Annotation of src/usr.bin/file/magic.c, Revision 1.4
1.4 ! deraadt 1: /* $OpenBSD: magic.c,v 1.3 2007/07/09 16:39:48 dim 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: * 3. The name of the author may not be used to endorse or promote products
16: * derived from this software without specific prior written permission.
17: *
18: * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
19: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21: * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
22: * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28: * SUCH DAMAGE.
29: */
30:
31: #include "file.h"
32: #include "magic.h"
33:
34: #include <stdio.h>
35: #include <stdlib.h>
36: #include <unistd.h>
37: #include <string.h>
38: #include <sys/types.h>
39: #include <sys/param.h> /* for MAXPATHLEN */
40: #include <sys/stat.h>
41: #include <fcntl.h> /* for open() */
42: #ifdef QUICK
43: #include <sys/mman.h>
44: #endif
45:
46: #if defined(HAVE_UTIME)
47: # if defined(HAVE_SYS_UTIME_H)
48: # include <sys/utime.h>
49: # elif defined(HAVE_UTIME_H)
50: # include <utime.h>
51: # endif
52: #elif defined(HAVE_UTIMES)
53: # include <sys/time.h>
54: #endif
55:
56: #ifdef HAVE_UNISTD_H
57: #include <unistd.h> /* for read() */
58: #endif
59:
60: #ifdef HAVE_LOCALE_H
61: #include <locale.h>
62: #endif
63:
64: #include <netinet/in.h> /* for byte swapping */
65:
66: #include "patchlevel.h"
67:
68: #ifndef lint
1.4 ! deraadt 69: FILE_RCSID("@(#)$Id: magic.c,v 1.3 2007/07/09 16:39:48 dim Exp $")
1.1 tedu 70: #endif /* lint */
71:
72: #ifdef __EMX__
73: private char *apptypeName = NULL;
74: protected int file_os2_apptype(struct magic_set *ms, const char *fn,
75: const void *buf, size_t nb);
76: #endif /* __EMX__ */
77:
78: private void free_mlist(struct mlist *);
79: private void close_and_restore(const struct magic_set *, const char *, int,
80: const struct stat *);
81:
82: public struct magic_set *
83: magic_open(int flags)
84: {
85: struct magic_set *ms;
86:
87: if ((ms = malloc(sizeof(struct magic_set))) == NULL)
88: return NULL;
89:
90: if (magic_setflags(ms, flags) == -1) {
91: free(ms);
92: errno = EINVAL;
93: return NULL;
94: }
95:
1.3 dim 96: ms->o.ptr = ms->o.buf = malloc(ms->o.left = ms->o.size = 1024);
1.1 tedu 97: if (ms->o.buf == NULL) {
98: free(ms);
99: return NULL;
100: }
101: ms->o.pbuf = malloc(ms->o.psize = 1024);
102: if (ms->o.pbuf == NULL) {
103: free(ms->o.buf);
104: free(ms);
105: return NULL;
106: }
1.4 ! deraadt 107: ms->c.len = 10;
! 108: ms->c.off = calloc(ms->c.len, sizeof(*ms->c.off));
1.1 tedu 109: if (ms->c.off == NULL) {
110: free(ms->o.pbuf);
111: free(ms->o.buf);
112: free(ms);
113: return NULL;
114: }
115: ms->haderr = 0;
116: ms->error = -1;
117: ms->mlist = NULL;
118: return ms;
119: }
120:
121: private void
122: free_mlist(struct mlist *mlist)
123: {
124: struct mlist *ml;
125:
126: if (mlist == NULL)
127: return;
128:
129: for (ml = mlist->next; ml != mlist;) {
130: struct mlist *next = ml->next;
131: struct magic *mg = ml->magic;
132: file_delmagic(mg, ml->mapped, ml->nmagic);
133: free(ml);
134: ml = next;
135: }
136: free(ml);
137: }
138:
139: public void
140: magic_close(ms)
141: struct magic_set *ms;
142: {
143: free_mlist(ms->mlist);
144: free(ms->o.buf);
145: free(ms->c.off);
146: free(ms);
147: }
148:
149: /*
150: * load a magic file
151: */
152: public int
153: magic_load(struct magic_set *ms, const char *magicfile)
154: {
155: struct mlist *ml = file_apprentice(ms, magicfile, FILE_LOAD);
156: if (ml) {
157: free_mlist(ms->mlist);
158: ms->mlist = ml;
159: return 0;
160: }
161: return -1;
162: }
163:
164: public int
165: magic_compile(struct magic_set *ms, const char *magicfile)
166: {
167: struct mlist *ml = file_apprentice(ms, magicfile, FILE_COMPILE);
168: free_mlist(ml);
169: return ml ? 0 : -1;
170: }
171:
172: public int
173: magic_check(struct magic_set *ms, const char *magicfile)
174: {
175: struct mlist *ml = file_apprentice(ms, magicfile, FILE_CHECK);
176: free_mlist(ml);
177: return ml ? 0 : -1;
178: }
179:
180: private void
181: close_and_restore(const struct magic_set *ms, const char *name, int fd,
182: const struct stat *sb)
183: {
184: (void) close(fd);
185: if (fd != STDIN_FILENO && (ms->flags & MAGIC_PRESERVE_ATIME) != 0) {
186: /*
187: * Try to restore access, modification times if read it.
188: * This is really *bad* because it will modify the status
189: * time of the file... And of course this will affect
190: * backup programs
191: */
192: #ifdef HAVE_UTIMES
193: struct timeval utsbuf[2];
194: utsbuf[0].tv_sec = sb->st_atime;
195: utsbuf[1].tv_sec = sb->st_mtime;
196:
197: (void) utimes(name, utsbuf); /* don't care if loses */
198: #elif defined(HAVE_UTIME_H) || defined(HAVE_SYS_UTIME_H)
199: struct utimbuf utbuf;
200:
201: utbuf.actime = sb->st_atime;
202: utbuf.modtime = sb->st_mtime;
203: (void) utime(name, &utbuf); /* don't care if loses */
204: #endif
205: }
206: }
207:
208: /*
209: * find type of named file
210: */
211: public const char *
212: magic_file(struct magic_set *ms, const char *inname)
213: {
214: int fd = 0;
215: unsigned char buf[HOWMANY+1]; /* one extra for terminating '\0' */
216: struct stat sb;
217: ssize_t nbytes = 0; /* number of bytes read from a datafile */
218:
219: if (file_reset(ms) == -1)
220: return NULL;
221:
222: switch (file_fsmagic(ms, inname, &sb)) {
223: case -1:
224: return NULL;
225: case 0:
226: break;
227: default:
228: return file_getbuffer(ms);
229: }
230:
231: #ifndef STDIN_FILENO
232: #define STDIN_FILENO 0
233: #endif
234: if (inname == NULL)
235: fd = STDIN_FILENO;
236: else if ((fd = open(inname, O_RDONLY)) < 0) {
237: /* We cannot open it, but we were able to stat it. */
238: if (sb.st_mode & 0222)
239: if (file_printf(ms, "writable, ") == -1)
240: return NULL;
241: if (sb.st_mode & 0111)
242: if (file_printf(ms, "executable, ") == -1)
243: return NULL;
244: if (S_ISREG(sb.st_mode))
245: if (file_printf(ms, "regular file, ") == -1)
246: return NULL;
247: if (file_printf(ms, "no read permission") == -1)
248: return NULL;
249: return file_getbuffer(ms);
250: }
251:
252: /*
253: * try looking at the first HOWMANY bytes
254: */
255: if ((nbytes = read(fd, (char *)buf, HOWMANY)) == -1) {
256: file_error(ms, errno, "cannot read `%s'", inname);
257: goto done;
258: }
259:
260: if (nbytes == 0) {
261: if (file_printf(ms, (ms->flags & MAGIC_MIME) ?
262: "application/x-empty" : "empty") == -1)
263: goto done;
264: goto gotit;
265: } else if (nbytes == 1) {
266: if (file_printf(ms, "very short file (no magic)") == -1)
267: goto done;
268: goto gotit;
269: } else {
270: buf[nbytes] = '\0'; /* null-terminate it */
271: #ifdef __EMX__
272: switch (file_os2_apptype(ms, inname, buf, nbytes)) {
273: case -1:
274: goto done;
275: case 0:
276: break;
277: default:
278: goto gotit;
279: }
280: #endif
281: if (file_buffer(ms, buf, (size_t)nbytes) == -1)
282: goto done;
283: #ifdef BUILTIN_ELF
284: if (nbytes > 5) {
285: /*
286: * We matched something in the file, so this *might*
287: * be an ELF file, and the file is at least 5 bytes
288: * long, so if it's an ELF file it has at least one
289: * byte past the ELF magic number - try extracting
290: * information from the ELF headers that cannot easily
291: * be extracted with rules in the magic file.
292: */
293: file_tryelf(ms, fd, buf, (size_t)nbytes);
294: }
295: #endif
296: }
297: gotit:
298: close_and_restore(ms, inname, fd, &sb);
299: return file_getbuffer(ms);
300: done:
301: close_and_restore(ms, inname, fd, &sb);
302: return NULL;
303: }
304:
305:
306: public const char *
307: magic_buffer(struct magic_set *ms, const void *buf, size_t nb)
308: {
309: if (file_reset(ms) == -1)
310: return NULL;
311: /*
312: * The main work is done here!
313: * We have the file name and/or the data buffer to be identified.
314: */
315: if (file_buffer(ms, buf, nb) == -1) {
316: return NULL;
317: }
318: return file_getbuffer(ms);
319: }
320:
321: public const char *
322: magic_error(struct magic_set *ms)
323: {
324: return ms->haderr ? ms->o.buf : NULL;
325: }
326:
327: public int
328: magic_errno(struct magic_set *ms)
329: {
330: return ms->haderr ? ms->error : 0;
331: }
332:
333: public int
334: magic_setflags(struct magic_set *ms, int flags)
335: {
336: #if !defined(HAVE_UTIME) && !defined(HAVE_UTIMES)
337: if (flags & MAGIC_PRESERVE_ATIME)
338: return -1;
339: #endif
340: ms->flags = flags;
341: return 0;
342: }