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

1.20    ! otto        1: /*     $OpenBSD: apprentice.c,v 1.19 2004/05/19 02:32:35 tedu 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.19      tedu       33: #include "file.h"
                     34: #include "magic.h"
1.1       deraadt    35: #include <stdlib.h>
1.19      tedu       36: #ifdef HAVE_UNISTD_H
                     37: #include <unistd.h>
                     38: #endif
1.1       deraadt    39: #include <string.h>
                     40: #include <ctype.h>
1.19      tedu       41: #include <fcntl.h>
                     42: #include <sys/stat.h>
                     43: #include <sys/param.h>
                     44: #ifdef QUICK
                     45: #include <sys/mman.h>
                     46: #endif
1.1       deraadt    47:
                     48: #ifndef        lint
1.20    ! otto       49: FILE_RCSID("@(#)$Id: apprentice.c,v 1.19 2004/05/19 02:32:35 tedu Exp $")
1.1       deraadt    50: #endif /* lint */
                     51:
                     52: #define        EATAB {while (isascii((unsigned char) *l) && \
                     53:                      isspace((unsigned char) *l))  ++l;}
                     54: #define LOWCASE(l) (isupper((unsigned char) (l)) ? \
                     55:                        tolower((unsigned char) (l)) : (l))
1.19      tedu       56: /*
                     57:  * Work around a bug in headers on Digital Unix.
                     58:  * At least confirmed for: OSF1 V4.0 878
                     59:  */
                     60: #if defined(__osf__) && defined(__DECC)
                     61: #ifdef MAP_FAILED
                     62: #undef MAP_FAILED
                     63: #endif
                     64: #endif
                     65:
                     66: #ifndef MAP_FAILED
                     67: #define MAP_FAILED (void *) -1
                     68: #endif
                     69:
                     70: #ifndef MAP_FILE
                     71: #define MAP_FILE 0
                     72: #endif
                     73:
                     74: #ifndef MAXPATHLEN
                     75: #define MAXPATHLEN     1024
                     76: #endif
                     77:
                     78: private int getvalue(struct magic_set *ms, struct magic *, char **);
                     79: private int hextoint(int);
                     80: private char *getstr(struct magic_set *, char *, char *, int, int *);
                     81: private int parse(struct magic_set *, struct magic **, uint32_t *, char *, int);
                     82: private void eatsize(char **);
                     83: private int apprentice_1(struct magic_set *, const char *, int, struct mlist *);
                     84: private int apprentice_file(struct magic_set *, struct magic **, uint32_t *,
                     85:     const char *, int);
                     86: private void byteswap(struct magic *, uint32_t);
                     87: private void bs1(struct magic *);
                     88: private uint16_t swap2(uint16_t);
                     89: private uint32_t swap4(uint32_t);
                     90: private char *mkdbname(const char *, char *, size_t);
                     91: private int apprentice_map(struct magic_set *, struct magic **, uint32_t *,
                     92:     const char *);
                     93: private int apprentice_compile(struct magic_set *, struct magic **, uint32_t *,
                     94:     const char *);
                     95:
                     96: private size_t maxmagic = 0;
                     97: private size_t magicsize = sizeof(struct magic);
                     98:
                     99: #ifdef COMPILE_ONLY
                    100: const char *magicfile;
                    101: char *progname;
                    102: int lineno;
                    103:
                    104: int main(int, char *[]);
                    105:
                    106: int
                    107: main(int argc, char *argv[])
                    108: {
                    109:        int ret;
                    110:
                    111:        if ((progname = strrchr(argv[0], '/')) != NULL)
                    112:                progname++;
                    113:        else
                    114:                progname = argv[0];
                    115:
                    116:        if (argc != 2) {
                    117:                (void)fprintf(stderr, "usage: %s file\n", progname);
                    118:                exit(1);
                    119:        }
                    120:        magicfile = argv[1];
                    121:
                    122:        exit(file_apprentice(magicfile, COMPILE, MAGIC_CHECK) == -1 ? 1 : 0);
                    123: }
                    124: #endif /* COMPILE_ONLY */
                    125:
                    126:
                    127: /*
                    128:  * Handle one file.
                    129:  */
                    130: private int
                    131: apprentice_1(struct magic_set *ms, const char *fn, int action,
                    132:     struct mlist *mlist)
                    133: {
                    134:        struct magic *magic = NULL;
                    135:        uint32_t nmagic = 0;
                    136:        struct mlist *ml;
                    137:        int rv = -1;
                    138:        int mapped;
                    139:
                    140:        if (magicsize != FILE_MAGICSIZE) {
                    141:                file_error(ms, 0, "magic element size %lu != %lu",
                    142:                    (unsigned long)sizeof(*magic),
                    143:                    (unsigned long)FILE_MAGICSIZE);
                    144:                return -1;
                    145:        }
1.1       deraadt   146:
1.19      tedu      147:        if (action == FILE_COMPILE) {
                    148:                rv = apprentice_file(ms, &magic, &nmagic, fn, action);
                    149:                if (rv != 0)
                    150:                        return -1;
                    151:                rv = apprentice_compile(ms, &magic, &nmagic, fn);
                    152:                free(magic);
                    153:                return rv;
                    154:        }
                    155: #ifndef COMPILE_ONLY
                    156:        if ((rv = apprentice_map(ms, &magic, &nmagic, fn)) == -1) {
                    157:                if (ms->flags & MAGIC_CHECK)
                    158:                        file_magwarn("using regular magic file `%s'", fn);
                    159:                rv = apprentice_file(ms, &magic, &nmagic, fn, action);
                    160:                if (rv != 0)
                    161:                        return -1;
                    162:                mapped = 0;
                    163:        }
1.1       deraadt   164:
1.19      tedu      165:        if (rv == -1)
                    166:                return rv;
                    167:        mapped = rv;
                    168:
                    169:        if (magic == NULL || nmagic == 0) {
                    170:                file_delmagic(magic, mapped, nmagic);
                    171:                return -1;
                    172:        }
1.1       deraadt   173:
1.19      tedu      174:        if ((ml = malloc(sizeof(*ml))) == NULL) {
                    175:                file_delmagic(magic, mapped, nmagic);
                    176:                file_oomem(ms);
                    177:                return -1;
                    178:        }
1.1       deraadt   179:
1.19      tedu      180:        ml->magic = magic;
                    181:        ml->nmagic = nmagic;
                    182:        ml->mapped = mapped;
                    183:
                    184:        mlist->prev->next = ml;
                    185:        ml->prev = mlist->prev;
                    186:        ml->next = mlist;
                    187:        mlist->prev = ml;
1.1       deraadt   188:
1.19      tedu      189:        return 0;
                    190: #endif /* COMPILE_ONLY */
                    191: }
                    192:
                    193: protected void
                    194: file_delmagic(struct magic *p, int type, size_t entries)
                    195: {
                    196:        if (p == NULL)
                    197:                return;
                    198:        switch (type) {
                    199:        case 2:
                    200:                p--;
                    201:                (void)munmap((void *)p, sizeof(*p) * (entries + 1));
                    202:                break;
                    203:        case 1:
                    204:                p--;
                    205:        case 0:
                    206:                free(p);
                    207:                break;
                    208:        default:
                    209:                abort();
                    210:        }
                    211: }
                    212:
                    213:
                    214: /* const char *fn: list of magic files */
                    215: protected struct mlist *
                    216: file_apprentice(struct magic_set *ms, const char *fn, int action)
