[BACK]Return to funcs.c CVS log [TXT][DIR] Up to [local] / src / usr.bin / file

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: }