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

Annotation of src/usr.bin/file/apprentice.c, Revision 1.28

1.28    ! deraadt     1: /*     $OpenBSD: apprentice.c,v 1.27 2009/08/27 16:26:42 deraadt Exp $ */
1.1       deraadt     2: /*
1.16      ian         3:  * Copyright (c) Ian F. Darwin 1986-1995.
                      4:  * Software written by Ian F. Darwin and others;
                      5:  * maintained 1995-present by Christos Zoulas and others.
                      6:  *
                      7:  * Redistribution and use in source and binary forms, with or without
                      8:  * modification, are permitted provided that the following conditions
                      9:  * are met:
                     10:  * 1. Redistributions of source code must retain the above copyright
                     11:  *    notice immediately at the beginning of the file, without modification,
                     12:  *    this list of conditions, and the following disclaimer.
                     13:  * 2. Redistributions in binary form must reproduce the above copyright
                     14:  *    notice, this list of conditions and the following disclaimer in the
                     15:  *    documentation and/or other materials provided with the distribution.
                     16:  *
                     17:  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
                     18:  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
                     19:  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
                     20:  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
                     21:  * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
                     22:  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
                     23:  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
                     24:  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
                     25:  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
                     26:  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
                     27:  * SUCH DAMAGE.
1.1       deraadt    28:  */
1.19      tedu       29: /*
                     30:  * apprentice - make one pass through /etc/magic, learning its secrets.
                     31:  */
1.1       deraadt    32:
1.27      deraadt    33: #include <sys/param.h>
                     34: #include <sys/stat.h>
                     35: #include <sys/types.h>
                     36:
1.19      tedu       37: #include "file.h"
                     38: #include "magic.h"
1.26      chl        39: #include "patchlevel.h"
1.1       deraadt    40: #include <stdlib.h>
1.19      tedu       41: #ifdef HAVE_UNISTD_H
                     42: #include <unistd.h>
                     43: #endif
1.1       deraadt    44: #include <string.h>
1.25      chl        45: #include <assert.h>
1.1       deraadt    46: #include <ctype.h>
1.19      tedu       47: #include <fcntl.h>
                     48: #ifdef QUICK
                     49: #include <sys/mman.h>
                     50: #endif
1.26      chl        51: #include <dirent.h>
1.1       deraadt    52:
                     53: #define        EATAB {while (isascii((unsigned char) *l) && \
                     54:                      isspace((unsigned char) *l))  ++l;}
                     55: #define LOWCASE(l) (isupper((unsigned char) (l)) ? \
                     56:                        tolower((unsigned char) (l)) : (l))
1.19      tedu       57: /*
                     58:  * Work around a bug in headers on Digital Unix.
                     59:  * At least confirmed for: OSF1 V4.0 878
                     60:  */
                     61: #if defined(__osf__) && defined(__DECC)
                     62: #ifdef MAP_FAILED
                     63: #undef MAP_FAILED
                     64: #endif
                     65: #endif
                     66:
                     67: #ifndef MAP_FAILED
                     68: #define MAP_FAILED (void *) -1
                     69: #endif
                     70:
                     71: #ifndef MAP_FILE
                     72: #define MAP_FILE 0
                     73: #endif
                     74:
                     75: #ifndef MAXPATHLEN
                     76: #define MAXPATHLEN     1024
                     77: #endif
                     78:
1.25      chl        79: struct magic_entry {
                     80:        struct magic *mp;
                     81:        uint32_t cont_count;
                     82:        uint32_t max_count;
                     83: };
                     84:
                     85: int file_formats[FILE_NAMES_SIZE];
                     86: const size_t file_nformats = FILE_NAMES_SIZE;
                     87: const char *file_names[FILE_NAMES_SIZE];
                     88: const size_t file_nnames = FILE_NAMES_SIZE;
                     89:
                     90: private int getvalue(struct magic_set *ms, struct magic *, const char **, int);
1.19      tedu       91: private int hextoint(int);
1.25      chl        92: private const char *getstr(struct magic_set *, const char *, char *, int,
                     93:     int *, int);
                     94: private int parse(struct magic_set *, struct magic_entry **, uint32_t *,
                     95:     const char *, size_t, int);
1.26      chl        96: private int parse_mime(struct magic_set *, struct magic_entry **, uint32_t *,
                     97:     const char *);
1.25      chl        98: private void eatsize(const char **);
1.19      tedu       99: private int apprentice_1(struct magic_set *, const char *, int, struct mlist *);
1.25      chl       100: private size_t apprentice_magic_strength(const struct magic *);
                    101: private int apprentice_sort(const void *, const void *);
1.26      chl       102: private int apprentice_load(struct magic_set *, struct magic **, uint32_t *,
1.19      tedu      103:     const char *, int);
                    104: private void byteswap(struct magic *, uint32_t);
                    105: private void bs1(struct magic *);
                    106: private uint16_t swap2(uint16_t);
                    107: private uint32_t swap4(uint32_t);
1.25      chl       108: private uint64_t swap8(uint64_t);
1.26      chl       109: private void mkdbname(const char *, char **, int);
1.19      tedu      110: private int apprentice_map(struct magic_set *, struct magic **, uint32_t *,
                    111:     const char *);
                    112: private int apprentice_compile(struct magic_set *, struct magic **, uint32_t *,
                    113:     const char *);
1.25      chl       114: private int check_format_type(const char *, int);
                    115: private int check_format(struct magic_set *, struct magic *);
1.26      chl       116: private int get_op(char);
1.19      tedu      117:
                    118: private size_t maxmagic = 0;
                    119: private size_t magicsize = sizeof(struct magic);
                    120:
1.26      chl       121: private const char usg_hdr[] = "cont\toffset\ttype\topcode\tmask\tvalue\tdesc";
                    122: private const char mime_marker[] = "!:mime";
                    123: private const size_t mime_marker_len = sizeof(mime_marker) - 1;
1.25      chl       124:
1.19      tedu      125: #ifdef COMPILE_ONLY
                    126:
                    127: int main(int, char *[]);
                    128:
                    129: int
                    130: main(int argc, char *argv[])
                    131: {
                    132:        int ret;
1.25      chl       133:        struct magic_set *ms;
                    134:        char *progname;
1.19      tedu      135:
                    136:        if ((progname = strrchr(argv[0], '/')) != NULL)
                    137:                progname++;
                    138:        else
                    139:                progname = argv[0];
                    140:
                    141:        if (argc != 2) {
1.25      chl       142:                (void)fprintf(stderr, "Usage: %s file\n", progname);
                    143:                return 1;
1.19      tedu      144:        }
                    145:
1.25      chl       146:        if ((ms = magic_open(MAGIC_CHECK)) == NULL) {
                    147:                (void)fprintf(stderr, "%s: %s\n", progname, strerror(errno));
                    148:                return 1;
                    149:        }
                    150:        ret = magic_compile(ms, argv[1]) == -1 ? 1 : 0;
                    151:        if (ret == 1)
                    152:                (void)fprintf(stderr, "%s: %s\n", progname, magic_error(ms));
                    153:        magic_close(ms);
                    154:        return ret;
1.19      tedu      155: }
                    156: #endif /* COMPILE_ONLY */
                    157:
1.25      chl       158: static const struct type_tbl_s {
1.26      chl       159:        const char name[16];
1.25      chl       160:        const size_t len;
                    161:        const int type;
                    162:        const int format;
                    163: } type_tbl[] = {
                    164: # define XX(s)         s, (sizeof(s) - 1)
1.26      chl       165: # define XX_NULL       "", 0
1.25      chl       166:        { XX("byte"),           FILE_BYTE,              FILE_FMT_NUM },
                    167:        { XX("short"),          FILE_SHORT,             FILE_FMT_NUM },
                    168:        { XX("default"),        FILE_DEFAULT,           FILE_FMT_STR },
                    169:        { XX("long"),           FILE_LONG,              FILE_FMT_NUM },
                    170:        { XX("string"),         FILE_STRING,            FILE_FMT_STR },
                    171:        { XX("date"),           FILE_DATE,              FILE_FMT_STR },
                    172:        { XX("beshort"),        FILE_BESHORT,           FILE_FMT_NUM },
                    173:        { XX("belong"),         FILE_BELONG,            FILE_FMT_NUM },
                    174:        { XX("bedate"),         FILE_BEDATE,            FILE_FMT_STR },
                    175:        { XX("leshort"),        FILE_LESHORT,           FILE_FMT_NUM },
                    176:        { XX("lelong"),         FILE_LELONG,            FILE_FMT_NUM },
                    177:        { XX("ledate"),         FILE_LEDATE,            FILE_FMT_STR },
                    178:        { XX("pstring"),        FILE_PSTRING,           FILE_FMT_STR },
                    179:        { XX("ldate"),          FILE_LDATE,             FILE_FMT_STR },
                    180:        { XX("beldate"),        FILE_BELDATE,           FILE_FMT_STR },
                    181:        { XX("leldate"),        FILE_LELDATE,           FILE_FMT_STR },
                    182:        { XX("regex"),          FILE_REGEX,             FILE_FMT_STR },
                    183:        { XX("bestring16"),     FILE_BESTRING16,        FILE_FMT_STR },
                    184:        { XX("lestring16"),     FILE_LESTRING16,        FILE_FMT_STR },
                    185:        { XX("search"),         FILE_SEARCH,            FILE_FMT_STR },
                    186:        { XX("medate"),         FILE_MEDATE,            FILE_FMT_STR },
                    187:        { XX("meldate"),        FILE_MELDATE,           FILE_FMT_STR },
                    188:        { XX("melong"),         FILE_MELONG,            FILE_FMT_NUM },
                    189:        { XX("quad"),           FILE_QUAD,              FILE_FMT_QUAD },
                    190:        { XX("lequad"),         FILE_LEQUAD,            FILE_FMT_QUAD },
                    191:        { XX("bequad"),         FILE_BEQUAD,            FILE_FMT_QUAD },
                    192:        { XX("qdate"),          FILE_QDATE,             FILE_FMT_STR },
                    193:        { XX("leqdate"),        FILE_LEQDATE,           FILE_FMT_STR },
                    194:        { XX("beqdate"),        FILE_BEQDATE,           FILE_FMT_STR },
                    195:        { XX("qldate"),         FILE_QLDATE,            FILE_FMT_STR },
                    196:        { XX("leqldate"),       FILE_LEQLDATE,          FILE_FMT_STR },
                    197:        { XX("beqldate"),       FILE_BEQLDATE,          FILE_FMT_STR },
1.26      chl       198:        { XX("float"),          FILE_FLOAT,             FILE_FMT_FLOAT },
                    199:        { XX("befloat"),        FILE_BEFLOAT,           FILE_FMT_FLOAT },
                    200:        { XX("lefloat"),        FILE_LEFLOAT,           FILE_FMT_FLOAT },
                    201:        { XX("double"),         FILE_DOUBLE,            FILE_FMT_DOUBLE },
                    202:        { XX("bedouble"),       FILE_BEDOUBLE,          FILE_FMT_DOUBLE },
                    203:        { XX("ledouble"),       FILE_LEDOUBLE,          FILE_FMT_DOUBLE },
1.25      chl       204:        { XX_NULL,              FILE_INVALID,           FILE_FMT_NONE },
                    205: # undef XX
                    206: # undef XX_NULL
                    207: };
                    208:
                    209: private int
                    210: get_type(const char *l, const char **t)
                    211: {
                    212:        const struct type_tbl_s *p;
                    213:
1.26      chl       214:        for (p = type_tbl; p->len; p++) {
1.25      chl       215:                if (strncmp(l, p->name, p->len) == 0) {
                    216:                        if (t)
                    217:                                *t = l + p->len;
                    218:                        break;
                    219:                }
                    220:        }
                    221:        return p->type;
                    222: }
                    223:
                    224: private void
                    225: init_file_tables(void)
                    226: {
                    227:        static int done = 0;
                    228:        const struct type_tbl_s *p;
                    229:
                    230:        if (done)
                    231:                return;
                    232:        done++;
                    233:
1.26      chl       234:        for (p = type_tbl; p->len; p++) {
1.25      chl       235:                assert(p->type < FILE_NAMES_SIZE);
                    236:                file_names[p->type] = p->name;
                    237:                file_formats[p->type] = p->format;
                    238:        }
                    239: }
