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

Annotation of src/usr.bin/cap_mkdb/getinfo.c, Revision 1.6

1.6     ! deraadt     1: /*     $OpenBSD: getinfo.c,v 1.5 2002/02/16 21:27:44 millert Exp $     */
1.1       tholo       2:
                      3: /*-
                      4:  * Copyright (c) 1992, 1993
                      5:  *     The Regents of the University of California.
                      6:  * Copyright (c) 1996 SigmaSoft, Th. Lockert <tholo@sigmasoft.com>
                      7:  * All rights reserved.
                      8:  *
                      9:  * Redistribution and use in source and binary forms, with or without
                     10:  * modification, are permitted provided that the following conditions
                     11:  * are met:
                     12:  * 1. Redistributions of source code must retain the above copyright
                     13:  *    notice, this list of conditions and the following disclaimer.
                     14:  * 2. Redistributions in binary form must reproduce the above copyright
                     15:  *    notice, this list of conditions and the following disclaimer in the
                     16:  *    documentation and/or other materials provided with the distribution.
                     17:  * 4. The name of the author may not be used to endorse or promote products
                     18:  *    derived from this software without specific prior written permission.
                     19:  *
                     20:  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
                     21:  * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
                     22:  * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
                     23:  * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
                     24:  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
                     25:  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
                     26:  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
                     27:  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
                     28:  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
                     29:  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
                     30:  */
                     31:
                     32: #ifndef lint
1.6     ! deraadt    33: static char rcsid[] = "$OpenBSD: getinfo.c,v 1.5 2002/02/16 21:27:44 millert Exp $";
1.1       tholo      34: #endif /* not lint */
                     35:
                     36: #include <sys/types.h>
                     37:
                     38: #include <ctype.h>
                     39: #include <errno.h>
                     40: #include <fcntl.h>
                     41: #include <limits.h>
                     42: #include <stdio.h>
                     43: #include <stdlib.h>
                     44: #include <string.h>
                     45: #include <unistd.h>
                     46:
                     47: #define        BFRAG           1024
                     48: #define        BSIZE           1024
                     49: #define        ESC             ('[' & 037)     /* ASCII ESC */
                     50: #define        MAX_RECURSION   32              /* maximum getent recursion */
                     51: #define        SFRAG           100             /* cgetstr mallocs in SFRAG chunks */
                     52:
                     53: #define RECOK  (char)0
                     54: #define TCERR  (char)1
                     55: #define        SHADOW  (char)2
                     56:
1.5       millert    57: static int      getent(char **, u_int *, char **, int, char *, int);
                     58: static char    *igetcap(char *, char *, int);
                     59: static int      igetmatch(char *, char *);
                     60: static int      igetclose(void);