1.2       deraadt   217: {
1.19      tedu      218:        char *p, *mfn, *afn = NULL;
1.2       deraadt   219:        int file_err, errs = -1;
1.19      tedu      220:        struct mlist *mlist;
1.2       deraadt   221:
1.19      tedu      222:        if (fn == NULL)
                    223:                fn = getenv("MAGIC");
                    224:        if (fn == NULL)
                    225:                fn = MAGIC;
                    226:
                    227:        if ((fn = mfn = strdup(fn)) == NULL) {
                    228:                file_oomem(ms);
                    229:                return NULL;
                    230:        }
                    231:
                    232:        if ((mlist = malloc(sizeof(*mlist))) == NULL) {
                    233:                free(mfn);
                    234:                file_oomem(ms);
                    235:                return NULL;
1.2       deraadt   236:        }
1.19      tedu      237:        mlist->next = mlist->prev = mlist;
1.17      deraadt   238:
1.2       deraadt   239:        while (fn) {
1.19      tedu      240:                p = strchr(fn, PATHSEP);
1.2       deraadt   241:                if (p)
                    242:                        *p++ = '\0';
1.19      tedu      243:                if (*fn == '\0')
                    244:                        break;
                    245:                if (ms->flags & MAGIC_MIME) {
                    246:                        size_t len = strlen(fn) + 5 + 1;
                    247:                        if ((afn = malloc(len)) == NULL) {
                    248:                                free(mfn);
                    249:                                free(mlist);
                    250:                                file_oomem(ms);
                    251:                                return NULL;
                    252:                        }
                    253:                        (void)strlcpy(afn, fn, len);
                    254:                        (void)strlcat(afn, ".mime", len);
                    255:                        fn = afn;
                    256:                }
                    257:                file_err = apprentice_1(ms, fn, action, mlist);
1.2       deraadt   258:                if (file_err > errs)
                    259:                        errs = file_err;
1.19      tedu      260:                if (afn) {
                    261:                        free(afn);
                    262:                        afn = NULL;
                    263:                }
1.2       deraadt   264:                fn = p;
                    265:        }
1.19      tedu      266:        if (errs == -1) {
                    267:                free(mfn);
                    268:                free(mlist);
                    269:                mlist = NULL;
                    270:                file_error(ms, 0, "could not find any magic files!");
                    271:                return NULL;
                    272:        }
1.2       deraadt   273:        free(mfn);
1.19      tedu      274:        return mlist;
1.2       deraadt   275: }
                    276:
1.19      tedu      277: /*
                    278:  * parse from a file
                    279:  * const char *fn: name of magic file
                    280:  */
                    281: private int
                    282: apprentice_file(struct magic_set *ms, struct magic **magicp, uint32_t *nmagicp,
                    283:     const char *fn, int action)