1.19      tedu      240:
                    241: /*
1.26      chl       242:  * Handle one file or directory.
1.19      tedu      243:  */
                    244: private int
                    245: apprentice_1(struct magic_set *ms, const char *fn, int action,
                    246:     struct mlist *mlist)
                    247: {
                    248:        struct magic *magic = NULL;
                    249:        uint32_t nmagic = 0;
                    250:        struct mlist *ml;
                    251:        int rv = -1;
                    252:        int mapped;
                    253:
                    254:        if (magicsize != FILE_MAGICSIZE) {
                    255:                file_error(ms, 0, "magic element size %lu != %lu",
                    256:                    (unsigned long)sizeof(*magic),
                    257:                    (unsigned long)FILE_MAGICSIZE);
                    258:                return -1;
                    259:        }
1.1       deraadt   260:
1.19      tedu      261:        if (action == FILE_COMPILE) {
1.26      chl       262:                rv = apprentice_load(ms, &magic, &nmagic, fn, action);
1.19      tedu      263:                if (rv != 0)
                    264:                        return -1;
                    265:                rv = apprentice_compile(ms, &magic, &nmagic, fn);
                    266:                free(magic);
                    267:                return rv;
                    268:        }
1.25      chl       269:
1.19      tedu      270: #ifndef COMPILE_ONLY
                    271:        if ((rv = apprentice_map(ms, &magic, &nmagic, fn)) == -1) {
                    272:                if (ms->flags & MAGIC_CHECK)
1.25      chl       273:                        file_magwarn(ms, "using regular magic file `%s'", fn);
1.26      chl       274:                rv = apprentice_load(ms, &magic, &nmagic, fn, action);
1.19      tedu      275:                if (rv != 0)
                    276:                        return -1;
                    277:        }
1.1       deraadt   278:
1.19      tedu      279:        mapped = rv;
                    280:
1.26      chl       281:        if (magic == NULL) {
1.19      tedu      282:                file_delmagic(magic, mapped, nmagic);
                    283:                return -1;
                    284:        }
1.1       deraadt   285:
1.19      tedu      286:        if ((ml = malloc(sizeof(*ml))) == NULL) {
                    287:                file_delmagic(magic, mapped, nmagic);
1.25      chl       288:                file_oomem(ms, sizeof(*ml));
1.19      tedu      289:                return -1;
                    290:        }
1.1       deraadt   291:
1.19      tedu      292:        ml->magic = magic;
                    293:        ml->nmagic = nmagic;
                    294:        ml->mapped = mapped;
                    295:
                    296:        mlist->prev->next = ml;
                    297:        ml->prev = mlist->prev;
                    298:        ml->next = mlist;
                    299:        mlist->prev = ml;
1.1       deraadt   300:
1.19      tedu      301:        return 0;
                    302: #endif /* COMPILE_ONLY */
                    303: }
                    304:
                    305: protected void
                    306: file_delmagic(struct magic *p, int type, size_t entries)
                    307: {
                    308:        if (p == NULL)
                    309:                return;
                    310:        switch (type) {
1.25      chl       311: #ifdef QUICK
1.19      tedu      312:        case 2:
                    313:                p--;
                    314:                (void)munmap((void *)p, sizeof(*p) * (entries + 1));
                    315:                break;
1.25      chl       316: #endif
1.19      tedu      317:        case 1:
                    318:                p--;
1.25      chl       319:                /*FALLTHROUGH*/
1.19      tedu      320:        case 0:
                    321:                free(p);
                    322:                break;
                    323:        default:
                    324:                abort();
                    325:        }
                    326: }
                    327:
1.26      chl       328: /* const char *fn: list of magic files and directories */
1.19      tedu      329: protected struct mlist *
                    330: file_apprentice(struct magic_set *ms, const char *fn, int action)
1.2       deraadt   331: {
1.26      chl       332:        char *p, *mfn;
1.2       deraadt   333:        int file_err, errs = -1;
1.19      tedu      334:        struct mlist *mlist;
1.25      chl       335:
                    336:        init_file_tables();
1.2       deraadt   337:
1.19      tedu      338:        if (fn == NULL)
                    339:                fn = getenv("MAGIC");
                    340:        if (fn == NULL)
                    341:                fn = MAGIC;
                    342:
1.25      chl       343:        if ((mfn = strdup(fn)) == NULL) {
                    344:                file_oomem(ms, strlen(fn));
1.19      tedu      345:                return NULL;
                    346:        }
1.25      chl       347:        fn = mfn;
1.19      tedu      348:
                    349:        if ((mlist = malloc(sizeof(*mlist))) == NULL) {
                    350:                free(mfn);
1.25      chl       351:                file_oomem(ms, sizeof(*mlist));
1.19      tedu      352:                return NULL;
1.2       deraadt   353:        }
1.19      tedu      354:        mlist->next = mlist->prev = mlist;
1.17      deraadt   355:
1.2       deraadt   356:        while (fn) {
1.19      tedu      357:                p = strchr(fn, PATHSEP);
1.2       deraadt   358:                if (p)
                    359:                        *p++ = '\0';
1.19      tedu      360:                if (*fn == '\0')
                    361:                        break;
                    362:                file_err = apprentice_1(ms, fn, action, mlist);
1.26      chl       363:                errs = MAX(errs, file_err);
1.2       deraadt   364:                fn = p;
                    365:        }
1.19      tedu      366:        if (errs == -1) {
                    367:                free(mfn);
                    368:                free(mlist);
                    369:                mlist = NULL;
                    370:                file_error(ms, 0, "could not find any magic files!");
                    371:                return NULL;
                    372:        }
1.2       deraadt   373:        free(mfn);
1.19      tedu      374:        return mlist;
1.2       deraadt   375: }
                    376:
1.19      tedu      377: /*
1.25      chl       378:  * Get weight of this magic entry, for sorting purposes.
                    379:  */
                    380: private size_t
                    381: apprentice_magic_strength(const struct magic *m)
                    382: {
                    383: #define MULT 10
                    384:        size_t val = 2 * MULT;  /* baseline strength */
                    385:
                    386:        switch (m->type) {
                    387:        case FILE_DEFAULT:      /* make sure this sorts last */
                    388:                return 0;
                    389:
                    390:        case FILE_BYTE:
                    391:                val += 1 * MULT;
                    392:                break;
                    393:
                    394:        case FILE_SHORT:
                    395:        case FILE_LESHORT:
                    396:        case FILE_BESHORT:
                    397:                val += 2 * MULT;
                    398:                break;
                    399:
                    400:        case FILE_LONG:
                    401:        case FILE_LELONG:
                    402:        case FILE_BELONG:
                    403:        case FILE_MELONG:
                    404:                val += 4 * MULT;
                    405:                break;
                    406:
                    407:        case FILE_PSTRING:
                    408:        case FILE_STRING:
                    409:                val += m->vallen * MULT;
                    410:                break;
                    411:
                    412:        case FILE_BESTRING16:
                    413:        case FILE_LESTRING16:
                    414:                val += m->vallen * MULT / 2;
                    415:                break;
                    416:
                    417:        case FILE_SEARCH:
                    418:        case FILE_REGEX:
1.26      chl       419:                val += m->vallen * MAX(MULT / m->vallen, 1);
1.25      chl       420:                break;
                    421:
                    422:        case FILE_DATE:
                    423:        case FILE_LEDATE:
                    424:        case FILE_BEDATE:
                    425:        case FILE_MEDATE:
                    426:        case FILE_LDATE:
                    427:        case FILE_LELDATE:
                    428:        case FILE_BELDATE:
                    429:        case FILE_MELDATE:
1.26      chl       430:        case FILE_FLOAT:
                    431:        case FILE_BEFLOAT:
                    432:        case FILE_LEFLOAT:
1.25      chl       433:                val += 4 * MULT;
                    434:                break;
                    435:
                    436:        case FILE_QUAD:
                    437:        case FILE_BEQUAD:
                    438:        case FILE_LEQUAD:
                    439:        case FILE_QDATE:
                    440:        case FILE_LEQDATE:
                    441:        case FILE_BEQDATE:
                    442:        case FILE_QLDATE:
                    443:        case FILE_LEQLDATE:
                    444:        case FILE_BEQLDATE:
1.26      chl       445:        case FILE_DOUBLE:
                    446:        case FILE_BEDOUBLE:
                    447:        case FILE_LEDOUBLE:
1.25      chl       448:                val += 8 * MULT;
                    449:                break;
                    450:
                    451:        default:
                    452:                val = 0;
                    453:                (void)fprintf(stderr, "Bad type %d\n", m->type);
                    454:                abort();
                    455:        }
                    456:
                    457:        switch (m->reln) {
                    458:        case 'x':       /* matches anything penalize */
1.26      chl       459:        case '!':       /* matches almost anything penalize */
1.25      chl       460:                val = 0;
                    461:                break;
                    462:
                    463:        case '=':       /* Exact match, prefer */
                    464:                val += MULT;
                    465:                break;
                    466:
                    467:        case '>':
                    468:        case '<':       /* comparison match reduce strength */
                    469:                val -= 2 * MULT;
                    470:                break;
                    471:
                    472:        case '^':
                    473:        case '&':       /* masking bits, we could count them too */
                    474:                val -= MULT;
                    475:                break;
                    476:
                    477:        default:
                    478:                (void)fprintf(stderr, "Bad relation %c\n", m->reln);
                    479:                abort();
                    480:        }
                    481:
                    482:        if (val == 0)   /* ensure we only return 0 for FILE_DEFAULT */
                    483:                val = 1;
                    484:
                    485:        return val;
                    486: }
                    487:
                    488: /*
                    489:  * Sort callback for sorting entries by "strength" (basically length)
                    490:  */
                    491: private int
                    492: apprentice_sort(const void *a, const void *b)
                    493: {
                    494:        const struct magic_entry *ma = a;
                    495:        const struct magic_entry *mb = b;
                    496:        size_t sa = apprentice_magic_strength(ma->mp);
                    497:        size_t sb = apprentice_magic_strength(mb->mp);
                    498:        if (sa == sb)
                    499:                return 0;
                    500:        else if (sa > sb)
                    501:                return -1;
                    502:        else
                    503:                return 1;
                    504: }
                    505:
