[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.32

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