1.1       deraadt   284: {
1.19      tedu      285:        private const char hdr[] =
1.2       deraadt   286:                "cont\toffset\ttype\topcode\tmask\tvalue\tdesc";
1.1       deraadt   287:        FILE *f;
1.20    ! otto      288:        char line[BUFSIZ];
1.19      tedu      289:        int lineno;
1.1       deraadt   290:        int errs = 0;
                    291:
                    292:        f = fopen(fn, "r");
1.19      tedu      293:        if (f == NULL) {
1.2       deraadt   294:                if (errno != ENOENT)
1.19      tedu      295:                        file_error(ms, errno, "cannot read magic file `%s'",
                    296:                            fn);
1.2       deraadt   297:                return -1;
1.1       deraadt   298:        }
                    299:
1.19      tedu      300:         maxmagic = MAXMAGIS;
                    301:        *magicp = (struct magic *) calloc(maxmagic, sizeof(struct magic));
                    302:        if (*magicp == NULL) {
                    303:                (void)fclose(f);
                    304:                file_oomem(ms);
                    305:                return -1;
                    306:        }
                    307:
                    308:        /* print silly verbose header for USG compat. */
                    309:        if (action == FILE_CHECK)
                    310:                (void)fprintf(stderr, "%s\n", hdr);
                    311:
1.1       deraadt   312:        /* parse it */
1.20    ! otto      313:        for (lineno = 1; fgets(line, sizeof(line), f) != NULL; lineno++) {
1.1       deraadt   314:                if (line[0]=='#')       /* comment, do not parse */
                    315:                        continue;
                    316:                if (strlen(line) <= (unsigned)1) /* null line, garbage, etc */
                    317:                        continue;
                    318:                line[strlen(line)-1] = '\0'; /* delete newline */
1.19      tedu      319:                if (parse(ms, magicp, nmagicp, line, action) != 0)
1.2       deraadt   320:                        errs = 1;
1.1       deraadt   321:        }
                    322:
1.19      tedu      323:        (void)fclose(f);
                    324:        if (errs) {
                    325:                free(*magicp);
                    326:                *magicp = NULL;
                    327:                *nmagicp = 0;
                    328:        }
1.2       deraadt   329:        return errs;
1.1       deraadt   330: }
                    331:
                    332: /*
                    333:  * extend the sign bit if the comparison is to be signed
                    334:  */
1.19      tedu      335: protected uint32_t
                    336: file_signextend(struct magic_set *ms, struct magic *m, uint32_t v)
1.1       deraadt   337: {
                    338:        if (!(m->flag & UNSIGNED))
                    339:                switch(m->type) {
                    340:                /*
                    341:                 * Do not remove the casts below.  They are
                    342:                 * vital.  When later compared with the data,
                    343:                 * the sign extension must have happened.
                    344:                 */
1.19      tedu      345:                case FILE_BYTE:
1.1       deraadt   346:                        v = (char) v;
                    347:                        break;
1.19      tedu      348:                case FILE_SHORT:
                    349:                case FILE_BESHORT:
                    350:                case FILE_LESHORT:
1.1       deraadt   351:                        v = (short) v;
                    352:                        break;
1.19      tedu      353:                case FILE_DATE:
                    354:                case FILE_BEDATE:
                    355:                case FILE_LEDATE:
                    356:                case FILE_LDATE:
                    357:                case FILE_BELDATE:
                    358:                case FILE_LELDATE:
                    359:                case FILE_LONG:
                    360:                case FILE_BELONG:
                    361:                case FILE_LELONG:
1.14      itojun    362:                        v = (int32_t) v;
1.1       deraadt   363:                        break;
1.19      tedu      364:                case FILE_STRING:
                    365:                case FILE_PSTRING:
                    366:                        break;
                    367:                case FILE_REGEX:
1.1       deraadt   368:                        break;
                    369:                default:
1.19      tedu      370:                        if (ms->flags & MAGIC_CHECK)
                    371:                            file_magwarn("cannot happen: m->type=%d\n",
                    372:                                    m->type);
                    373:                        return ~0U;
1.1       deraadt   374:                }
                    375:        return v;
                    376: }
                    377:
                    378: /*
                    379:  * parse one line from magic file, put into magic[index++] if valid
                    380:  */
1.19      tedu      381: private int
                    382: parse(struct magic_set *ms, struct magic **magicp, uint32_t *nmagicp, char *l,
                    383:     int action)