1.26      chl       506: private void
                    507: set_test_type(struct magic *mstart, struct magic *m)
                    508: {
                    509:        switch (m->type) {
                    510:        case FILE_BYTE:
                    511:        case FILE_SHORT:
                    512:        case FILE_LONG:
                    513:        case FILE_DATE:
                    514:        case FILE_BESHORT:
                    515:        case FILE_BELONG:
                    516:        case FILE_BEDATE:
                    517:        case FILE_LESHORT:
                    518:        case FILE_LELONG:
                    519:        case FILE_LEDATE:
                    520:        case FILE_LDATE:
                    521:        case FILE_BELDATE:
                    522:        case FILE_LELDATE:
                    523:        case FILE_MEDATE:
                    524:        case FILE_MELDATE:
                    525:        case FILE_MELONG:
                    526:        case FILE_QUAD:
                    527:        case FILE_LEQUAD:
                    528:        case FILE_BEQUAD:
                    529:        case FILE_QDATE:
                    530:        case FILE_LEQDATE:
                    531:        case FILE_BEQDATE:
                    532:        case FILE_QLDATE:
                    533:        case FILE_LEQLDATE:
                    534:        case FILE_BEQLDATE:
                    535:        case FILE_FLOAT:
                    536:        case FILE_BEFLOAT:
                    537:        case FILE_LEFLOAT:
                    538:        case FILE_DOUBLE:
                    539:        case FILE_BEDOUBLE:
                    540:        case FILE_LEDOUBLE:
                    541:        case FILE_STRING:
                    542:        case FILE_PSTRING:
                    543:        case FILE_BESTRING16:
                    544:        case FILE_LESTRING16:
                    545:                /* binary test, set flag */
                    546:                mstart->flag |= BINTEST;
                    547:                break;
                    548:        case FILE_REGEX:
                    549:        case FILE_SEARCH:
                    550:                /* binary test if pattern is not text */
                    551:                if (file_looks_utf8(m->value.s, m->vallen, NULL, NULL) == 0)
                    552:                        mstart->flag |= BINTEST;
                    553:                break;
                    554:        case FILE_DEFAULT:
                    555:                /* can't deduce anything; we shouldn't see this at the
                    556:                   top level anyway */
                    557:                break;
                    558:        case FILE_INVALID:
                    559:        default:
                    560:                /* invalid search type, but no need to complain here */
                    561:                break;
                    562:        }
                    563: }
                    564:
1.25      chl       565: /*
1.26      chl       566:  * Load and parse one file.
                    567:  */
                    568: private void
                    569: load_1(struct magic_set *ms, int action, const char *fn, int *errs,
                    570:    struct magic_entry **marray, uint32_t *marraycount)
                    571: {
                    572:        char line[BUFSIZ];
                    573:        size_t lineno = 0;
                    574:        FILE *f = fopen(ms->file = fn, "r");
                    575:        if (f == NULL) {
                    576:                if (errno != ENOENT)
                    577:                        file_error(ms, errno, "cannot read magic file `%s'",
                    578:                                   fn);
                    579:                (*errs)++;
                    580:        } else {
                    581:                /* read and parse this file */
                    582:                for (ms->line = 1; fgets(line, sizeof(line), f) != NULL; ms->line++) {
                    583:                        size_t len;
                    584:                        len = strlen(line);
                    585:                        if (len == 0) /* null line, garbage, etc */
                    586:                                continue;
                    587:                        if (line[len - 1] == '\n') {
                    588:                                lineno++;
                    589:                                line[len - 1] = '\0'; /* delete newline */
                    590:                        }
                    591:                        if (line[0] == '\0')    /* empty, do not parse */
                    592:                                continue;
                    593:                        if (line[0] == '#')     /* comment, do not parse */
                    594:                                continue;
                    595:                        if (len > mime_marker_len &&
                    596:                            memcmp(line, mime_marker, mime_marker_len) == 0) {
                    597:                                /* MIME type */
                    598:                                if (parse_mime(ms, marray, marraycount,
                    599:                                               line + mime_marker_len) != 0)
                    600:                                        (*errs)++;
                    601:                                continue;
                    602:                        }
                    603:                        if (parse(ms, marray, marraycount, line, lineno, action) != 0)
                    604:                                (*errs)++;
                    605:                }
                    606:
                    607:                (void)fclose(f);
                    608:        }
                    609: }
                    610:
                    611: /*
                    612:  * parse a file or directory of files
                    613:  * const char *fn: name of magic file or directory
1.19      tedu      614:  */
                    615: private int
1.26      chl       616: apprentice_load(struct magic_set *ms, struct magic **magicp, uint32_t *nmagicp,
1.19      tedu      617:     const char *fn, int action)
1.1       deraadt   618: {
                    619:        int errs = 0;
1.25      chl       620:        struct magic_entry *marray;
1.26      chl       621:        uint32_t marraycount, i, mentrycount = 0, starttest;
                    622:        char subfn[MAXPATHLEN];
                    623:        struct stat st;
                    624:        DIR *dir;
                    625:        struct dirent *d;
1.1       deraadt   626:
1.25      chl       627:        ms->flags |= MAGIC_CHECK;       /* Enable checks for parsed files */
                    628:
1.19      tedu      629:         maxmagic = MAXMAGIS;
1.25      chl       630:        if ((marray = calloc(maxmagic, sizeof(*marray))) == NULL) {
                    631:                file_oomem(ms, maxmagic * sizeof(*marray));
1.19      tedu      632:                return -1;
                    633:        }
1.25      chl       634:        marraycount = 0;
1.19      tedu      635:
                    636:        /* print silly verbose header for USG compat. */
                    637:        if (action == FILE_CHECK)
1.26      chl       638:                (void)fprintf(stderr, "%s\n", usg_hdr);
                    639:
                    640:        /* load directory or file */
                    641:        if (stat(fn, &st) == 0 && S_ISDIR(st.st_mode)) {
                    642:                dir = opendir(fn);
                    643:                if (dir) {
                    644:                        while (d = readdir(dir)) {
                    645:                                snprintf(subfn, sizeof(subfn), "%s/%s",
                    646:                                    fn, d->d_name);
                    647:                                if (stat(subfn, &st) == 0 && S_ISREG(st.st_mode)) {
                    648:                                        load_1(ms, action, subfn, &errs,
                    649:                                            &marray, &marraycount);
                    650:                                }
                    651:                        }
                    652:                        closedir(dir);
                    653:                } else
                    654:                        errs++;
                    655:        } else
                    656:                load_1(ms, action, fn, &errs, &marray, &marraycount);
                    657:        if (errs)
                    658:                goto out;
1.19      tedu      659:
1.26      chl       660:        /* Set types of tests */
                    661:        for (i = 0; i < marraycount; ) {
                    662:                if (marray[i].mp->cont_level != 0) {
                    663:                        i++;
1.25      chl       664:                        continue;
                    665:                }
1.26      chl       666:
                    667:                starttest = i;
                    668:                do {
                    669:                        set_test_type(marray[starttest].mp, marray[i].mp);
                    670:                        if (ms->flags & MAGIC_DEBUG) {
                    671:                                (void)fprintf(stderr, "%s%s%s: %s\n",
                    672:                                        marray[i].mp->mimetype,
                    673:                                        marray[i].mp->mimetype[0] == '\0' ? "" : "; ",
                    674:                                        marray[i].mp->desc[0] ? marray[i].mp->desc : "(no description)",
                    675:                                        marray[i].mp->flag & BINTEST ? "binary" : "text");
                    676:                                if (marray[i].mp->flag & BINTEST) {
                    677: #define SYMBOL "text"
                    678: #define SYMLEN sizeof(SYMBOL)
                    679:                                        char *p = strstr(marray[i].mp->desc, "text");
                    680:                                        if (p && (p == marray[i].mp->desc || isspace(p[-1])) &&
                    681:                                            (p + SYMLEN - marray[i].mp->desc == MAXstring ||
                    682:                                             (p[SYMLEN] == '\0' || isspace(p[SYMLEN])))) {
                    683:                                                (void)fprintf(stderr,
                    684:                                                              "*** Possible binary test for text type\n");
                    685:                                        }
                    686: #undef SYMBOL
                    687: #undef SYMLEN
                    688:                                }
                    689:                        }
                    690:                } while (++i < marraycount && marray[i].mp->cont_level != 0);
1.1       deraadt   691:        }
                    692:
1.26      chl       693:        qsort(marray, marraycount, sizeof(*marray), apprentice_sort);
1.25      chl       694:
                    695:        /*
                    696:         * Make sure that any level 0 "default" line is last (if one exists).
                    697:         */
                    698:        for (i = 0; i < marraycount; i++) {
                    699:                if (marray[i].mp->cont_level == 0 &&
                    700:                    marray[i].mp->type == FILE_DEFAULT) {
                    701:                        while (++i < marraycount)
                    702:                                if (marray[i].mp->cont_level == 0)
                    703:                                        break;
                    704:                        if (i != marraycount) {
                    705:                                ms->line = marray[i].mp->lineno; /* XXX - Ugh! */
                    706:                                file_magwarn(ms,
                    707:                                    "level 0 \"default\" did not sort last");
                    708:                        }
                    709:                        break;
                    710:                }
                    711:        }
                    712:
                    713:        for (i = 0; i < marraycount; i++)
                    714:                mentrycount += marray[i].cont_count;
                    715:
                    716:        if ((*magicp = malloc(sizeof(**magicp) * mentrycount)) == NULL) {
                    717:                file_oomem(ms, sizeof(**magicp) * mentrycount);
                    718:                errs++;
                    719:                goto out;
                    720:        }
                    721:
                    722:        mentrycount = 0;
                    723:        for (i = 0; i < marraycount; i++) {
                    724:                (void)memcpy(*magicp + mentrycount, marray[i].mp,
                    725:                    marray[i].cont_count * sizeof(**magicp));
                    726:                mentrycount += marray[i].cont_count;
                    727:        }
                    728: out:
                    729:        for (i = 0; i < marraycount; i++)
                    730:                free(marray[i].mp);
                    731:        free(marray);
1.19      tedu      732:        if (errs) {
                    733:                *magicp = NULL;
                    734:                *nmagicp = 0;
1.25      chl       735:                return errs;
                    736:        } else {
                    737:                *nmagicp = mentrycount;
                    738:                return 0;
1.19      tedu      739:        }
1.25      chl       740:
1.1       deraadt   741: }
                    742:
                    743: /*
                    744:  * extend the sign bit if the comparison is to be signed
                    745:  */
1.25      chl       746: protected uint64_t
                    747: file_signextend(struct magic_set *ms, struct magic *m, uint64_t v)
