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