1.1       deraadt   384: {
1.19      tedu      385:        int i = 0;
1.1       deraadt   386:        struct magic *m;
1.19      tedu      387:        char *t;
                    388:        private const char *fops = FILE_OPS;
                    389:        uint32_t val;
                    390:
                    391: #define ALLOC_INCR     200
                    392:        if (*nmagicp + 1 >= maxmagic){
                    393:                maxmagic += ALLOC_INCR;
                    394:                if ((m = (struct magic *) realloc(*magicp,
                    395:                    sizeof(struct magic) * maxmagic)) == NULL) {
                    396:                        file_oomem(ms);
                    397:                        if (*magicp)
                    398:                                free(*magicp);
1.1       deraadt   399:                        return -1;
1.19      tedu      400:                }
                    401:                *magicp = m;
                    402:                memset(&(*magicp)[*nmagicp], 0, sizeof(struct magic)
                    403:                    * ALLOC_INCR);
1.1       deraadt   404:        }
1.19      tedu      405:        m = &(*magicp)[*nmagicp];
1.1       deraadt   406:        m->flag = 0;
                    407:        m->cont_level = 0;
                    408:
                    409:        while (*l == '>') {
                    410:                ++l;            /* step over */
                    411:                m->cont_level++;
                    412:        }
                    413:
                    414:        if (m->cont_level != 0 && *l == '(') {
                    415:                ++l;            /* step over */
                    416:                m->flag |= INDIR;
                    417:        }
1.4       millert   418:        if (m->cont_level != 0 && *l == '&') {
                    419:                 ++l;            /* step over */
1.19      tedu      420:                 m->flag |= OFFADD;
1.4       millert   421:         }
1.1       deraadt   422:
                    423:        /* get offset, then skip over it */
1.19      tedu      424:        m->offset = (uint32_t)strtoul(l, &t, 0);
1.1       deraadt   425:         if (l == t)
1.19      tedu      426:                if (ms->flags & MAGIC_CHECK)
                    427:                        file_magwarn("offset %s invalid", l);
1.1       deraadt   428:         l = t;
                    429:
                    430:        if (m->flag & INDIR) {
1.19      tedu      431:                m->in_type = FILE_LONG;
                    432:                m->in_offset = 0;
1.1       deraadt   433:                /*
                    434:                 * read [.lbs][+-]nnnnn)
                    435:                 */
                    436:                if (*l == '.') {
                    437:                        l++;
1.19      tedu      438:                        switch (*l) {
1.1       deraadt   439:                        case 'l':
1.19      tedu      440:                                m->in_type = FILE_LELONG;
                    441:                                break;
                    442:                        case 'L':
                    443:                                m->in_type = FILE_BELONG;
1.1       deraadt   444:                                break;
                    445:                        case 'h':
                    446:                        case 's':
1.19      tedu      447:                                m->in_type = FILE_LESHORT;
                    448:                                break;
                    449:                        case 'H':
                    450:                        case 'S':
                    451:                                m->in_type = FILE_BESHORT;
1.1       deraadt   452:                                break;
                    453:                        case 'c':
                    454:                        case 'b':
1.19      tedu      455:                        case 'C':
                    456:                        case 'B':
                    457:                                m->in_type = FILE_BYTE;
1.1       deraadt   458:                                break;
                    459:                        default:
1.19      tedu      460:                                if (ms->flags & MAGIC_CHECK)
                    461:                                        file_magwarn(
                    462:                                            "indirect offset type %c invalid",
                    463:                                            *l);
1.1       deraadt   464:                                break;
                    465:                        }
                    466:                        l++;
                    467:                }
1.19      tedu      468:                if (*l == '~') {
                    469:                        m->in_op = FILE_OPINVERSE;
                    470:                        l++;
                    471:                }
                    472:                switch (*l) {
                    473:                case '&':
                    474:                        m->in_op |= FILE_OPAND;
                    475:                        l++;
                    476:                        break;
                    477:                case '|':
                    478:                        m->in_op |= FILE_OPOR;
                    479:                        l++;
                    480:                        break;
                    481:                case '^':
                    482:                        m->in_op |= FILE_OPXOR;
                    483:                        l++;
                    484:                        break;
                    485:                case '+':
                    486:                        m->in_op |= FILE_OPADD;
                    487:                        l++;
                    488:                        break;
                    489:                case '-':
                    490:                        m->in_op |= FILE_OPMINUS;
                    491:                        l++;
                    492:                        break;
                    493:                case '*':
                    494:                        m->in_op |= FILE_OPMULTIPLY;
                    495:                        l++;
                    496:                        break;
                    497:                case '/':
                    498:                        m->in_op |= FILE_OPDIVIDE;
                    499:                        l++;
                    500:                        break;
                    501:                case '%':
                    502:                        m->in_op |= FILE_OPMODULO;
                    503:                        l++;
                    504:                        break;
1.1       deraadt   505:                }
1.19      tedu      506:                if (isdigit((unsigned char)*l))
                    507:                        m->in_offset = (uint32_t)strtoul(l, &t, 0);
1.1       deraadt   508:                else
                    509:                        t = l;
                    510:                if (*t++ != ')')
1.19      tedu      511:                        if (ms->flags & MAGIC_CHECK)
                    512:                                file_magwarn("missing ')' in indirect offset");
1.1       deraadt   513:                l = t;
                    514:        }
                    515:
                    516:
                    517:        while (isascii((unsigned char)*l) && isdigit((unsigned char)*l))
                    518:                ++l;
                    519:        EATAB;
                    520:
                    521: #define NBYTE          4
                    522: #define NSHORT         5
                    523: #define NLONG          4
                    524: #define NSTRING        6
                    525: #define NDATE          4
                    526: #define NBESHORT       7
                    527: #define NBELONG                6
                    528: #define NBEDATE                6
                    529: #define NLESHORT       7
                    530: #define NLELONG                6
                    531: #define NLEDATE                6
1.19      tedu      532: #define NPSTRING       7
                    533: #define NLDATE         5
                    534: #define NBELDATE       7
                    535: #define NLELDATE       7
                    536: #define NREGEX         5
1.1       deraadt   537:
                    538:        if (*l == 'u') {
                    539:                ++l;
                    540:                m->flag |= UNSIGNED;
                    541:        }
                    542:
                    543:        /* get type, skip it */
1.19      tedu      544:        if (strncmp(l, "char", NBYTE)==0) {     /* HP/UX compat */
                    545:                m->type = FILE_BYTE;
                    546:                l += NBYTE;
                    547:        } else if (strncmp(l, "byte", NBYTE)==0) {
                    548:                m->type = FILE_BYTE;
1.1       deraadt   549:                l += NBYTE;
                    550:        } else if (strncmp(l, "short", NSHORT)==0) {
1.19      tedu      551:                m->type = FILE_SHORT;
1.1       deraadt   552:                l += NSHORT;
                    553:        } else if (strncmp(l, "long", NLONG)==0) {
1.19      tedu      554:                m->type = FILE_LONG;
1.1       deraadt   555:                l += NLONG;
                    556:        } else if (strncmp(l, "string", NSTRING)==0) {
1.19      tedu      557:                m->type = FILE_STRING;
1.1       deraadt   558:                l += NSTRING;
                    559:        } else if (strncmp(l, "date", NDATE)==0) {
1.19      tedu      560:                m->type = FILE_DATE;
1.1       deraadt   561:                l += NDATE;
                    562:        } else if (strncmp(l, "beshort", NBESHORT)==0) {
1.19      tedu      563:                m->type = FILE_BESHORT;
1.1       deraadt   564:                l += NBESHORT;
                    565:        } else if (strncmp(l, "belong", NBELONG)==0) {
1.19      tedu      566:                m->type = FILE_BELONG;
1.1       deraadt   567:                l += NBELONG;
                    568:        } else if (strncmp(l, "bedate", NBEDATE)==0) {
1.19      tedu      569:                m->type = FILE_BEDATE;
1.1       deraadt   570:                l += NBEDATE;
                    571:        } else if (strncmp(l, "leshort", NLESHORT)==0) {
1.19      tedu      572:                m->type = FILE_LESHORT;
1.1       deraadt   573:                l += NLESHORT;
                    574:        } else if (strncmp(l, "lelong", NLELONG)==0) {
1.19      tedu      575:                m->type = FILE_LELONG;
1.1       deraadt   576:                l += NLELONG;
                    577:        } else if (strncmp(l, "ledate", NLEDATE)==0) {
1.19      tedu      578:                m->type = FILE_LEDATE;
1.1       deraadt   579:                l += NLEDATE;
1.19      tedu      580:        } else if (strncmp(l, "pstring", NPSTRING)==0) {
                    581:                m->type = FILE_PSTRING;
                    582:                l += NPSTRING;
                    583:        } else if (strncmp(l, "ldate", NLDATE)==0) {
                    584:                m->type = FILE_LDATE;
                    585:                l += NLDATE;
                    586:        } else if (strncmp(l, "beldate", NBELDATE)==0) {
                    587:                m->type = FILE_BELDATE;
                    588:                l += NBELDATE;
                    589:        } else if (strncmp(l, "leldate", NLELDATE)==0) {
                    590:                m->type = FILE_LELDATE;
                    591:                l += NLELDATE;
                    592:        } else if (strncmp(l, "regex", NREGEX)==0) {
                    593:                m->type = FILE_REGEX;
                    594:                l += sizeof("regex");
1.1       deraadt   595:        } else {
1.19      tedu      596:                if (ms->flags & MAGIC_CHECK)
                    597:                        file_magwarn("type %s invalid", l);
1.1       deraadt   598:                return -1;
                    599:        }
                    600:        /* New-style anding: "0 byte&0x80 =0x80 dynamically linked" */
1.19      tedu      601:        /* New and improved: ~ & | ^ + - * / % -- exciting, isn't it? */
                    602:        if (*l == '~') {
                    603:                if (FILE_STRING != m->type && FILE_PSTRING != m->type)
                    604:                        m->mask_op = FILE_OPINVERSE;
1.1       deraadt   605:                ++l;
1.19      tedu      606:        }
                    607:        if ((t = strchr(fops,  *l)) != NULL) {
                    608:                uint32_t op = (uint32_t)(t - fops);
                    609:                if (op != FILE_OPDIVIDE ||
                    610:                    (FILE_STRING != m->type && FILE_PSTRING != m->type)) {
                    611:                        ++l;
                    612:                        m->mask_op |= op;
                    613:                        val = (uint32_t)strtoul(l, &l, 0);
                    614:                        m->mask = file_signextend(ms, m, val);
                    615:                        eatsize(&l);
                    616:                } else {
                    617:                        m->mask = 0L;
                    618:                        while (!isspace((unsigned char)*++l)) {
                    619:                                switch (*l) {
                    620:                                case CHAR_IGNORE_LOWERCASE:
                    621:                                        m->mask |= STRING_IGNORE_LOWERCASE;
                    622:                                        break;
                    623:                                case CHAR_COMPACT_BLANK:
                    624:                                        m->mask |= STRING_COMPACT_BLANK;
                    625:                                        break;
                    626:                                case CHAR_COMPACT_OPTIONAL_BLANK:
                    627:                                        m->mask |=
                    628:                                            STRING_COMPACT_OPTIONAL_BLANK;
                    629:                                        break;
                    630:                                default:
                    631:                                        if (ms->flags & MAGIC_CHECK)
                    632:                                                file_magwarn(
                    633:                                                "string extension %c invalid",
                    634:                                                *l);
                    635:                                        return -1;
                    636:                                }
                    637:                        }
                    638:                }
                    639:        }
                    640:        /*
                    641:         * We used to set mask to all 1's here, instead let's just not do
                    642:         * anything if mask = 0 (unless you have a better idea)
                    643:         */
1.1       deraadt   644:        EATAB;
                    645:
                    646:        switch (*l) {
                    647:        case '>':
                    648:        case '<':
                    649:        /* Old-style anding: "0 byte &0x80 dynamically linked" */
                    650:        case '&':
                    651:        case '^':
                    652:        case '=':
                    653:                m->reln = *l;
                    654:                ++l;
1.19      tedu      655:                if (*l == '=') {
                    656:                   /* HP compat: ignore &= etc. */
                    657:                   ++l;
                    658:                }
1.1       deraadt   659:                break;
                    660:        case '!':
1.19      tedu      661:                if (m->type != FILE_STRING && m->type != FILE_PSTRING) {
1.1       deraadt   662:                        m->reln = *l;
                    663:                        ++l;
                    664:                        break;
                    665:                }
1.19      tedu      666:                /*FALLTHROUGH*/
1.1       deraadt   667:        default:
                    668:                if (*l == 'x' && isascii((unsigned char)l[1]) &&
                    669:                    isspace((unsigned char)l[1])) {
                    670:                        m->reln = *l;
                    671:                        ++l;
                    672:                        goto GetDesc;   /* Bill The Cat */
                    673:                }
                    674:                m->reln = '=';
                    675:                break;
                    676:        }
                    677:        EATAB;
                    678:
1.19      tedu      679:        if (getvalue(ms, m, &l))
1.1       deraadt   680:                return -1;
                    681:        /*
                    682:         * TODO finish this macro and start using it!
                    683:         * #define offsetcheck {if (offset > HOWMANY-1)
1.19      tedu      684:         *      magwarn("offset too big"); }
1.1       deraadt   685:         */
                    686:
                    687:        /*
                    688:         * now get last part - the description
                    689:         */
                    690: GetDesc:
                    691:        EATAB;
                    692:        if (l[0] == '\b') {
                    693:                ++l;
                    694:                m->nospflag = 1;
                    695:        } else if ((l[0] == '\\') && (l[1] == 'b')) {
                    696:                ++l;
                    697:                ++l;
                    698:                m->nospflag = 1;
                    699:        } else
                    700:                m->nospflag = 0;
1.19      tedu      701:        while ((m->desc[i++] = *l++) != '\0' && i < MAXDESC)
1.1       deraadt   702:                /* NULLBODY */;
                    703:
1.19      tedu      704: #ifndef COMPILE_ONLY
                    705:        if (action == FILE_CHECK) {
                    706:                file_mdump(m);
1.1       deraadt   707:        }
1.19      tedu      708: #endif
                    709:        ++(*nmagicp);           /* make room for next */
1.1       deraadt   710:        return 0;
                    711: }
                    712:
                    713: /*
                    714:  * Read a numeric value from a pointer, into the value union of a magic
                    715:  * pointer, according to the magic type.  Update the string pointer to point
                    716:  * just after the number read.  Return 0 for success, non-zero for failure.
                    717:  */
