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

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