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