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

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