1.1       tholo      61:
1.5       millert    62: int    igetnext(char **, char **);
1.1       tholo      63:
                     64: /*
                     65:  * Cgetcap searches the capability record buf for the capability cap with
                     66:  * type `type'.  A pointer to the value of cap is returned on success, NULL
                     67:  * if the requested capability couldn't be found.
                     68:  *
                     69:  * Specifying a type of ',' means that nothing should follow cap (,cap,).
                     70:  * In this case a pointer to the terminating ',' or NUL will be returned if
                     71:  * cap is found.
                     72:  *
                     73:  * If (cap, '@') or (cap, terminator, '@') is found before (cap, terminator)
                     74:  * return NULL.
                     75:  */
                     76: static char *
                     77: igetcap(buf, cap, type)
                     78:        char *buf, *cap;
                     79:        int type;
                     80: {
1.4       mpech      81:        char *bp, *cp;
1.1       tholo      82:
                     83:        bp = buf;
                     84:        for (;;) {
                     85:                /*
                     86:                 * Skip past the current capability field - it's either the
                     87:                 * name field if this is the first time through the loop, or
                     88:                 * the remainder of a field whose name failed to match cap.
                     89:                 */
                     90:                for (;;)
                     91:                        if (*bp == '\0')
                     92:                                return (NULL);
                     93:                        else
                     94:                                if (*bp++ == ',')
                     95:                                        break;
                     96:
                     97:                /*
                     98:                 * Try to match (cap, type) in buf.
                     99:                 */
                    100:                for (cp = cap; *cp == *bp && *bp != '\0'; cp++, bp++)
                    101:                        continue;
                    102:                if (*cp != '\0')
                    103:                        continue;
                    104:                if (*bp == '@')
                    105:                        return (NULL);
                    106:                if (type == ',') {
                    107:                        if (*bp != '\0' && *bp != ',')
                    108:                                continue;
                    109:                        return(bp);
                    110:                }
                    111:                if (*bp != type)
                    112:                        continue;
                    113:                bp++;
                    114:                return (*bp == '@' ? NULL : bp);
                    115:        }
                    116:        /* NOTREACHED */
                    117: }
                    118:
                    119: /*
                    120:  * Getent implements the functions of igetent.  If fd is non-negative,
                    121:  * *db_array has already been opened and fd is the open file descriptor.  We
                    122:  * do this to save time and avoid using up file descriptors for use=
                    123:  * recursions.
                    124:  *
                    125:  * Getent returns the same success/failure codes as igetent.  On success, a
                    126:  * pointer to a malloc'ed capability record with all use= capabilities fully
                    127:  * expanded and its length (not including trailing ASCII NUL) are left in
                    128:  * *cap and *len.
                    129:  *
                    130:  * Basic algorithm:
                    131:  *     + Allocate memory incrementally as needed in chunks of size BFRAG
                    132:  *       for capability buffer.
                    133:  *     + Recurse for each use=name and interpolate result.  Stop when all
                    134:  *       names interpolated, a name can't be found, or depth exceeds
                    135:  *       MAX_RECURSION.
                    136:  */
                    137: static int
                    138: getent(cap, len, db_array, fd, name, depth)
                    139:        char **cap, **db_array, *name;
                    140:        u_int *len;
                    141:        int fd, depth;
                    142: {
1.4       mpech     143:        char *r_end, *rp, **db_p;
1.1       tholo     144:        int myfd, eof, foundit;
                    145:        char *record;
                    146:        int tc_not_resolved;
                    147:
                    148:        /*
                    149:         * Return with ``loop detected'' error if we've recursed more than
                    150:         * MAX_RECURSION times.
                    151:         */
                    152:        if (depth > MAX_RECURSION)
                    153:                return (-3);
                    154:
                    155:        /*
                    156:         * Allocate first chunk of memory.
                    157:         */
                    158:        if ((record = malloc(BFRAG)) == NULL) {
                    159:                errno = ENOMEM;
                    160:                return (-2);
                    161:        }
                    162:        r_end = record + BFRAG;
                    163:        foundit = 0;
                    164:        rp = NULL;
                    165:        myfd = -1;
                    166:        /*
                    167:         * Loop through database array until finding the record.
                    168:         */
                    169:
                    170:        for (db_p = db_array; *db_p != NULL; db_p++) {
                    171:                eof = 0;
                    172:
                    173:                /*
                    174:                 * Open database if not already open.
                    175:                 */
                    176:
                    177:                if (fd >= 0) {
                    178:                        (void)lseek(fd, (off_t)0, SEEK_SET);
                    179:                        myfd = 0;
                    180:                } else {
                    181:                        fd = open(*db_p, O_RDONLY, 0);
                    182:                        if (fd < 0) {
                    183:                                /* No error on unfound file. */
                    184:                                continue;
                    185:                        }
                    186:                        myfd = 1;
                    187:                }
                    188:                /*
                    189:                 * Find the requested capability record ...
                    190:                 */
                    191:                {
                    192:                char buf[BUFSIZ];
1.4       mpech     193:                char *b_end, *bp;
                    194:                int c;
1.1       tholo     195:
                    196:                /*
                    197:                 * Loop invariants:
                    198:                 *      There is always room for one more character in record.
                    199:                 *      R_end always points just past end of record.
                    200:                 *      Rp always points just past last character in record.
                    201:                 *      B_end always points just past last character in buf.
                    202:                 *      Bp always points at next character in buf.
                    203:                 */
                    204:                b_end = buf;
                    205:                bp = buf;
                    206:                for (;;) {
                    207:
                    208:                        /*
                    209:                         * Read in a line implementing (\, newline)
                    210:                         * line continuation.
                    211:                         */
                    212:                        rp = record;
                    213:                        for (;;) {
                    214:                                if (bp >= b_end) {
                    215:                                        int n;
                    216:
                    217:                                        n = read(fd, buf, sizeof(buf));
                    218:                                        if (n <= 0) {
                    219:                                                if (myfd)
                    220:                                                        (void)close(fd);
                    221:                                                if (n < 0) {
                    222:                                                        free(record);
                    223:                                                        return (-2);
                    224:                                                } else {
                    225:                                                        fd = -1;
                    226:                                                        eof = 1;
                    227:                                                        break;
                    228:                                                }
                    229:                                        }
                    230:                                        b_end = buf+n;
                    231:                                        bp = buf;
                    232:                                }
                    233:
                    234:                                c = *bp++;
                    235:                                if (c == '\n') {
                    236:                                        if (bp >= b_end) {
                    237:                                                int n;
                    238:
                    239:                                                n = read(fd, buf, sizeof(buf));
                    240:                                                if (n <= 0) {
                    241:                                                        if (myfd)
                    242:                                                                (void)close(fd);
                    243:                                                        if (n < 0) {
                    244:                                                                free(record);
                    245:                                                                return (-2);
                    246:                                                        } else {
                    247:                                                                fd = -1;
                    248:                                                                eof = 1;
                    249:                                                                break;
                    250:                                                        }
                    251:                                                }
                    252:                                                b_end = buf+n;
                    253:                                                bp = buf;
                    254:                                        }
                    255:                                        if (rp > record && isspace(*bp))
                    256:                                                continue;
                    257:                                        else
                    258:                                                break;
                    259:                                }
                    260:                                if (rp <= record || *(rp - 1) != ',' || !isspace(c))
                    261:                                        *rp++ = c;
                    262:
                    263:                                /*
                    264:                                 * Enforce loop invariant: if no room
                    265:                                 * left in record buffer, try to get
                    266:                                 * some more.
                    267:                                 */
                    268:                                if (rp >= r_end) {
                    269:                                        u_int pos;
                    270:                                        size_t newsize;
                    271:
                    272:                                        pos = rp - record;
                    273:                                        newsize = r_end - record + BFRAG;
                    274:                                        record = realloc(record, newsize);
                    275:                                        if (record == NULL) {
                    276:                                                errno = ENOMEM;
                    277:                                                if (myfd)
                    278:                                                        (void)close(fd);
                    279:                                                return (-2);
                    280:                                        }
                    281:                                        r_end = record + newsize;
                    282:                                        rp = record + pos;
                    283:                                }
                    284:                        }
                    285:                                /* loop invariant let's us do this */
                    286:                        *rp++ = '\0';
                    287:
                    288:                        /*
                    289:                         * Toss blank lines and comments.
                    290:                         */
                    291:                        if (*record == '\0' || *record == '#')
                    292:                                continue;
                    293:
                    294:                        /*
                    295:                         * See if this is the record we want ...
                    296:                         */
                    297:                        if (igetmatch(record, name) == 0) {
                    298:                                foundit = 1;
                    299:                                break;  /* found it! */
                    300:                        }
1.2       naddy     301:
                    302:                        /*
                    303:                         * If encountered eof check next file.
                    304:                         */
                    305:                        if (eof)
                    306:                                break;
1.1       tholo     307:                }
                    308:        }
                    309:                if (foundit)
                    310:                        break;
                    311:        }
                    312:
                    313:        if (!foundit)
                    314:                return (-1);
                    315:
                    316:        /*
                    317:         * Got the capability record, but now we have to expand all use=name
                    318:         * references in it ...
                    319:         */
                    320:        {
1.4       mpech     321:                char *newicap, *s;
                    322:                int newilen;
1.1       tholo     323:                u_int ilen;
                    324:                int diff, iret, tclen;
                    325:                char *icap, *scan, *tc, *tcstart, *tcend;
                    326:
                    327:                /*
                    328:                 * Loop invariants:
                    329:                 *      There is room for one more character in record.
                    330:                 *      R_end points just past end of record.
                    331:                 *      Rp points just past last character in record.
                    332:                 *      Scan points at remainder of record that needs to be
                    333:                 *      scanned for use=name constructs.
                    334:                 */
                    335:                scan = record;
                    336:                tc_not_resolved = 0;
                    337:                for (;;) {
                    338:                        if ((tc = igetcap(scan, "use", '=')) == NULL)
                    339:                                break;
                    340:
                    341:                        /*
                    342:                         * Find end of use=name and stomp on the trailing `,'
                    343:                         * (if present) so we can use it to call ourselves.
                    344:                         */
                    345:                        s = tc;
                    346:                        for (;;)
                    347:                                if (*s == '\0')
                    348:                                        break;
                    349:                                else
                    350:                                        if (*s++ == ',') {
                    351:                                                *(s - 1) = '\0';
                    352:                                                break;
                    353:                                        }
                    354:                        tcstart = tc - 4;
                    355:                        tclen = s - tcstart;
                    356:                        tcend = s;
                    357:
                    358:                        iret = getent(&icap, &ilen, db_p, fd, tc, depth+1);
                    359:                        newicap = icap;         /* Put into a register. */
                    360:                        newilen = ilen;
                    361:                        if (iret != 0) {
                    362:                                /* an error */
                    363:                                if (iret < -1) {
                    364:                                        if (myfd)
                    365:                                                (void)close(fd);
                    366:                                        free(record);
                    367:                                        return (iret);
                    368:                                }
                    369:                                if (iret == 1)
                    370:                                        tc_not_resolved = 1;
                    371:                                /* couldn't resolve tc */
                    372:                                if (iret == -1) {
                    373:                                        *(s - 1) = ',';
                    374:                                        scan = s - 1;
                    375:                                        tc_not_resolved = 1;
                    376:                                        continue;
                    377:
                    378:                                }
                    379:                        }
                    380:                        /* not interested in name field of tc'ed record */
                    381:                        s = newicap;
                    382:                        for (;;)
                    383:                                if (*s == '\0')
                    384:                                        break;
                    385:                                else
                    386:                                        if (*s++ == ',')
                    387:                                                break;
                    388:                        newilen -= s - newicap;
                    389:                        newicap = s;
                    390:
                    391:                        /* make sure interpolated record is `,'-terminated */
                    392:                        s += newilen;
                    393:                        if (*(s-1) != ',') {
                    394:                                *s = ',';       /* overwrite NUL with , */
                    395:                                newilen++;
                    396:                        }
                    397:
                    398:                        /*
                    399:                         * Make sure there's enough room to insert the
                    400:                         * new record.
                    401:                         */
                    402:                        diff = newilen - tclen;
                    403:                        if (diff >= r_end - rp) {
                    404:                                u_int pos, tcpos, tcposend;
                    405:                                size_t newsize;
                    406:
                    407:                                pos = rp - record;
                    408:                                newsize = r_end - record + diff + BFRAG;
                    409:                                tcpos = tcstart - record;
                    410:                                tcposend = tcend - record;
                    411:                                record = realloc(record, newsize);
                    412:                                if (record == NULL) {
                    413:                                        errno = ENOMEM;
                    414:                                        if (myfd)
                    415:                                                (void)close(fd);
                    416:                                        free(icap);
                    417:                                        return (-2);
                    418:                                }
                    419:                                r_end = record + newsize;
                    420:                                rp = record + pos;
                    421:                                tcstart = record + tcpos;
                    422:                                tcend = record + tcposend;
                    423:                        }
                    424:
                    425:                        /*
                    426:                         * Insert tc'ed record into our record.
                    427:                         */
                    428:                        s = tcstart + newilen;
                    429:                        bcopy(tcend, s, (size_t)(rp - tcend));
                    430:                        bcopy(newicap, tcstart, (size_t)newilen);
                    431:                        rp += diff;
                    432:                        free(icap);
                    433:
                    434:                        /*
                    435:                         * Start scan on `,' so next igetcap works properly
                    436:                         * (igetcap always skips first field).
                    437:                         */
                    438:                        scan = s-1;
                    439:                }
                    440:
                    441:        }
                    442:        /*
                    443:         * Close file (if we opened it), give back any extra memory, and
                    444:         * return capability, length and success.
                    445:         */
                    446:        if (myfd)
                    447:                (void)close(fd);
                    448:        *len = rp - record - 1; /* don't count NUL */
                    449:        if (r_end > rp)
                    450:                if ((record =
                    451:                     realloc(record, (size_t)(rp - record))) == NULL) {
                    452:                        errno = ENOMEM;
                    453:                        return (-2);
                    454:                }
                    455:
                    456:        *cap = record;
                    457:        if (tc_not_resolved)
                    458:                return (1);
                    459:        return (0);
                    460: }
                    461:
                    462: /*
                    463:  * Cgetmatch will return 0 if name is one of the names of the capability
                    464:  * record buf, -1 if not.
                    465:  */
                    466: static int
                    467: igetmatch(buf, name)
                    468:        char *buf, *name;
                    469: {
1.4       mpech     470:        char *np, *bp;
1.1       tholo     471:
                    472:        /*
                    473:         * Start search at beginning of record.
                    474:         */
                    475:        bp = buf;
                    476:        for (;;) {
                    477:                /*
                    478:                 * Try to match a record name.
                    479:                 */
                    480:                np = name;
                    481:                for (;;)
                    482:                        if (*np == '\0') {
                    483:                                if (*bp == '|' || *bp == ',' || *bp == '\0')
                    484:                                        return (0);
                    485:                                else
                    486:                                        break;
                    487:                        } else {
                    488:                                if (*bp++ != *np++)
                    489:                                        break;
                    490:                        }
                    491:
                    492:                /*
                    493:                 * Match failed, skip to next name in record.
                    494:                 */
                    495:                bp--;   /* a '|' or ',' may have stopped the match */
                    496:                for (;;)
                    497:                        if (*bp == '\0' || *bp == ',')
                    498:                                return (-1);    /* match failed totally */
                    499:                        else
                    500:                                if (*bp++ == '|')
                    501:                                        break;  /* found next name */
                    502:        }
                    503: }
                    504:
                    505: static FILE *pfp;
                    506: static int slash;
                    507: static char **dbp;
                    508:
                    509: static int
                    510: igetclose()
                    511: {
                    512:        if (pfp != NULL) {
                    513:                (void)fclose(pfp);
                    514:                pfp = NULL;
                    515:        }
                    516:        dbp = NULL;
                    517:        slash = 0;
                    518:        return(0);
                    519: }
                    520:
                    521: /*
                    522:  * Cgetnext() gets either the first or next entry in the logical database
                    523:  * specified by db_array.  It returns 0 upon completion of the database, 1
                    524:  * upon returning an entry with more remaining, and -1 if an error occurs.
                    525:  */
                    526: int
                    527: igetnext(bp, db_array)