1.19      tedu      718: private int
                    719: getvalue(struct magic_set *ms, struct magic *m, char **p)
1.1       deraadt   720: {
                    721:        int slen;
                    722:
1.19      tedu      723:        switch (m->type) {
                    724:        case FILE_STRING:
                    725:        case FILE_PSTRING:
                    726:        case FILE_REGEX:
                    727:                *p = getstr(ms, *p, m->value.s, sizeof(m->value.s), &slen);
                    728:                if (*p == NULL) {
                    729:                        if (ms->flags & MAGIC_CHECK)
                    730:                                file_magwarn("cannot get string from `%s'",
                    731:                                    m->value.s);
                    732:                        return -1;
                    733:                }
1.1       deraadt   734:                m->vallen = slen;
1.19      tedu      735:                return 0;
                    736:        default:
1.1       deraadt   737:                if (m->reln != 'x') {
1.19      tedu      738:                        m->value.l = file_signextend(ms, m,
                    739:                            (uint32_t)strtoul(*p, p, 0));
1.1       deraadt   740:                        eatsize(p);
                    741:                }
1.19      tedu      742:                return 0;
                    743:        }
1.1       deraadt   744: }
                    745:
                    746: /*
                    747:  * Convert a string containing C character escapes.  Stop at an unescaped
                    748:  * space or tab.
                    749:  * Copy the converted version to "p", returning its length in *slen.
                    750:  * Return updated scan pointer as function result.
                    751:  */