1.1       deraadt   748: {
1.25      chl       749:        if (!(m->flag & UNSIGNED)) {
1.1       deraadt   750:                switch(m->type) {
                    751:                /*
                    752:                 * Do not remove the casts below.  They are
                    753:                 * vital.  When later compared with the data,
                    754:                 * the sign extension must have happened.
                    755:                 */
1.19      tedu      756:                case FILE_BYTE:
1.1       deraadt   757:                        v = (char) v;
                    758:                        break;
1.19      tedu      759:                case FILE_SHORT:
                    760:                case FILE_BESHORT:
                    761:                case FILE_LESHORT:
1.1       deraadt   762:                        v = (short) v;
                    763:                        break;
1.19      tedu      764:                case FILE_DATE:
                    765:                case FILE_BEDATE:
                    766:                case FILE_LEDATE:
1.25      chl       767:                case FILE_MEDATE:
1.19      tedu      768:                case FILE_LDATE:
                    769:                case FILE_BELDATE:
                    770:                case FILE_LELDATE:
1.25      chl       771:                case FILE_MELDATE:
1.19      tedu      772:                case FILE_LONG:
                    773:                case FILE_BELONG:
                    774:                case FILE_LELONG:
1.25      chl       775:                case FILE_MELONG:
1.26      chl       776:                case FILE_FLOAT:
                    777:                case FILE_BEFLOAT:
                    778:                case FILE_LEFLOAT:
1.14      itojun    779:                        v = (int32_t) v;
1.1       deraadt   780:                        break;
1.25      chl       781:                case FILE_QUAD:
                    782:                case FILE_BEQUAD:
                    783:                case FILE_LEQUAD:
                    784:                case FILE_QDATE:
                    785:                case FILE_QLDATE:
                    786:                case FILE_BEQDATE:
                    787:                case FILE_BEQLDATE:
                    788:                case FILE_LEQDATE:
                    789:                case FILE_LEQLDATE:
1.26      chl       790:                case FILE_DOUBLE:
                    791:                case FILE_BEDOUBLE:
                    792:                case FILE_LEDOUBLE:
1.25      chl       793:                        v = (int64_t) v;
                    794:                        break;
1.19      tedu      795:                case FILE_STRING:
                    796:                case FILE_PSTRING:
1.25      chl       797:                case FILE_BESTRING16:
                    798:                case FILE_LESTRING16:
1.19      tedu      799:                case FILE_REGEX:
1.25      chl       800:                case FILE_SEARCH:
                    801:                case FILE_DEFAULT:
1.1       deraadt   802:                        break;
                    803:                default:
1.19      tedu      804:                        if (ms->flags & MAGIC_CHECK)
1.25      chl       805:                            file_magwarn(ms, "cannot happen: m->type=%d\n",
1.19      tedu      806:                                    m->type);
                    807:                        return ~0U;
1.1       deraadt   808:                }
1.25      chl       809:        }
1.1       deraadt   810:        return v;
                    811: }
                    812:
1.25      chl       813: private int
1.26      chl       814: string_modifier_check(struct magic_set *ms, struct magic *m)
1.25      chl       815: {
                    816:        if ((ms->flags & MAGIC_CHECK) == 0)
                    817:                return 0;
                    818:
                    819:        switch (m->type) {
                    820:        case FILE_BESTRING16:
                    821:        case FILE_LESTRING16:
                    822:                if (m->str_flags != 0) {
1.26      chl       823:                        file_magwarn(ms,
                    824:                            "no modifiers allowed for 16-bit strings\n");
1.25      chl       825:                        return -1;
                    826:                }
                    827:                break;
                    828:        case FILE_STRING:
                    829:        case FILE_PSTRING:
                    830:                if ((m->str_flags & REGEX_OFFSET_START) != 0) {
1.26      chl       831:                        file_magwarn(ms,
                    832:                            "'/%c' only allowed on regex and search\n",
1.25      chl       833:                            CHAR_REGEX_OFFSET_START);
                    834:                        return -1;
                    835:                }
                    836:                break;
                    837:        case FILE_SEARCH:
1.26      chl       838:                if (m->str_range == 0) {
                    839:                        file_magwarn(ms,
                    840:                            "missing range; defaulting to %d\n",
                    841:                             STRING_DEFAULT_RANGE);
                    842:                        m->str_range = STRING_DEFAULT_RANGE;
                    843:                        return -1;
                    844:                }
1.25      chl       845:                break;
                    846:        case FILE_REGEX:
                    847:                if ((m->str_flags & STRING_COMPACT_BLANK) != 0) {
                    848:                        file_magwarn(ms, "'/%c' not allowed on regex\n",
                    849:                            CHAR_COMPACT_BLANK);
                    850:                        return -1;
                    851:                }
                    852:                if ((m->str_flags & STRING_COMPACT_OPTIONAL_BLANK) != 0) {
                    853:                        file_magwarn(ms, "'/%c' not allowed on regex\n",
                    854:                            CHAR_COMPACT_OPTIONAL_BLANK);
                    855:                        return -1;
                    856:                }
                    857:                break;
                    858:        default:
                    859:                file_magwarn(ms, "coding error: m->type=%d\n",
                    860:                    m->type);
                    861:                return -1;
                    862:        }
                    863:        return 0;
                    864: }
                    865:
                    866: private int
                    867: get_op(char c)
                    868: {
                    869:        switch (c) {
                    870:        case '&':
                    871:                return FILE_OPAND;
                    872:        case '|':
                    873:                return FILE_OPOR;
                    874:        case '^':
                    875:                return FILE_OPXOR;
                    876:        case '+':
                    877:                return FILE_OPADD;
                    878:        case '-':
                    879:                return FILE_OPMINUS;
                    880:        case '*':
                    881:                return FILE_OPMULTIPLY;
                    882:        case '/':
                    883:                return FILE_OPDIVIDE;
                    884:        case '%':
                    885:                return FILE_OPMODULO;
                    886:        default:
                    887:                return -1;
                    888:        }
                    889: }
                    890:
                    891: #ifdef ENABLE_CONDITIONALS
                    892: private int
                    893: get_cond(const char *l, const char **t)
                    894: {
1.26      chl       895:        static const struct cond_tbl_s {
                    896:                char name[8];
                    897:                size_t len;
                    898:                int cond;
1.25      chl       899:        } cond_tbl[] = {
                    900:                { "if",         2,      COND_IF },
                    901:                { "elif",       4,      COND_ELIF },
                    902:                { "else",       4,      COND_ELSE },
1.26      chl       903:                { "",           0,      COND_NONE },
1.25      chl       904:        };
1.26      chl       905:        const struct cond_tbl_s *p;
1.25      chl       906:
1.26      chl       907:        for (p = cond_tbl; p->len; p++) {
1.25      chl       908:                if (strncmp(l, p->name, p->len) == 0 &&
                    909:                    isspace((unsigned char)l[p->len])) {
                    910:                        if (t)
                    911:                                *t = l + p->len;
                    912:                        break;
                    913:                }
                    914:        }
                    915:        return p->cond;
                    916: }
                    917:
                    918: private int
                    919: check_cond(struct magic_set *ms, int cond, uint32_t cont_level)
                    920: {
                    921:        int last_cond;
                    922:        last_cond = ms->c.li[cont_level].last_cond;
                    923:
                    924:        switch (cond) {
                    925:        case COND_IF:
                    926:                if (last_cond != COND_NONE && last_cond != COND_ELIF) {
                    927:                        if (ms->flags & MAGIC_CHECK)
                    928:                                file_magwarn(ms, "syntax error: `if'");
                    929:                        return -1;
                    930:                }
                    931:                last_cond = COND_IF;
                    932:                break;
                    933:
                    934:        case COND_ELIF:
                    935:                if (last_cond != COND_IF && last_cond != COND_ELIF) {
                    936:                        if (ms->flags & MAGIC_CHECK)
                    937:                                file_magwarn(ms, "syntax error: `elif'");
                    938:                        return -1;
                    939:                }
                    940:                last_cond = COND_ELIF;
                    941:                break;
                    942:
                    943:        case COND_ELSE:
                    944:                if (last_cond != COND_IF && last_cond != COND_ELIF) {
                    945:                        if (ms->flags & MAGIC_CHECK)
                    946:                                file_magwarn(ms, "syntax error: `else'");
                    947:                        return -1;
                    948:                }
                    949:                last_cond = COND_NONE;
                    950:                break;
                    951:
                    952:        case COND_NONE:
                    953:                last_cond = COND_NONE;
                    954:                break;
                    955:        }
                    956:
                    957:        ms->c.li[cont_level].last_cond = last_cond;
                    958:        return 0;
                    959: }
                    960: #endif /* ENABLE_CONDITIONALS */
                    961:
1.1       deraadt   962: /*
                    963:  * parse one line from magic file, put into magic[index++] if valid
                    964:  */
1.19      tedu      965: private int
1.25      chl       966: parse(struct magic_set *ms, struct magic_entry **mentryp, uint32_t *nmentryp,
                    967:     const char *line, size_t lineno, int action)