1.4       mpech     528:         char **bp;
1.1       tholo     529:        char **db_array;
                    530: {
                    531:        size_t len;
                    532:        int status, done;
                    533:        char *cp, *line, *rp, *np, buf[BSIZE], nbuf[BSIZE];
                    534:        u_int dummy;
                    535:
                    536:        if (dbp == NULL)
                    537:                dbp = db_array;
                    538:
                    539:        if (pfp == NULL && (pfp = fopen(*dbp, "r")) == NULL) {
                    540:                (void)igetclose();
                    541:                return (-1);
                    542:        }
                    543:        for(;;) {
                    544:                line = fgetln(pfp, &len);
                    545:                if (line == NULL && pfp) {
                    546:                        (void)fclose(pfp);
                    547:                        if (ferror(pfp)) {
                    548:                                (void)igetclose();
                    549:                                return (-1);
                    550:                        } else {
                    551:                                if (*++dbp == NULL) {
                    552:                                        (void)igetclose();
                    553:                                        return (0);
                    554:                                } else if ((pfp =
                    555:                                    fopen(*dbp, "r")) == NULL) {
                    556:                                        (void)igetclose();
                    557:                                        return (-1);
                    558:                                } else
                    559:                                        continue;
                    560:                        }
                    561:                } else
                    562:                        line[len - 1] = '\0';
                    563:                if (len == 1) {
                    564:                        slash = 0;
                    565:                        continue;
                    566:                }
                    567:                if (isspace(*line) ||
                    568:                    *line == ',' || *line == '#' || slash) {
                    569:                        if (line[len - 2] == '\\')
                    570:                                slash = 1;
                    571:                        else
                    572:                                slash = 0;
                    573:                        continue;
                    574:                }
                    575:                if (line[len - 2] == '\\')
                    576:                        slash = 1;
                    577:                else
                    578:                        slash = 0;
                    579:
                    580:                /*
                    581:                 * Line points to a name line.
                    582:                 */
                    583:                done = 0;
                    584:                np = nbuf;
                    585:                for (;;) {
                    586:                        for (cp = line; *cp != '\0'; cp++) {
                    587:                                if (*cp == ',') {
                    588:                                        *np++ = ',';
                    589:                                        done = 1;
                    590:                                        break;
                    591:                                }
                    592:                                *np++ = *cp;
                    593:                        }
                    594:                        if (done) {
                    595:                                *np = '\0';
                    596:                                break;
                    597:                        } else { /* name field extends beyond the line */
                    598:                                line = fgetln(pfp, &len);
                    599:                                if (line == NULL && pfp) {
                    600:                                        (void)fclose(pfp);
                    601:                                        if (ferror(pfp)) {
                    602:                                                (void)igetclose();
                    603:                                                return (-1);
                    604:                                        }
                    605:                                } else
                    606:                                        line[len - 1] = '\0';
                    607:                        }
                    608:                }
                    609:                rp = buf;
                    610:                for(cp = nbuf; *cp != NULL; cp++)
                    611:                        if (*cp == '|' || *cp == ',')
                    612:                                break;
                    613:                        else
                    614:                                *rp++ = *cp;
                    615:
                    616:                *rp = '\0';
                    617:                status = getent(bp, &dummy, db_array, -1, buf, 0);
                    618:                if (status == -2 || status == -3)
                    619:                        (void)igetclose();
                    620:
                    621:                return (status + 1);
                    622:        }
                    623:        /* NOTREACHED */
                    624: }