1.19      tedu      752: private char *
                    753: getstr(struct magic_set *ms, char *s, char *p, int plen, int *slen)
1.1       deraadt   754: {
                    755:        char    *origs = s, *origp = p;
                    756:        char    *pmax = p + plen - 1;
1.11      mpech     757:        int     c;
                    758:        int     val;
1.1       deraadt   759:
                    760:        while ((c = *s++) != '\0') {
                    761:                if (isspace((unsigned char) c))
                    762:                        break;
                    763:                if (p >= pmax) {
1.19      tedu      764:                        file_error(ms, 0, "string too long: `%s'", origs);
                    765:                        return NULL;
1.1       deraadt   766:                }
                    767:                if(c == '\\') {
                    768:                        switch(c = *s++) {
                    769:
                    770:                        case '\0':
                    771:                                goto out;
                    772:
                    773:                        default:
                    774:                                *p++ = (char) c;
                    775:                                break;
                    776:
                    777:                        case 'n':
                    778:                                *p++ = '\n';
                    779:                                break;
                    780:
                    781:                        case 'r':
                    782:                                *p++ = '\r';
                    783:                                break;
                    784:
                    785:                        case 'b':
                    786:                                *p++ = '\b';
                    787:                                break;
                    788:
                    789:                        case 't':
                    790:                                *p++ = '\t';
                    791:                                break;
                    792:
                    793:                        case 'f':
                    794:                                *p++ = '\f';
                    795:                                break;
                    796:
                    797:                        case 'v':
                    798:                                *p++ = '\v';
                    799:                                break;
                    800:
                    801:                        /* \ and up to 3 octal digits */
                    802:                        case '0':
                    803:                        case '1':
                    804:                        case '2':
                    805:                        case '3':
                    806:                        case '4':
                    807:                        case '5':
                    808:                        case '6':
                    809:                        case '7':
                    810:                                val = c - '0';
                    811:                                c = *s++;  /* try for 2 */
                    812:                                if(c >= '0' && c <= '7') {
                    813:                                        val = (val<<3) | (c - '0');
                    814:                                        c = *s++;  /* try for 3 */
                    815:                                        if(c >= '0' && c <= '7')
                    816:                                                val = (val<<3) | (c-'0');
                    817:                                        else
                    818:                                                --s;
                    819:                                }
                    820:                                else
                    821:                                        --s;
                    822:                                *p++ = (char)val;
                    823:                                break;
                    824:
1.4       millert   825:                        /* \x and up to 2 hex digits */
1.1       deraadt   826:                        case 'x':
                    827:                                val = 'x';      /* Default if no digits */
                    828:                                c = hextoint(*s++);     /* Get next char */
                    829:                                if (c >= 0) {
                    830:                                        val = c;
                    831:                                        c = hextoint(*s++);
1.4       millert   832:                                        if (c >= 0)
1.1       deraadt   833:                                                val = (val << 4) + c;
1.4       millert   834:                                        else
1.1       deraadt   835:                                                --s;
                    836:                                } else
                    837:                                        --s;
                    838:                                *p++ = (char)val;
                    839:                                break;
                    840:                        }
                    841:                } else
                    842:                        *p++ = (char)c;
                    843:        }
                    844: out:
                    845:        *p = '\0';
                    846:        *slen = p - origp;
                    847:        return s;
                    848: }
                    849:
                    850:
                    851: /* Single hex char to int; -1 if not a hex char. */
