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

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