Annotation of src/usr.bin/file/funcs.c, Revision 1.7
1.7 ! deraadt 1: /* $OpenBSD: funcs.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: #include "file.h"
29: #include "magic.h"
30: #include <stdarg.h>
31: #include <stdlib.h>
32: #include <string.h>
33: #include <ctype.h>
1.5 chl 34: #if defined(HAVE_WCHAR_H)
35: #include <wchar.h>
36: #endif
37: #if defined(HAVE_WCTYPE_H)
38: #include <wctype.h>
39: #endif
40:
1.1 tedu 41: /*
1.6 chl 42: * Like printf, only we append to a buffer.
1.1 tedu 43: */
44: protected int
45: file_printf(struct magic_set *ms, const char *fmt, ...)
46: {
47: va_list ap;
1.6 chl 48: int len;
49: char *buf, *newstr;
1.1 tedu 50:
51: va_start(ap, fmt);
1.6 chl 52: len = vasprintf(&buf, fmt, ap);
53: if (len < 0)
54: goto out;
55: va_end(ap);
1.1 tedu 56:
1.6 chl 57: if (ms->o.buf != NULL) {
58: len = asprintf(&newstr, "%s%s", ms->o.buf, buf);
59: free(buf);
60: if (len < 0)
61: goto out;
62: free(ms->o.buf);
63: buf = newstr;
1.1 tedu 64: }
1.6 chl 65: ms->o.buf = buf;
1.1 tedu 66: return 0;
1.6 chl 67: out:
68: file_error(ms, errno, "vasprintf failed");
69: return -1;
1.1 tedu 70: }
71:
72: /*
73: * error - print best error message possible
74: */
75: /*VARARGS*/
1.5 chl 76: private void
77: file_error_core(struct magic_set *ms, int error, const char *f, va_list va,
78: uint32_t lineno)
1.1 tedu 79: {
80: /* Only the first error is ok */
81: if (ms->haderr)
82: return;
1.5 chl 83: if (lineno != 0) {
1.6 chl 84: free(ms->o.buf);
85: ms->o.buf = NULL;
86: file_printf(ms, "line %u: ", lineno);
87: }
88: file_printf(ms, f, va);
89: if (error > 0)
90: file_printf(ms, " (%s)", strerror(error));
1.1 tedu 91: ms->haderr++;
92: ms->error = error;
93: }
94:
1.5 chl 95: /*VARARGS*/
96: protected void
97: file_error(struct magic_set *ms, int error, const char *f, ...)
98: {
99: va_list va;
100: va_start(va, f);
101: file_error_core(ms, error, f, va, 0);
102: va_end(va);
103: }
104:
105: /*
106: * Print an error with magic line number.
107: */
108: /*VARARGS*/
109: protected void
110: file_magerror(struct magic_set *ms, const char *f, ...)
111: {
112: va_list va;
113: va_start(va, f);
114: file_error_core(ms, 0, f, va, ms->line);
115: va_end(va);
116: }
1.1 tedu 117:
118: protected void
1.5 chl 119: file_oomem(struct magic_set *ms, size_t len)
1.1 tedu 120: {
1.5 chl 121: file_error(ms, errno, "cannot allocate %zu bytes", len);
1.1 tedu 122: }
123:
124: protected void
125: file_badseek(struct magic_set *ms)
126: {
127: file_error(ms, errno, "error seeking");
128: }
129:
130: protected void
131: file_badread(struct magic_set *ms)
132: {
133: file_error(ms, errno, "error reading");
134: }
135:
1.5 chl 136: #ifndef COMPILE_ONLY
1.1 tedu 137: protected int
1.5 chl 138: file_buffer(struct magic_set *ms, int fd, const char *inname, const void *buf,
139: size_t nb)
1.1 tedu 140: {
1.6 chl 141: int m;
142: int mime = ms->flags & MAGIC_MIME;
143:
144: if (nb == 0) {
145: if ((!mime || (mime & MAGIC_MIME_TYPE)) &&
146: file_printf(ms, mime ? "application/x-empty" :
147: "empty") == -1)
148: return -1;
149: return 1;
150: } else if (nb == 1) {
151: if ((!mime || (mime & MAGIC_MIME_TYPE)) &&
152: file_printf(ms, mime ? "application/octet-stream" :
153: "very short file (no magic)") == -1)
154: return -1;
155: return 1;
156: }
1.5 chl 157:
158: #ifdef __EMX__
1.6 chl 159: if ((ms->flags & MAGIC_NO_CHECK_APPTYPE) == 0 && inname) {
160: switch (file_os2_apptype(ms, inname, buf, nb)) {
161: case -1:
162: return -1;
163: case 0:
164: break;
165: default:
166: return 1;
167: }
1.5 chl 168: }
169: #endif
170:
1.6 chl 171: /* try compression stuff */
172: if ((ms->flags & MAGIC_NO_CHECK_COMPRESS) != 0 ||
173: (m = file_zmagic(ms, fd, inname, buf, nb)) == 0) {
174: /* Check if we have a tar file */
175: if ((ms->flags & MAGIC_NO_CHECK_TAR) != 0 ||
176: (m = file_is_tar(ms, buf, nb)) == 0) {
177: /* try tests in /etc/magic (or surrogate magic file) */
178: if ((ms->flags & MAGIC_NO_CHECK_SOFT) != 0 ||
179: (m = file_softmagic(ms, buf, nb, BINTEST)) == 0) {
180: /* try known keywords, check whether it is ASCII */
181: if ((ms->flags & MAGIC_NO_CHECK_ASCII) != 0 ||
182: (m = file_ascmagic(ms, buf, nb)) == 0) {
183: /* abandon hope, all ye who remain here */
184: if ((!mime || (mime & MAGIC_MIME_TYPE)) &&
185: file_printf(ms, mime ? "application/octet-stream" :
186: "data") == -1)
187: return -1;
188: m = 1;
189: }
1.1 tedu 190: }
191: }
192: }
1.5 chl 193: #ifdef BUILTIN_ELF
1.6 chl 194: if ((ms->flags & MAGIC_NO_CHECK_ELF) == 0 && m == 1 &&
195: nb > 5 && fd != -1) {
196: /*
197: * We matched something in the file, so this *might*
198: * be an ELF file, and the file is at least 5 bytes
199: * long, so if it's an ELF file it has at least one
200: * byte past the ELF magic number - try extracting
201: * information from the ELF headers that cannot easily
202: * be extracted with rules in the magic file.
203: */
204: (void)file_tryelf(ms, fd, buf, nb);
205: }
1.5 chl 206: #endif
1.6 chl 207: return m;
1.1 tedu 208: }
1.5 chl 209: #endif
1.1 tedu 210:
211: protected int
212: file_reset(struct magic_set *ms)
213: {
214: if (ms->mlist == NULL) {
215: file_error(ms, 0, "no magic files loaded");
216: return -1;
217: }
1.6 chl 218: ms->o.buf = NULL;
1.1 tedu 219: ms->haderr = 0;
220: ms->error = -1;
221: return 0;
222: }
223:
1.5 chl 224: #define OCTALIFY(n, o) \
225: /*LINTED*/ \
226: (void)(*(n)++ = '\\', \
227: *(n)++ = (((uint32_t)*(o) >> 6) & 3) + '0', \
228: *(n)++ = (((uint32_t)*(o) >> 3) & 7) + '0', \
229: *(n)++ = (((uint32_t)*(o) >> 0) & 7) + '0', \
230: (o)++)
231:
1.1 tedu 232: protected const char *
233: file_getbuffer(struct magic_set *ms)
234: {
1.4 dim 235: char *pbuf, *op, *np;
236: size_t psize, len;
1.1 tedu 237:
238: if (ms->haderr)
239: return NULL;
240:
241: if (ms->flags & MAGIC_RAW)
242: return ms->o.buf;
243:
1.5 chl 244: /* * 4 is for octal representation, + 1 is for NUL */
1.6 chl 245: len = strlen(ms->o.buf);
246: if (len > (SIZE_MAX - 1) / 4) {
1.5 chl 247: file_oomem(ms, len);
1.4 dim 248: return NULL;
249: }
250: psize = len * 4 + 1;
1.6 chl 251: if ((pbuf = realloc(ms->o.pbuf, psize)) == NULL) {
252: file_oomem(ms, psize);
253: return NULL;
1.1 tedu 254: }
1.6 chl 255: ms->o.pbuf = pbuf;
1.1 tedu 256:
1.5 chl 257: #if defined(HAVE_WCHAR_H) && defined(HAVE_MBRTOWC) && defined(HAVE_WCWIDTH)
258: {
259: mbstate_t state;
260: wchar_t nextchar;
261: int mb_conv = 1;
262: size_t bytesconsumed;
263: char *eop;
264: (void)memset(&state, 0, sizeof(mbstate_t));
265:
266: np = ms->o.pbuf;
267: op = ms->o.buf;
1.6 chl 268: eop = op + len;
1.5 chl 269:
270: while (op < eop) {
271: bytesconsumed = mbrtowc(&nextchar, op,
272: (size_t)(eop - op), &state);
273: if (bytesconsumed == (size_t)(-1) ||
274: bytesconsumed == (size_t)(-2)) {
275: mb_conv = 0;
276: break;
277: }
278:
279: if (iswprint(nextchar)) {
280: (void)memcpy(np, op, bytesconsumed);
281: op += bytesconsumed;
282: np += bytesconsumed;
283: } else {
284: while (bytesconsumed-- > 0)
285: OCTALIFY(np, op);
286: }
287: }
288: *np = '\0';
289:
290: /* Parsing succeeded as a multi-byte sequence */
291: if (mb_conv != 0)
292: return ms->o.pbuf;
293: }
294: #endif
295:
1.1 tedu 296: for (np = ms->o.pbuf, op = ms->o.buf; *op; op++) {
297: if (isprint((unsigned char)*op)) {
298: *np++ = *op;
299: } else {
1.5 chl 300: OCTALIFY(np, op);
1.1 tedu 301: }
302: }
303: *np = '\0';
304: return ms->o.pbuf;
305: }
1.5 chl 306:
307: protected int
308: file_check_mem(struct magic_set *ms, unsigned int level)
309: {
310: size_t len;
311:
312: if (level >= ms->c.len) {
313: len = (ms->c.len += 20) * sizeof(*ms->c.li);
314: ms->c.li = (ms->c.li == NULL) ? malloc(len) :
315: realloc(ms->c.li, len);
316: if (ms->c.li == NULL) {
317: file_oomem(ms, len);
318: return -1;
319: }
320: }
321: ms->c.li[level].got_match = 0;
322: #ifdef ENABLE_CONDITIONALS
323: ms->c.li[level].last_match = 0;
324: ms->c.li[level].last_cond = COND_NONE;
325: #endif /* ENABLE_CONDITIONALS */
326: return 0;
327: }