1.19      tedu      852: private int
                    853: hextoint(int c)
                    854: {
                    855:        if (!isascii((unsigned char) c))
                    856:                return -1;
                    857:        if (isdigit((unsigned char) c))
                    858:                return c - '0';
                    859:        if ((c >= 'a')&&(c <= 'f'))
                    860:                return c + 10 - 'a';
                    861:        if (( c>= 'A')&&(c <= 'F'))
                    862:                return c + 10 - 'A';
                    863:        return -1;
1.1       deraadt   864: }
                    865:
                    866:
                    867: /*
                    868:  * Print a string containing C character escapes.
                    869:  */
1.19      tedu      870: protected void
                    871: file_showstr(FILE *fp, const char *s, size_t len)
1.1       deraadt   872: {
1.11      mpech     873:        char    c;
1.1       deraadt   874:
                    875:        for (;;) {
                    876:                c = *s++;
1.19      tedu      877:                if (len == ~0U) {
1.1       deraadt   878:                        if (c == '\0')
                    879:                                break;
                    880:                }
                    881:                else  {
                    882:                        if (len-- == 0)
                    883:                                break;
                    884:                }
                    885:                if(c >= 040 && c <= 0176)       /* TODO isprint && !iscntrl */
                    886:                        (void) fputc(c, fp);
                    887:                else {
                    888:                        (void) fputc('\\', fp);
                    889:                        switch (c) {
                    890:
                    891:                        case '\n':
                    892:                                (void) fputc('n', fp);
                    893:                                break;
                    894:
                    895:                        case '\r':
                    896:                                (void) fputc('r', fp);
                    897:                                break;
                    898:
                    899:                        case '\b':
                    900:                                (void) fputc('b', fp);
                    901:                                break;
                    902:
                    903:                        case '\t':
                    904:                                (void) fputc('t', fp);
                    905:                                break;
                    906:
                    907:                        case '\f':
                    908:                                (void) fputc('f', fp);
                    909:                                break;
                    910:
                    911:                        case '\v':
                    912:                                (void) fputc('v', fp);
                    913:                                break;
                    914:
                    915:                        default:
                    916:                                (void) fprintf(fp, "%.3o", c & 0377);
                    917:                                break;
                    918:                        }
                    919:                }
                    920:        }
                    921: }
                    922:
                    923: /*
                    924:  * eatsize(): Eat the size spec from a number [eg. 10UL]
                    925:  */
1.19      tedu      926: private void
                    927: eatsize(char **p)