1.1       deraadt   968: {
1.25      chl       969: #ifdef ENABLE_CONDITIONALS
                    970:        static uint32_t last_cont_level = 0;
                    971: #endif
                    972:        size_t i;
                    973:        struct magic_entry *me;
1.1       deraadt   974:        struct magic *m;
1.25      chl       975:        const char *l = line;
1.19      tedu      976:        char *t;
1.25      chl       977:        int op;
                    978:        uint32_t cont_level;
1.19      tedu      979:
1.25      chl       980:        cont_level = 0;
1.1       deraadt   981:
                    982:        while (*l == '>') {
                    983:                ++l;            /* step over */
1.25      chl       984:                cont_level++;
1.1       deraadt   985:        }
1.25      chl       986: #ifdef ENABLE_CONDITIONALS
                    987:        if (cont_level == 0 || cont_level > last_cont_level)
                    988:                if (file_check_mem(ms, cont_level) == -1)
                    989:                        return -1;
                    990:        last_cont_level = cont_level;
                    991: #endif
                    992:
                    993: #define ALLOC_CHUNK    (size_t)10
                    994: #define ALLOC_INCR     (size_t)200
1.1       deraadt   995:
1.25      chl       996:        if (cont_level != 0) {
                    997:                if (*nmentryp == 0) {
                    998:                        file_error(ms, 0, "No current entry for continuation");
                    999:                        return -1;
                   1000:                }
                   1001:                me = &(*mentryp)[*nmentryp - 1];
                   1002:                if (me->cont_count == me->max_count) {
                   1003:                        struct magic *nm;
                   1004:                        size_t cnt = me->max_count + ALLOC_CHUNK;
                   1005:                        if ((nm = realloc(me->mp, sizeof(*nm) * cnt)) == NULL) {
                   1006:                                file_oomem(ms, sizeof(*nm) * cnt);
                   1007:                                return -1;
                   1008:                        }
                   1009:                        me->mp = m = nm;
                   1010:                        me->max_count = cnt;
                   1011:                }
                   1012:                m = &me->mp[me->cont_count++];
                   1013:                (void)memset(m, 0, sizeof(*m));
                   1014:                m->cont_level = cont_level;
                   1015:        } else {
                   1016:                if (*nmentryp == maxmagic) {
                   1017:                        struct magic_entry *mp;
                   1018:
                   1019:                        maxmagic += ALLOC_INCR;
                   1020:                        if ((mp = realloc(*mentryp, sizeof(*mp) * maxmagic)) ==
                   1021:                            NULL) {
                   1022:                                file_oomem(ms, sizeof(*mp) * maxmagic);
                   1023:                                return -1;
                   1024:                        }
                   1025:                        (void)memset(&mp[*nmentryp], 0, sizeof(*mp) *
                   1026:                            ALLOC_INCR);
                   1027:                        *mentryp = mp;
                   1028:                }
                   1029:                me = &(*mentryp)[*nmentryp];
                   1030:                if (me->mp == NULL) {
                   1031:                        if ((m = malloc(sizeof(*m) * ALLOC_CHUNK)) == NULL) {
                   1032:                                file_oomem(ms, sizeof(*m) * ALLOC_CHUNK);
                   1033:                                return -1;
                   1034:                        }
                   1035:                        me->mp = m;
                   1036:                        me->max_count = ALLOC_CHUNK;
                   1037:                } else
                   1038:                        m = me->mp;
                   1039:                (void)memset(m, 0, sizeof(*m));
                   1040:                m->cont_level = 0;
                   1041:                me->cont_count = 1;
1.1       deraadt  1042:        }
1.25      chl      1043:        m->lineno = lineno;
                   1044:
                   1045:        if (*l == '&') {  /* m->cont_level == 0 checked below. */
1.4       millert  1046:                 ++l;            /* step over */
1.19      tedu     1047:                 m->flag |= OFFADD;
1.4       millert  1048:         }
1.25      chl      1049:        if (*l == '(') {
                   1050:                ++l;            /* step over */
                   1051:                m->flag |= INDIR;
                   1052:                if (m->flag & OFFADD)
                   1053:                        m->flag = (m->flag & ~OFFADD) | INDIROFFADD;
                   1054:
                   1055:                if (*l == '&') {  /* m->cont_level == 0 checked below */
                   1056:                        ++l;            /* step over */
                   1057:                        m->flag |= OFFADD;
                   1058:                }
                   1059:        }
                   1060:        /* Indirect offsets are not valid at level 0. */
                   1061:        if (m->cont_level == 0 && (m->flag & (OFFADD | INDIROFFADD)))
                   1062:                if (ms->flags & MAGIC_CHECK)
                   1063:                        file_magwarn(ms, "relative offset at level 0");
1.1       deraadt  1064:
                   1065:        /* get offset, then skip over it */
1.19      tedu     1066:        m->offset = (uint32_t)strtoul(l, &t, 0);
1.1       deraadt  1067:         if (l == t)
1.19      tedu     1068:                if (ms->flags & MAGIC_CHECK)
1.25      chl      1069:                        file_magwarn(ms, "offset `%s' invalid", l);
1.1       deraadt  1070:         l = t;
                   1071:
                   1072:        if (m->flag & INDIR) {
1.19      tedu     1073:                m->in_type = FILE_LONG;
                   1074:                m->in_offset = 0;
1.1       deraadt  1075:                /*
                   1076:                 * read [.lbs][+-]nnnnn)
                   1077:                 */
                   1078:                if (*l == '.') {
                   1079:                        l++;
1.19      tedu     1080:                        switch (*l) {
1.1       deraadt  1081:                        case 'l':
1.19      tedu     1082:                                m->in_type = FILE_LELONG;
                   1083:                                break;
                   1084:                        case 'L':
                   1085:                                m->in_type = FILE_BELONG;
1.1       deraadt  1086:                                break;
1.25      chl      1087:                        case 'm':
                   1088:                                m->in_type = FILE_MELONG;
                   1089:                                break;
1.1       deraadt  1090:                        case 'h':
                   1091:                        case 's':
1.19      tedu     1092:                                m->in_type = FILE_LESHORT;
                   1093:                                break;
                   1094:                        case 'H':
                   1095:                        case 'S':
                   1096:                                m->in_type = FILE_BESHORT;
1.1       deraadt  1097:                                break;
                   1098:                        case 'c':
                   1099:                        case 'b':
1.19      tedu     1100:                        case 'C':
                   1101:                        case 'B':
                   1102:                                m->in_type = FILE_BYTE;
1.1       deraadt  1103:                                break;
1.26      chl      1104:                        case 'e':
                   1105:                        case 'f':
                   1106:                        case 'g':
                   1107:                                m->in_type = FILE_LEDOUBLE;
                   1108:                                break;
                   1109:                        case 'E':
                   1110:                        case 'F':
                   1111:                        case 'G':
                   1112:                                m->in_type = FILE_BEDOUBLE;
                   1113:                                break;
1.1       deraadt  1114:                        default:
1.19      tedu     1115:                                if (ms->flags & MAGIC_CHECK)
1.25      chl      1116:                                        file_magwarn(ms,
                   1117:                                            "indirect offset type `%c' invalid",
1.19      tedu     1118:                                            *l);
1.1       deraadt  1119:                                break;
                   1120:                        }
                   1121:                        l++;
                   1122:                }
1.25      chl      1123:
                   1124:                m->in_op = 0;
1.19      tedu     1125:                if (*l == '~') {
1.25      chl      1126:                        m->in_op |= FILE_OPINVERSE;
1.19      tedu     1127:                        l++;
                   1128:                }
1.25      chl      1129:                if ((op = get_op(*l)) != -1) {
                   1130:                        m->in_op |= op;
1.19      tedu     1131:                        l++;
1.25      chl      1132:                }
                   1133:                if (*l == '(') {
                   1134:                        m->in_op |= FILE_OPINDIRECT;
1.19      tedu     1135:                        l++;
1.1       deraadt  1136:                }
1.25      chl      1137:                if (isdigit((unsigned char)*l) || *l == '-') {
                   1138:                        m->in_offset = (int32_t)strtol(l, &t, 0);
                   1139:                        if (l == t)
                   1140:                                if (ms->flags & MAGIC_CHECK)
                   1141:                                        file_magwarn(ms,
                   1142:                                            "in_offset `%s' invalid", l);
                   1143:                        l = t;
                   1144:                }
                   1145:                if (*l++ != ')' ||
                   1146:                    ((m->in_op & FILE_OPINDIRECT) && *l++ != ')'))
1.19      tedu     1147:                        if (ms->flags & MAGIC_CHECK)
1.25      chl      1148:                                file_magwarn(ms,
                   1149:                                    "missing ')' in indirect offset");
1.1       deraadt  1150:        }
1.25      chl      1151:        EATAB;
1.1       deraadt  1152:
1.25      chl      1153: #ifdef ENABLE_CONDITIONALS
                   1154:        m->cond = get_cond(l, &l);
                   1155:        if (check_cond(ms, m->cond, cont_level) == -1)
                   1156:                return -1;
1.1       deraadt  1157:
                   1158:        EATAB;
1.25      chl      1159: #endif
1.1       deraadt  1160:
                   1161:        if (*l == 'u') {
                   1162:                ++l;
                   1163:                m->flag |= UNSIGNED;
                   1164:        }
                   1165:
1.25      chl      1166:        m->type = get_type(l, &l);
                   1167:        if (m->type == FILE_INVALID) {
1.19      tedu     1168:                if (ms->flags & MAGIC_CHECK)
1.25      chl      1169:                        file_magwarn(ms, "type `%s' invalid", l);
1.1       deraadt  1170:                return -1;
                   1171:        }
1.25      chl      1172:
1.1       deraadt  1173:        /* New-style anding: "0 byte&0x80 =0x80 dynamically linked" */
1.19      tedu     1174:        /* New and improved: ~ & | ^ + - * / % -- exciting, isn't it? */
1.25      chl      1175:
                   1176:        m->mask_op = 0;
1.19      tedu     1177:        if (*l == '~') {
1.25      chl      1178:                if (!IS_STRING(m->type))
                   1179:                        m->mask_op |= FILE_OPINVERSE;
                   1180:                else if (ms->flags & MAGIC_CHECK)
                   1181:                        file_magwarn(ms, "'~' invalid for string types");
1.1       deraadt  1182:                ++l;
1.19      tedu     1183:        }
1.26      chl      1184:        m->str_range = 0;
1.25      chl      1185:        m->str_flags = 0;
                   1186:        m->num_mask = 0;
                   1187:        if ((op = get_op(*l)) != -1) {
                   1188:                if (!IS_STRING(m->type)) {
                   1189:                        uint64_t val;
1.19      tedu     1190:                        ++l;
                   1191:                        m->mask_op |= op;
1.25      chl      1192:                        val = (uint64_t)strtoull(l, &t, 0);
                   1193:                        l = t;
                   1194:                        m->num_mask = file_signextend(ms, m, val);
1.19      tedu     1195:                        eatsize(&l);
1.25      chl      1196:                }
                   1197:                else if (op == FILE_OPDIVIDE) {
1.26      chl      1198:                        int have_range = 0;
1.19      tedu     1199:                        while (!isspace((unsigned char)*++l)) {
                   1200:                                switch (*l) {
1.25      chl      1201:                                case '0':  case '1':  case '2':
                   1202:                                case '3':  case '4':  case '5':
                   1203:                                case '6':  case '7':  case '8':
1.26      chl      1204:                                case '9':
                   1205:                                        if (have_range &&
                   1206:                                            (ms->flags & MAGIC_CHECK))
1.25      chl      1207:                                                file_magwarn(ms,
1.26      chl      1208:                                                    "multiple ranges");
                   1209:                                        have_range = 1;
                   1210:                                        m->str_range = strtoul(l, &t, 0);
                   1211:                                        if (m->str_range == 0)
                   1212:                                                file_magwarn(ms,
                   1213:                                                    "zero range");
1.25      chl      1214:                                        l = t - 1;
1.19      tedu     1215:                                        break;
                   1216:                                case CHAR_COMPACT_BLANK:
1.25      chl      1217:                                        m->str_flags |= STRING_COMPACT_BLANK;
1.19      tedu     1218:                                        break;
                   1219:                                case CHAR_COMPACT_OPTIONAL_BLANK:
1.25      chl      1220:                                        m->str_flags |=
1.19      tedu     1221:                                            STRING_COMPACT_OPTIONAL_BLANK;
                   1222:                                        break;
1.25      chl      1223:                                case CHAR_IGNORE_LOWERCASE:
                   1224:                                        m->str_flags |= STRING_IGNORE_LOWERCASE;
                   1225:                                        break;
                   1226:                                case CHAR_IGNORE_UPPERCASE:
                   1227:                                        m->str_flags |= STRING_IGNORE_UPPERCASE;
                   1228:                                        break;
                   1229:                                case CHAR_REGEX_OFFSET_START:
                   1230:                                        m->str_flags |= REGEX_OFFSET_START;
                   1231:                                        break;
1.19      tedu     1232:                                default:
                   1233:                                        if (ms->flags & MAGIC_CHECK)
1.25      chl      1234:                                                file_magwarn(ms,
                   1235:                                                "string extension `%c' invalid",
1.19      tedu     1236:                                                *l);
                   1237:                                        return -1;
                   1238:                                }
1.25      chl      1239:                                /* allow multiple '/' for readability */
1.26      chl      1240:                                if (l[1] == '/' &&
                   1241:                                    !isspace((unsigned char)l[2]))
1.25      chl      1242:                                        l++;
1.19      tedu     1243:                        }
1.25      chl      1244:                        if (string_modifier_check(ms, m) == -1)
                   1245:                                return -1;
                   1246:                }
                   1247:                else {
                   1248:                        if (ms->flags & MAGIC_CHECK)
                   1249:                                file_magwarn(ms, "invalid string op: %c", *t);
                   1250:                        return -1;
1.19      tedu     1251:                }
                   1252:        }
                   1253:        /*
                   1254:         * We used to set mask to all 1's here, instead let's just not do
                   1255:         * anything if mask = 0 (unless you have a better idea)
                   1256:         */
1.1       deraadt  1257:        EATAB;
                   1258:
                   1259:        switch (*l) {
                   1260:        case '>':
                   1261:        case '<':
                   1262:        /* Old-style anding: "0 byte &0x80 dynamically linked" */
                   1263:        case '&':
                   1264:        case '^':
                   1265:        case '=':
                   1266:                m->reln = *l;
                   1267:                ++l;
1.19      tedu     1268:                if (*l == '=') {
                   1269:                   /* HP compat: ignore &= etc. */
                   1270:                   ++l;
                   1271:                }
1.1       deraadt  1272:                break;
                   1273:        case '!':
1.25      chl      1274:                m->reln = *l;
                   1275:                ++l;
                   1276:                break;
1.1       deraadt  1277:        default:
1.25      chl      1278:                m->reln = '=';  /* the default relation */
                   1279:                if (*l == 'x' && ((isascii((unsigned char)l[1]) &&
                   1280:                    isspace((unsigned char)l[1])) || !l[1])) {
1.1       deraadt  1281:                        m->reln = *l;
                   1282:                        ++l;
                   1283:                }
                   1284:                break;
                   1285:        }
1.25      chl      1286:        /*
                   1287:         * Grab the value part, except for an 'x' reln.
                   1288:         */
                   1289:        if (m->reln != 'x' && getvalue(ms, m, &l, action))
1.1       deraadt  1290:                return -1;
1.25      chl      1291:
1.1       deraadt  1292:        /*
                   1293:         * TODO finish this macro and start using it!
                   1294:         * #define offsetcheck {if (offset > HOWMANY-1)
1.19      tedu     1295:         *      magwarn("offset too big"); }
1.1       deraadt  1296:         */
                   1297:
                   1298:        /*
1.25      chl      1299:         * Now get last part - the description
1.1       deraadt  1300:         */
                   1301:        EATAB;
                   1302:        if (l[0] == '\b') {
                   1303:                ++l;
1.26      chl      1304:                m->flag |= NOSPACE;
1.1       deraadt  1305:        } else if ((l[0] == '\\') && (l[1] == 'b')) {
                   1306:                ++l;
                   1307:                ++l;
1.26      chl      1308:                m->flag |= NOSPACE;
                   1309:        }
1.25      chl      1310:        for (i = 0; (m->desc[i++] = *l++) != '\0' && i < sizeof(m->desc); )
                   1311:                continue;
                   1312:        if (i == sizeof(m->desc)) {
                   1313:                m->desc[sizeof(m->desc) - 1] = '\0';
                   1314:                if (ms->flags & MAGIC_CHECK)
                   1315:                        file_magwarn(ms, "description `%s' truncated", m->desc);
                   1316:        }
1.21      pedro    1317:
1.25      chl      1318:         /*
                   1319:         * We only do this check while compiling, or if any of the magic
                   1320:         * files were not compiled.
                   1321:          */
                   1322:         if (ms->flags & MAGIC_CHECK) {
                   1323:                if (check_format(ms, m) == -1)
                   1324:                        return -1;
                   1325:        }
1.19      tedu     1326: #ifndef COMPILE_ONLY
                   1327:        if (action == FILE_CHECK) {
                   1328:                file_mdump(m);
1.1       deraadt  1329:        }
1.19      tedu     1330: #endif
1.26      chl      1331:        m->mimetype[0] = '\0';          /* initialise MIME type to none */
1.25      chl      1332:        if (m->cont_level == 0)
                   1333:                ++(*nmentryp);          /* make room for next */
                   1334:        return 0;
                   1335: }
                   1336:
1.26      chl      1337: /*
                   1338:  * parse a MIME annotation line from magic file, put into magic[index - 1]
                   1339:  * if valid
                   1340:  */
                   1341: private int
                   1342: parse_mime(struct magic_set *ms, struct magic_entry **mentryp,
                   1343:     uint32_t *nmentryp, const char *line)
                   1344: {
                   1345:        size_t i;
                   1346:        const char *l = line;
                   1347:        struct magic *m;
                   1348:        struct magic_entry *me;
                   1349:
                   1350:        if (*nmentryp == 0) {
                   1351:                file_error(ms, 0, "No current entry for MIME type");
                   1352:                return -1;
                   1353:        }
                   1354:
                   1355:        me = &(*mentryp)[*nmentryp - 1];
                   1356:        m = &me->mp[me->cont_count == 0 ? 0 : me->cont_count - 1];
                   1357:
                   1358:        if (m->mimetype[0] != '\0') {
                   1359:                file_error(ms, 0, "Current entry already has a MIME type: %s\n"
                   1360:                    "Description: %s\nNew type: %s", m->mimetype, m->desc, l);
                   1361:                return -1;
                   1362:        }
                   1363:
                   1364:        EATAB;
                   1365:        for (i = 0;
                   1366:             *l && ((isascii((unsigned char)*l) && isalnum((unsigned char)*l))
                   1367:             || strchr("-+/.", *l)) && i < sizeof(m->mimetype);
                   1368:             m->mimetype[i++] = *l++)
                   1369:                continue;
                   1370:        if (i == sizeof(m->mimetype)) {
                   1371:                m->desc[sizeof(m->mimetype) - 1] = '\0';
                   1372:                if (ms->flags & MAGIC_CHECK)
                   1373:                        file_magwarn(ms, "MIME type `%s' truncated %zu",
                   1374:                            m->mimetype, i);
                   1375:        } else
                   1376:                m->mimetype[i] = '\0';
                   1377:
                   1378:        if (i > 0)
                   1379:                return 0;
                   1380:        else
                   1381:                return -1;
                   1382: }
                   1383:
1.25      chl      1384: private int
                   1385: check_format_type(const char *ptr, int type)
                   1386: {
                   1387:        int quad = 0;
                   1388:        if (*ptr == '\0') {
                   1389:                /* Missing format string; bad */
                   1390:                return -1;
                   1391:        }
                   1392:
                   1393:        switch (type) {
                   1394:        case FILE_FMT_QUAD:
                   1395:                quad = 1;
                   1396:                /*FALLTHROUGH*/
                   1397:        case FILE_FMT_NUM:
                   1398:                if (*ptr == '-')
                   1399:                        ptr++;
                   1400:                if (*ptr == '.')
                   1401:                        ptr++;
                   1402:                while (isdigit((unsigned char)*ptr)) ptr++;
                   1403:                if (*ptr == '.')
                   1404:                        ptr++;
                   1405:                while (isdigit((unsigned char)*ptr)) ptr++;
                   1406:                if (quad) {
                   1407:                        if (*ptr++ != 'l')
                   1408:                                return -1;
                   1409:                        if (*ptr++ != 'l')
                   1410:                                return -1;
                   1411:                }
                   1412:
                   1413:                switch (*ptr++) {
                   1414:                case 'l':
                   1415:                        switch (*ptr++) {
                   1416:                        case 'i':
                   1417:                        case 'd':
                   1418:                        case 'u':
                   1419:                        case 'x':
                   1420:                        case 'X':
                   1421:                                return 0;
                   1422:                        default:
                   1423:                                return -1;
                   1424:                        }
                   1425:
                   1426:                case 'h':
                   1427:                        switch (*ptr++) {
                   1428:                        case 'h':
                   1429:                                switch (*ptr++) {
                   1430:                                case 'i':
                   1431:                                case 'd':
                   1432:                                case 'u':
                   1433:                                case 'x':
                   1434:                                case 'X':
                   1435:                                        return 0;
                   1436:                                default:
                   1437:                                        return -1;
                   1438:                                }
                   1439:                        case 'd':
                   1440:                                return 0;
                   1441:                        default:
                   1442:                                return -1;
                   1443:                        }
                   1444:
                   1445:                case 'i':
                   1446:                case 'c':
                   1447:                case 'd':
                   1448:                case 'u':
                   1449:                case 'x':
                   1450:                case 'X':
                   1451:                        return 0;
                   1452:
                   1453:                default:
                   1454:                        return -1;
                   1455:                }
                   1456:
1.26      chl      1457:        case FILE_FMT_FLOAT:
                   1458:        case FILE_FMT_DOUBLE:
                   1459:                if (*ptr == '-')
                   1460:                        ptr++;
                   1461:                if (*ptr == '.')
                   1462:                        ptr++;
                   1463:                while (isdigit((unsigned char)*ptr)) ptr++;
                   1464:                if (*ptr == '.')
                   1465:                        ptr++;
                   1466:                while (isdigit((unsigned char)*ptr)) ptr++;
                   1467:
                   1468:                switch (*ptr++) {
                   1469:                case 'e':
                   1470:                case 'E':
                   1471:                case 'f':
                   1472:                case 'F':
                   1473:                case 'g':
                   1474:                case 'G':
                   1475:                        return 0;
                   1476:
                   1477:                default:
                   1478:                        return -1;
                   1479:                }
                   1480:
                   1481:
1.25      chl      1482:        case FILE_FMT_STR:
                   1483:                if (*ptr == '-')
                   1484:                        ptr++;
                   1485:                while (isdigit((unsigned char )*ptr))
                   1486:                        ptr++;
                   1487:                if (*ptr == '.') {
                   1488:                        ptr++;
                   1489:                        while (isdigit((unsigned char )*ptr))
                   1490:                                ptr++;
                   1491:                }
                   1492:
                   1493:                switch (*ptr++) {
                   1494:                case 's':
                   1495:                        return 0;
                   1496:                default:
                   1497:                        return -1;
                   1498:                }
                   1499:
                   1500:        default:
                   1501:                /* internal error */
                   1502:                abort();
                   1503:        }
                   1504:        /*NOTREACHED*/
                   1505:        return -1;
                   1506: }
                   1507:
                   1508: /*
                   1509:  * Check that the optional printf format in description matches
                   1510:  * the type of the magic.
                   1511:  */
                   1512: private int
                   1513: check_format(struct magic_set *ms, struct magic *m)
                   1514: {
                   1515:        char *ptr;
                   1516:
                   1517:        for (ptr = m->desc; *ptr; ptr++)
                   1518:                if (*ptr == '%')
                   1519:                        break;
                   1520:        if (*ptr == '\0') {
                   1521:                /* No format string; ok */
                   1522:                return 1;
                   1523:        }
                   1524:
                   1525:        assert(file_nformats == file_nnames);
                   1526:
                   1527:        if (m->type >= file_nformats) {
1.26      chl      1528:                file_magwarn(ms, "Internal error inconsistency between "
1.25      chl      1529:                    "m->type and format strings");
                   1530:                return -1;
                   1531:        }
                   1532:        if (file_formats[m->type] == FILE_FMT_NONE) {
1.26      chl      1533:                file_magwarn(ms, "No format string for `%s' with description "
1.25      chl      1534:                    "`%s'", m->desc, file_names[m->type]);
                   1535:                return -1;
                   1536:        }
                   1537:
                   1538:        ptr++;
                   1539:        if (check_format_type(ptr, file_formats[m->type]) == -1) {
                   1540:                /*
                   1541:                 * TODO: this error message is unhelpful if the format
                   1542:                 * string is not one character long
                   1543:                 */
1.26      chl      1544:                file_magwarn(ms, "Printf format `%c' is not valid for type "
                   1545:                    "`%s' in description `%s'",
1.25      chl      1546:                    ptr && *ptr ? *ptr : '?',
                   1547:                    file_names[m->type], m->desc);
                   1548:                return -1;
                   1549:        }
                   1550:
                   1551:        for (; *ptr; ptr++) {
                   1552:                if (*ptr == '%') {
1.26      chl      1553:                        file_magwarn(ms,
1.25      chl      1554:                            "Too many format strings (should have at most one) "
                   1555:                            "for `%s' with description `%s'",
                   1556:                            file_names[m->type], m->desc);
                   1557:                        return -1;
                   1558:                }
                   1559:        }
1.1       deraadt  1560:        return 0;
                   1561: }
                   1562:
                   1563: /*
                   1564:  * Read a numeric value from a pointer, into the value union of a magic
                   1565:  * pointer, according to the magic type.  Update the string pointer to point
                   1566:  * just after the number read.  Return 0 for success, non-zero for failure.
                   1567:  */
1.19      tedu     1568: private int
1.25      chl      1569: getvalue(struct magic_set *ms, struct magic *m, const char **p, int action)
1.1       deraadt  1570: {
                   1571:        int slen;
                   1572:
1.19      tedu     1573:        switch (m->type) {
1.25      chl      1574:        case FILE_BESTRING16:
                   1575:        case FILE_LESTRING16:
1.19      tedu     1576:        case FILE_STRING:
                   1577:        case FILE_PSTRING:
                   1578:        case FILE_REGEX:
1.25      chl      1579:        case FILE_SEARCH:
                   1580:                *p = getstr(ms, *p, m->value.s, sizeof(m->value.s), &slen, action);
1.19      tedu     1581:                if (*p == NULL) {
                   1582:                        if (ms->flags & MAGIC_CHECK)
1.25      chl      1583:                                file_magwarn(ms, "cannot get string from `%s'",
1.19      tedu     1584:                                    m->value.s);
                   1585:                        return -1;
                   1586:                }
1.1       deraadt  1587:                m->vallen = slen;
1.26      chl      1588:                if (m->type == FILE_PSTRING)
                   1589:                        m->vallen++;
                   1590:                return 0;
                   1591:        case FILE_FLOAT:
                   1592:        case FILE_BEFLOAT:
                   1593:        case FILE_LEFLOAT:
                   1594:                if (m->reln != 'x') {
                   1595:                        char *ep;
                   1596: #ifdef HAVE_STRTOF
                   1597:                        m->value.f = strtof(*p, &ep);
                   1598: #else
                   1599:                        m->value.f = (float)strtod(*p, &ep);
                   1600: #endif
                   1601:                        *p = ep;
                   1602:                }
                   1603:                return 0;
                   1604:        case FILE_DOUBLE:
                   1605:        case FILE_BEDOUBLE:
                   1606:        case FILE_LEDOUBLE:
                   1607:                if (m->reln != 'x') {
                   1608:                        char *ep;
                   1609:                        m->value.d = strtod(*p, &ep);
                   1610:                        *p = ep;
                   1611:                }
1.19      tedu     1612:                return 0;
                   1613:        default:
1.1       deraadt  1614:                if (m->reln != 'x') {
1.25      chl      1615:                        char *ep;
                   1616:                        m->value.q = file_signextend(ms, m,
                   1617:                            (uint64_t)strtoull(*p, &ep, 0));
                   1618:                        *p = ep;
1.1       deraadt  1619:                        eatsize(p);
                   1620:                }
1.19      tedu     1621:                return 0;
                   1622:        }
1.1       deraadt  1623: }
                   1624:
                   1625: /*
                   1626:  * Convert a string containing C character escapes.  Stop at an unescaped
                   1627:  * space or tab.
                   1628:  * Copy the converted version to "p", returning its length in *slen.
                   1629:  * Return updated scan pointer as function result.
                   1630:  */
1.25      chl      1631: private const char *
                   1632: getstr(struct magic_set *ms, const char *s, char *p, int plen, int *slen, int action)
1.1       deraadt  1633: {
1.25      chl      1634:        const char *origs = s;
                   1635:        char    *origp = p;
1.1       deraadt  1636:        char    *pmax = p + plen - 1;
1.11      mpech    1637:        int     c;
                   1638:        int     val;
1.1       deraadt  1639:
                   1640:        while ((c = *s++) != '\0') {
                   1641:                if (isspace((unsigned char) c))
                   1642:                        break;
                   1643:                if (p >= pmax) {
1.19      tedu     1644:                        file_error(ms, 0, "string too long: `%s'", origs);
                   1645:                        return NULL;
1.1       deraadt  1646:                }
1.25      chl      1647:                if (c == '\\') {
1.1       deraadt  1648:                        switch(c = *s++) {
                   1649:
                   1650:                        case '\0':
1.25      chl      1651:                                if (action == FILE_COMPILE)
                   1652:                                        file_magwarn(ms, "incomplete escape");
1.1       deraadt  1653:                                goto out;
                   1654:
1.25      chl      1655:                        case '\t':
                   1656:                                if (action == FILE_COMPILE) {
                   1657:                                        file_magwarn(ms,
                   1658:                                            "escaped tab found, use \\t instead");
                   1659:                                        action++;
                   1660:                                }
                   1661:                                /*FALLTHROUGH*/
1.1       deraadt  1662:                        default:
1.25      chl      1663:                                if (action == FILE_COMPILE) {
                   1664:                                        if (isprint((unsigned char)c))
                   1665:                                            file_magwarn(ms,
                   1666:                                                "no need to escape `%c'", c);
                   1667:                                        else
                   1668:                                            file_magwarn(ms,
                   1669:                                                "unknown escape sequence: \\%03o", c);
                   1670:                                }
                   1671:                                /*FALLTHROUGH*/
                   1672:                        /* space, perhaps force people to use \040? */
                   1673:                        case ' ':
                   1674: #if 0
                   1675:                        /*
                   1676:                         * Other things people escape, but shouldn't need to,
                   1677:                         * so we disallow them
                   1678:                         */
                   1679:                        case '\'':
                   1680:                        case '"':
                   1681:                        case '?':
                   1682: #endif
                   1683:                        /* Relations */
                   1684:                        case '>':
                   1685:                        case '<':
                   1686:                        case '&':
                   1687:                        case '^':
                   1688:                        case '=':
                   1689:                        case '!':
                   1690:                        /* and baskslash itself */
                   1691:                        case '\\':
1.1       deraadt  1692:                                *p++ = (char) c;
                   1693:                                break;
                   1694:
1.25      chl      1695:                        case 'a':
                   1696:                                *p++ = '\a';
                   1697:                                break;
                   1698:
                   1699:                        case 'b':
                   1700:                                *p++ = '\b';
                   1701:                                break;
                   1702:
                   1703:                        case 'f':
                   1704:                                *p++ = '\f';
                   1705:                                break;
                   1706:
1.1       deraadt  1707:                        case 'n':
                   1708:                                *p++ = '\n';
                   1709:                                break;
                   1710:
                   1711:                        case 'r':
                   1712:                                *p++ = '\r';
                   1713:                                break;
                   1714:
                   1715:                        case 't':
                   1716:                                *p++ = '\t';
                   1717:                                break;
                   1718:
                   1719:                        case 'v':
                   1720:                                *p++ = '\v';
                   1721:                                break;
                   1722:
                   1723:                        /* \ and up to 3 octal digits */
                   1724:                        case '0':
                   1725:                        case '1':
                   1726:                        case '2':
                   1727:                        case '3':
                   1728:                        case '4':
                   1729:                        case '5':
                   1730:                        case '6':
                   1731:                        case '7':
                   1732:                                val = c - '0';
                   1733:                                c = *s++;  /* try for 2 */
1.25      chl      1734:                                if (c >= '0' && c <= '7') {
                   1735:                                        val = (val << 3) | (c - '0');
1.1       deraadt  1736:                                        c = *s++;  /* try for 3 */
1.25      chl      1737:                                        if (c >= '0' && c <= '7')
                   1738:                                                val = (val << 3) | (c-'0');
1.1       deraadt  1739:                                        else
                   1740:                                                --s;
                   1741:                                }
                   1742:                                else
                   1743:                                        --s;
                   1744:                                *p++ = (char)val;
                   1745:                                break;
                   1746:
1.4       millert  1747:                        /* \x and up to 2 hex digits */
1.1       deraadt  1748:                        case 'x':
                   1749:                                val = 'x';      /* Default if no digits */
                   1750:                                c = hextoint(*s++);     /* Get next char */
                   1751:                                if (c >= 0) {
                   1752:                                        val = c;
                   1753:                                        c = hextoint(*s++);
1.4       millert  1754:                                        if (c >= 0)
1.1       deraadt  1755:                                                val = (val << 4) + c;
1.4       millert  1756:                                        else
1.1       deraadt  1757:                                                --s;
                   1758:                                } else
                   1759:                                        --s;
                   1760:                                *p++ = (char)val;
                   1761:                                break;
                   1762:                        }
                   1763:                } else
                   1764:                        *p++ = (char)c;
                   1765:        }
                   1766: out:
                   1767:        *p = '\0';
                   1768:        *slen = p - origp;
                   1769:        return s;
                   1770: }
                   1771:
                   1772:
                   1773: /* Single hex char to int; -1 if not a hex char. */
1.19      tedu     1774: private int
                   1775: hextoint(int c)
                   1776: {
                   1777:        if (!isascii((unsigned char) c))
                   1778:                return -1;
                   1779:        if (isdigit((unsigned char) c))
                   1780:                return c - '0';
1.25      chl      1781:        if ((c >= 'a') && (c <= 'f'))
1.19      tedu     1782:                return c + 10 - 'a';
1.25      chl      1783:        if (( c>= 'A') && (c <= 'F'))
1.19      tedu     1784:                return c + 10 - 'A';
                   1785:        return -1;
1.1       deraadt  1786: }
                   1787:
                   1788:
                   1789: /*
                   1790:  * Print a string containing C character escapes.
                   1791:  */
1.19      tedu     1792: protected void
                   1793: file_showstr(FILE *fp, const char *s, size_t len)
1.1       deraadt  1794: {
1.11      mpech    1795:        char    c;
1.1       deraadt  1796:
                   1797:        for (;;) {
                   1798:                c = *s++;
1.19      tedu     1799:                if (len == ~0U) {
1.1       deraadt  1800:                        if (c == '\0')
                   1801:                                break;
                   1802:                }
                   1803:                else  {
                   1804:                        if (len-- == 0)
                   1805:                                break;
                   1806:                }
1.25      chl      1807:                if (c >= 040 && c <= 0176)      /* TODO isprint && !iscntrl */
1.1       deraadt  1808:                        (void) fputc(c, fp);
                   1809:                else {
                   1810:                        (void) fputc('\\', fp);
                   1811:                        switch (c) {
1.25      chl      1812:                        case '\a':
                   1813:                                (void) fputc('a', fp);
                   1814:                                break;
                   1815:
                   1816:                        case '\b':
                   1817:                                (void) fputc('b', fp);
                   1818:                                break;
                   1819:
                   1820:                        case '\f':
                   1821:                                (void) fputc('f', fp);
                   1822:                                break;
                   1823:
1.1       deraadt  1824:                        case '\n':
                   1825:                                (void) fputc('n', fp);
                   1826:                                break;
                   1827:
                   1828:                        case '\r':
                   1829:                                (void) fputc('r', fp);
                   1830:                                break;
                   1831:
                   1832:                        case '\t':
                   1833:                                (void) fputc('t', fp);
                   1834:                                break;
                   1835:
                   1836:                        case '\v':
                   1837:                                (void) fputc('v', fp);
                   1838:                                break;
                   1839:
                   1840:                        default:
                   1841:                                (void) fprintf(fp, "%.3o", c & 0377);
                   1842:                                break;
                   1843:                        }
                   1844:                }
                   1845:        }
                   1846: }
                   1847:
                   1848: /*
                   1849:  * eatsize(): Eat the size spec from a number [eg. 10UL]
                   1850:  */