1.1       deraadt   928: {
                    929:        char *l = *p;
                    930:
                    931:        if (LOWCASE(*l) == 'u')
                    932:                l++;
                    933:
                    934:        switch (LOWCASE(*l)) {
                    935:        case 'l':    /* long */
                    936:        case 's':    /* short */
                    937:        case 'h':    /* short */
                    938:        case 'b':    /* char/byte */
                    939:        case 'c':    /* char/byte */
                    940:                l++;
                    941:                /*FALLTHROUGH*/
                    942:        default:
                    943:                break;
                    944:        }
                    945:
                    946:        *p = l;
1.19      tedu      947: }
                    948:
                    949: /*
                    950:  * handle a compiled file.
                    951:  */
                    952: private int
                    953: apprentice_map(struct magic_set *ms, struct magic **magicp, uint32_t *nmagicp,
                    954:     const char *fn)
                    955: {
                    956:        int fd;
                    957:        struct stat st;
                    958:        uint32_t *ptr;
                    959:        uint32_t version;
                    960:        int needsbyteswap;
                    961:        char buf[MAXPATHLEN];
                    962:        char *dbname = mkdbname(fn, buf, sizeof(buf));
                    963:        void *mm = NULL;
                    964:
                    965:        if (dbname == NULL)
                    966:                return -1;
                    967:
                    968:        if ((fd = open(dbname, O_RDONLY)) == -1)
                    969:                return -1;
                    970:
                    971:        if (fstat(fd, &st) == -1) {
                    972:                file_error(ms, errno, "cannot stat `%s'", dbname);
                    973:                goto error;
                    974:        }
                    975:        if (st.st_size < 16) {
                    976:                file_error(ms, 0, "file `%s' is too small", dbname);
                    977:                goto error;
                    978:        }
                    979:
                    980: #ifdef QUICK
                    981:        if ((mm = mmap(0, (size_t)st.st_size, PROT_READ|PROT_WRITE,
                    982:            MAP_PRIVATE|MAP_FILE, fd, (off_t)0)) == MAP_FAILED) {
                    983:                file_error(ms, errno, "cannot map `%s'", dbname);
                    984:                goto error;
                    985:        }
                    986: #define RET    2
                    987: #else
                    988:        if ((mm = malloc((size_t)st.st_size)) == NULL) {
                    989:                file_oomem(ms);
                    990:                goto error;
                    991:        }
                    992:        if (read(fd, mm, (size_t)st.st_size) != (size_t)st.st_size) {
                    993:                file_badread(ms);
                    994:                goto error;
                    995:        }
                    996: #define RET    1
                    997: #endif
                    998:        *magicp = mm;
                    999:        (void)close(fd);
                   1000:        fd = -1;
                   1001:        ptr = (uint32_t *)(void *)*magicp;
                   1002:        if (*ptr != MAGICNO) {
                   1003:                if (swap4(*ptr) != MAGICNO) {
                   1004:                        file_error(ms, 0, "bad magic in `%s'");
                   1005:                        goto error;
                   1006:                }
                   1007:                needsbyteswap = 1;
                   1008:        } else
                   1009:                needsbyteswap = 0;
                   1010:        if (needsbyteswap)
                   1011:                version = swap4(ptr[1]);
                   1012:        else
                   1013:                version = ptr[1];
                   1014:        if (version != VERSIONNO) {
                   1015:                file_error(ms, 0, "version mismatch (%d != %d) in `%s'",
                   1016:                    version, VERSIONNO, dbname);
                   1017:                goto error;
                   1018:        }
                   1019:        *nmagicp = (uint32_t)(st.st_size / sizeof(struct magic)) - 1;
                   1020:        (*magicp)++;
                   1021:        if (needsbyteswap)
                   1022:                byteswap(*magicp, *nmagicp);
                   1023:        return RET;
                   1024:
                   1025: error:
                   1026:        if (fd != -1)
                   1027:                (void)close(fd);
                   1028:        if (mm) {
                   1029: #ifdef QUICK
                   1030:                (void)munmap((void *)mm, (size_t)st.st_size);
                   1031: #else
                   1032:                free(mm);
                   1033: #endif
                   1034:        } else {
                   1035:                *magicp = NULL;
                   1036:                *nmagicp = 0;
                   1037:        }
                   1038:        return -1;
                   1039: }
                   1040:
                   1041: private const uint32_t ar[] = {
                   1042:     MAGICNO, VERSIONNO
                   1043: };
                   1044: /*
                   1045:  * handle an mmaped file.
                   1046:  */
                   1047: private int
                   1048: apprentice_compile(struct magic_set *ms, struct magic **magicp,
                   1049:     uint32_t *nmagicp, const char *fn)
                   1050: {
                   1051:        int fd;
                   1052:        char buf[MAXPATHLEN];
                   1053:        char *dbname = mkdbname(fn, buf, sizeof(buf));
                   1054:
                   1055:        if (dbname == NULL)
                   1056:                return -1;
                   1057:
                   1058:        if ((fd = open(dbname, O_WRONLY|O_CREAT|O_TRUNC, 0644)) == -1) {
                   1059:                file_error(ms, errno, "cannot open `%s'", dbname);
                   1060:                return -1;
                   1061:        }
                   1062:
                   1063:        if (write(fd, ar, sizeof(ar)) != (ssize_t)sizeof(ar)) {
                   1064:                file_error(ms, errno, "error writing `%s'", dbname);
                   1065:                return -1;
                   1066:        }
                   1067:
                   1068:        if (lseek(fd, (off_t)sizeof(struct magic), SEEK_SET)
                   1069:            != sizeof(struct magic)) {
                   1070:                file_error(ms, errno, "error seeking `%s'", dbname);
                   1071:                return -1;
                   1072:        }
                   1073:
                   1074:        if (write(fd, *magicp, (sizeof(struct magic) * *nmagicp))
                   1075:            != (ssize_t)(sizeof(struct magic) * *nmagicp)) {
                   1076:                file_error(ms, errno, "error writing `%s'", dbname);
                   1077:                return -1;
                   1078:        }
                   1079:
                   1080:        (void)close(fd);
                   1081:        return 0;
                   1082: }
                   1083:
                   1084: private const char ext[] = ".mgc";
                   1085: /*
                   1086:  * make a dbname
                   1087:  */
                   1088: private char *
                   1089: mkdbname(const char *fn, char *buf, size_t bufsiz)
                   1090: {
                   1091: #ifdef notdef
                   1092:        const char *p;
                   1093:        if ((p = strrchr(fn, '/')) != NULL)
                   1094:                fn = ++p;
                   1095: #endif
                   1096:        (void)snprintf(buf, bufsiz, "%s%s", fn, ext);
                   1097:        return buf;
                   1098: }
                   1099:
                   1100: /*
                   1101:  * Byteswap an mmap'ed file if needed
                   1102:  */
                   1103: private void
                   1104: byteswap(struct magic *magic, uint32_t nmagic)
                   1105: {
                   1106:        uint32_t i;
                   1107:        for (i = 0; i < nmagic; i++)
                   1108:                bs1(&magic[i]);
                   1109: }
                   1110:
                   1111: /*
                   1112:  * swap a short
                   1113:  */
                   1114: private uint16_t
                   1115: swap2(uint16_t sv)
                   1116: {
                   1117:        uint16_t rv;
                   1118:        uint8_t *s = (uint8_t *)(void *)&sv;
                   1119:        uint8_t *d = (uint8_t *)(void *)&rv;
                   1120:        d[0] = s[1];
                   1121:        d[1] = s[0];
                   1122:        return rv;
                   1123: }
                   1124:
                   1125: /*
                   1126:  * swap an int
                   1127:  */
                   1128: private uint32_t
                   1129: swap4(uint32_t sv)
                   1130: {
                   1131:        uint32_t rv;
                   1132:        uint8_t *s = (uint8_t *)(void *)&sv;
                   1133:        uint8_t *d = (uint8_t *)(void *)&rv;
                   1134:        d[0] = s[3];
                   1135:        d[1] = s[2];
                   1136:        d[2] = s[1];
                   1137:        d[3] = s[0];
                   1138:        return rv;
                   1139: }
                   1140:
                   1141: /*
                   1142:  * byteswap a single magic entry
                   1143:  */
                   1144: private void
                   1145: bs1(struct magic *m)
                   1146: {
                   1147:        m->cont_level = swap2(m->cont_level);
                   1148:        m->offset = swap4((uint32_t)m->offset);
                   1149:        m->in_offset = swap4((uint32_t)m->in_offset);
                   1150:        if (m->type != FILE_STRING)
                   1151:                m->value.l = swap4(m->value.l);
                   1152:        m->mask = swap4(m->mask);
1.1       deraadt  1153: }