1.19      tedu     1851: private void
1.25      chl      1852: eatsize(const char **p)
1.1       deraadt  1853: {
1.25      chl      1854:        const char *l = *p;
1.1       deraadt  1855:
                   1856:        if (LOWCASE(*l) == 'u')
                   1857:                l++;
                   1858:
                   1859:        switch (LOWCASE(*l)) {
                   1860:        case 'l':    /* long */
                   1861:        case 's':    /* short */
                   1862:        case 'h':    /* short */
                   1863:        case 'b':    /* char/byte */
                   1864:        case 'c':    /* char/byte */
                   1865:                l++;
                   1866:                /*FALLTHROUGH*/
                   1867:        default:
                   1868:                break;
                   1869:        }
                   1870:
                   1871:        *p = l;
1.19      tedu     1872: }
                   1873:
                   1874: /*
                   1875:  * handle a compiled file.
                   1876:  */
                   1877: private int
                   1878: apprentice_map(struct magic_set *ms, struct magic **magicp, uint32_t *nmagicp,
                   1879:     const char *fn)
                   1880: {
                   1881:        int fd;
                   1882:        struct stat st;
                   1883:        uint32_t *ptr;
                   1884:        uint32_t version;
                   1885:        int needsbyteswap;
1.26      chl      1886:        char *dbname = NULL;
1.19      tedu     1887:        void *mm = NULL;
                   1888:
1.26      chl      1889:        mkdbname(fn, &dbname, 0);
1.19      tedu     1890:        if (dbname == NULL)
1.26      chl      1891:                goto error2;
1.19      tedu     1892:
1.25      chl      1893:        if ((fd = open(dbname, O_RDONLY|O_BINARY)) == -1)
1.26      chl      1894:                goto error2;
1.19      tedu     1895:
                   1896:        if (fstat(fd, &st) == -1) {
                   1897:                file_error(ms, errno, "cannot stat `%s'", dbname);
1.26      chl      1898:                goto error1;
1.19      tedu     1899:        }
1.26      chl      1900:        if (st.st_size < 8) {
1.19      tedu     1901:                file_error(ms, 0, "file `%s' is too small", dbname);
1.26      chl      1902:                goto error1;
1.19      tedu     1903:        }
                   1904:
                   1905: #ifdef QUICK
                   1906:        if ((mm = mmap(0, (size_t)st.st_size, PROT_READ|PROT_WRITE,
                   1907:            MAP_PRIVATE|MAP_FILE, fd, (off_t)0)) == MAP_FAILED) {
                   1908:                file_error(ms, errno, "cannot map `%s'", dbname);
1.26      chl      1909:                goto error1;
1.19      tedu     1910:        }
                   1911: #define RET    2
                   1912: #else
                   1913:        if ((mm = malloc((size_t)st.st_size)) == NULL) {
1.25      chl      1914:                file_oomem(ms, (size_t)st.st_size);
1.26      chl      1915:                goto error1;
1.19      tedu     1916:        }
                   1917:        if (read(fd, mm, (size_t)st.st_size) != (size_t)st.st_size) {
                   1918:                file_badread(ms);
1.26      chl      1919:                goto error1;
1.19      tedu     1920:        }
                   1921: #define RET    1
                   1922: #endif
                   1923:        *magicp = mm;
                   1924:        (void)close(fd);
                   1925:        fd = -1;
                   1926:        ptr = (uint32_t *)(void *)*magicp;
                   1927:        if (*ptr != MAGICNO) {
                   1928:                if (swap4(*ptr) != MAGICNO) {
                   1929:                        file_error(ms, 0, "bad magic in `%s'");
1.26      chl      1930:                        goto error1;
1.19      tedu     1931:                }
                   1932:                needsbyteswap = 1;
                   1933:        } else
                   1934:                needsbyteswap = 0;
                   1935:        if (needsbyteswap)
                   1936:                version = swap4(ptr[1]);
                   1937:        else
                   1938:                version = ptr[1];
                   1939:        if (version != VERSIONNO) {
1.26      chl      1940:                file_error(ms, 0, "File %d.%d supports only %d version magic "
                   1941:                    "files. `%s' is version %d", FILE_VERSION_MAJOR, patchlevel,
                   1942:                    VERSIONNO, dbname, version);
                   1943:                goto error1;
                   1944:        }
                   1945:        *nmagicp = (uint32_t)(st.st_size / sizeof(struct magic));
                   1946:        if (*nmagicp > 0)
                   1947:                (*nmagicp)--;
1.19      tedu     1948:        (*magicp)++;
                   1949:        if (needsbyteswap)
                   1950:                byteswap(*magicp, *nmagicp);
1.26      chl      1951:        free(dbname);
1.19      tedu     1952:        return RET;
                   1953:
1.26      chl      1954: error1:
1.19      tedu     1955:        if (fd != -1)
                   1956:                (void)close(fd);
                   1957:        if (mm) {
                   1958: #ifdef QUICK
                   1959:                (void)munmap((void *)mm, (size_t)st.st_size);
                   1960: #else
                   1961:                free(mm);
                   1962: #endif
                   1963:        } else {
                   1964:                *magicp = NULL;
                   1965:                *nmagicp = 0;
                   1966:        }
1.26      chl      1967: error2:
                   1968:        free(dbname);
1.19      tedu     1969:        return -1;
                   1970: }
                   1971:
                   1972: private const uint32_t ar[] = {
                   1973:     MAGICNO, VERSIONNO
                   1974: };
                   1975: /*
                   1976:  * handle an mmaped file.
                   1977:  */
                   1978: private int
                   1979: apprentice_compile(struct magic_set *ms, struct magic **magicp,
                   1980:     uint32_t *nmagicp, const char *fn)
                   1981: {
                   1982:        int fd;
1.26      chl      1983:        char *dbname;
                   1984:        int rv = -1;
                   1985:
                   1986:        mkdbname(fn, &dbname, 1);
1.19      tedu     1987:
                   1988:        if (dbname == NULL)
1.26      chl      1989:                goto out;
1.19      tedu     1990:
1.25      chl      1991:        if ((fd = open(dbname, O_WRONLY|O_CREAT|O_TRUNC|O_BINARY, 0644)) == -1) {
1.19      tedu     1992:                file_error(ms, errno, "cannot open `%s'", dbname);
1.26      chl      1993:                goto out;
1.19      tedu     1994:        }
                   1995:
                   1996:        if (write(fd, ar, sizeof(ar)) != (ssize_t)sizeof(ar)) {
                   1997:                file_error(ms, errno, "error writing `%s'", dbname);
1.26      chl      1998:                goto out;
1.19      tedu     1999:        }
                   2000:
                   2001:        if (lseek(fd, (off_t)sizeof(struct magic), SEEK_SET)
                   2002:            != sizeof(struct magic)) {
                   2003:                file_error(ms, errno, "error seeking `%s'", dbname);
1.26      chl      2004:                goto out;
1.19      tedu     2005:        }
                   2006:
                   2007:        if (write(fd, *magicp, (sizeof(struct magic) * *nmagicp))
                   2008:            != (ssize_t)(sizeof(struct magic) * *nmagicp)) {
                   2009:                file_error(ms, errno, "error writing `%s'", dbname);
1.26      chl      2010:                goto out;
1.19      tedu     2011:        }
                   2012:
                   2013:        (void)close(fd);
1.26      chl      2014:        rv = 0;
                   2015: out:
                   2016:        free(dbname);
                   2017:        return rv;
1.19      tedu     2018: }
                   2019:
                   2020: private const char ext[] = ".mgc";
                   2021: /*
                   2022:  * make a dbname
                   2023:  */
1.26      chl      2024: private void
                   2025: mkdbname(const char *fn, char **buf, int strip)
1.19      tedu     2026: {
1.25      chl      2027:        if (strip) {
                   2028:                const char *p;
                   2029:                if ((p = strrchr(fn, '/')) != NULL)
                   2030:                        fn = ++p;
                   2031:        }
                   2032:
1.26      chl      2033:        (void)asprintf(buf, "%s%s", fn, ext);
                   2034:        if (*buf && strlen(*buf) > MAXPATHLEN) {
                   2035:                free(*buf);
                   2036:                *buf = NULL;
                   2037:        }
1.19      tedu     2038: }
                   2039:
                   2040: /*
                   2041:  * Byteswap an mmap'ed file if needed
                   2042:  */
                   2043: private void
                   2044: byteswap(struct magic *magic, uint32_t nmagic)
                   2045: {
                   2046:        uint32_t i;
                   2047:        for (i = 0; i < nmagic; i++)
                   2048:                bs1(&magic[i]);
                   2049: }
                   2050:
                   2051: /*
                   2052:  * swap a short
                   2053:  */
                   2054: private uint16_t
                   2055: swap2(uint16_t sv)
                   2056: {
                   2057:        uint16_t rv;
                   2058:        uint8_t *s = (uint8_t *)(void *)&sv;
                   2059:        uint8_t *d = (uint8_t *)(void *)&rv;
                   2060:        d[0] = s[1];
                   2061:        d[1] = s[0];
                   2062:        return rv;
                   2063: }
                   2064:
                   2065: /*
                   2066:  * swap an int
                   2067:  */
                   2068: private uint32_t
                   2069: swap4(uint32_t sv)
                   2070: {
                   2071:        uint32_t rv;
                   2072:        uint8_t *s = (uint8_t *)(void *)&sv;
                   2073:        uint8_t *d = (uint8_t *)(void *)&rv;
                   2074:        d[0] = s[3];
                   2075:        d[1] = s[2];
                   2076:        d[2] = s[1];
                   2077:        d[3] = s[0];
                   2078:        return rv;
                   2079: }
                   2080:
                   2081: /*
1.25      chl      2082:  * swap a quad
                   2083:  */
                   2084: private uint64_t
                   2085: swap8(uint64_t sv)
                   2086: {
                   2087:        uint32_t rv;
                   2088:        uint8_t *s = (uint8_t *)(void *)&sv;
                   2089:        uint8_t *d = (uint8_t *)(void *)&rv;
1.26      chl      2090: #if 0
1.25      chl      2091:        d[0] = s[3];
                   2092:        d[1] = s[2];
                   2093:        d[2] = s[1];
                   2094:        d[3] = s[0];
                   2095:        d[4] = s[7];
                   2096:        d[5] = s[6];
                   2097:        d[6] = s[5];
                   2098:        d[7] = s[4];
1.26      chl      2099: #else
                   2100:        d[0] = s[7];
                   2101:        d[1] = s[6];
                   2102:        d[2] = s[5];
                   2103:        d[3] = s[4];
                   2104:        d[4] = s[3];
                   2105:        d[5] = s[2];
                   2106:        d[6] = s[1];
                   2107:        d[7] = s[0];
                   2108: #endif
1.25      chl      2109:        return rv;
                   2110: }
                   2111:
                   2112: /*
1.19      tedu     2113:  * byteswap a single magic entry
                   2114:  */
                   2115: private void
                   2116: bs1(struct magic *m)
                   2117: {
                   2118:        m->cont_level = swap2(m->cont_level);
                   2119:        m->offset = swap4((uint32_t)m->offset);
                   2120:        m->in_offset = swap4((uint32_t)m->in_offset);
1.25      chl      2121:        m->lineno = swap4((uint32_t)m->lineno);
                   2122:        if (IS_STRING(m->type)) {
1.26      chl      2123:                m->str_range = swap4(m->str_range);
1.25      chl      2124:                m->str_flags = swap4(m->str_flags);
                   2125:        }
                   2126:        else {
                   2127:                m->value.q = swap8(m->value.q);
                   2128:                m->num_mask = swap8(m->num_mask);
                   2129:        }
1.1       deraadt  2130: }