155868Sbostic /*- 255868Sbostic * Copyright (c) 1992 The Regents of the University of California. 355868Sbostic * All rights reserved. 455868Sbostic * 555868Sbostic * This code is derived from software contributed to Berkeley by 655868Sbostic * Casey Leedom of Lawrence Livermore National Laboratory. 755868Sbostic * 855875Selan * Redistribution and use in source and binary forms, with or without 955875Selan * modification, are permitted provided that the following conditions 1055875Selan * are met: 1155875Selan * 1. Redistributions of source code must retain the above copyright 1255875Selan * notice, this list of conditions and the following disclaimer. 1355875Selan * 2. Redistributions in binary form must reproduce the above copyright 1455875Selan * notice, this list of conditions and the following disclaimer in the 1555875Selan * documentation and/or other materials provided with the distribution. 1655875Selan * 3. All advertising materials mentioning features or use of this software 1755875Selan * must display the following acknowledgement: 1855875Selan * This product includes software developed by the University of 1955875Selan * California, Berkeley and its contributors. 2055875Selan * 4. Neither the name of the University nor the names of its contributors 2155875Selan * may be used to endorse or promote products derived from this software 2255875Selan * without specific prior written permission. 2355875Selan * 2455875Selan * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 2555875Selan * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2655875Selan * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2755875Selan * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 2855875Selan * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2955875Selan * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 3055875Selan * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 3155875Selan * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 3255875Selan * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 3355875Selan * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 3455875Selan * SUCH DAMAGE. 3555868Sbostic */ 3655868Sbostic 3755868Sbostic #if defined(LIBC_SCCS) && !defined(lint) 3855875Selan static char sccsid[] = "@(#)getcap.c 5.1 (Berkeley) 8/6/92"; 3955868Sbostic #endif /* LIBC_SCCS and not lint */ 4055868Sbostic 4155868Sbostic #include <sys/types.h> 4255868Sbostic 4355868Sbostic #include <ctype.h> 4455868Sbostic #include <errno.h> 4555868Sbostic #include <errno.h> 4655868Sbostic #include <fcntl.h> 4755868Sbostic #include <stdio.h> 4855868Sbostic #include <stdlib.h> 4955868Sbostic #include <string.h> 5055868Sbostic #include <unistd.h> 5155868Sbostic 5255868Sbostic #define BFRAG 1024 5355868Sbostic #define BSIZE 80 5455868Sbostic #define ESC ('[' & 037) /* ASCII ESC */ 5555868Sbostic #define MAX_RECURSION 32 /* maximum getent recursion */ 5655868Sbostic #define SFRAG 100 /* cgetstr mallocs in SFRAG chunks */ 5755868Sbostic 5855868Sbostic static size_t topreclen; /* toprec length */ 5955868Sbostic static char *toprec; /* Additional record specified by cgetset() */ 6055875Selan static int gottoprec; /* Flag indicating retrieval of toprecord */ 6155868Sbostic 6255868Sbostic static int getent __P((char **, u_int *, char **, int, char *, int)); 6355868Sbostic 6455868Sbostic /* 6555868Sbostic * Cgetset() allows the addition of a user specified buffer to be added 6655868Sbostic * to the database array, in effect "pushing" the buffer on top of the 6755868Sbostic * virtual database. 0 is returned on success, -1 on failure. 6855868Sbostic */ 6955868Sbostic int 7055868Sbostic cgetset(ent) 7155868Sbostic char *ent; 7255868Sbostic { 7355868Sbostic if (ent == NULL) { 7455868Sbostic if (toprec) 7555868Sbostic free(toprec); 7655868Sbostic toprec = NULL; 7755868Sbostic topreclen = 0; 7855868Sbostic return (0); 7955868Sbostic } 8055868Sbostic topreclen = strlen(ent); 8155868Sbostic if ((toprec = malloc (topreclen + 1)) == NULL) { 8255868Sbostic errno = ENOMEM; 8355868Sbostic return (-1); 8455868Sbostic } 85*55876Selan gottoprec = 0; 8655868Sbostic (void)strcpy(toprec, ent); 8755868Sbostic return (0); 8855868Sbostic } 8955868Sbostic 9055868Sbostic /* 9155868Sbostic * Cgetcap searches the capability record buf for the capability cap with 9255868Sbostic * type `type'. A pointer to the value of cap is returned on success, NULL 9355868Sbostic * if the requested capability couldn't be found. 9455868Sbostic * 9555868Sbostic * Specifying a type of ':' means that nothing should follow cap (:cap:). 9655868Sbostic * In this case a pointer to the terminating ':' or NUL will be returned if 9755868Sbostic * cap is found. 9855868Sbostic * 9955868Sbostic * If (cap, '@') or (cap, terminator, '@') is found before (cap, terminator) 10055868Sbostic * return NULL. 10155868Sbostic */ 10255868Sbostic char * 10355868Sbostic cgetcap(buf, cap, type) 10455868Sbostic char *buf, *cap; 10555868Sbostic int type; 10655868Sbostic { 10755868Sbostic register char *bp, *cp; 10855868Sbostic 10955868Sbostic bp = buf; 11055868Sbostic for (;;) { 11155868Sbostic /* 11255868Sbostic * Skip past the current capability field - it's either the 11355868Sbostic * name field if this is the first time through the loop, or 11455868Sbostic * the remainder of a field whose name failed to match cap. 11555868Sbostic */ 11655868Sbostic for (;;) 11755868Sbostic if (*bp == '\0') 11855868Sbostic return (NULL); 11955868Sbostic else 12055868Sbostic if (*bp++ == ':') 12155868Sbostic break; 12255868Sbostic 12355868Sbostic /* 12455868Sbostic * Try to match (cap, type) in buf. 12555868Sbostic */ 12655868Sbostic for (cp = cap; *cp == *bp && *bp != '\0'; cp++, bp++) 12755868Sbostic continue; 12855868Sbostic if (*cp != '\0') 12955868Sbostic continue; 13055868Sbostic if (*bp == '@') 13155868Sbostic return (NULL); 13255868Sbostic if (type == ':') { 13355868Sbostic if (*bp != '\0' && *bp != ':') 13455868Sbostic continue; 13555868Sbostic return(bp); 13655868Sbostic } 13755868Sbostic if (*bp != type) 13855868Sbostic continue; 13955868Sbostic bp++; 14055868Sbostic return (*bp == '@' ? NULL : bp); 14155868Sbostic } 14255868Sbostic /* NOTREACHED */ 14355868Sbostic } 14455868Sbostic 14555868Sbostic /* 14655868Sbostic * Cgetent extracts the capability record name from the NULL terminated file 14755868Sbostic * array db_array and returns a pointer to a malloc'd copy of it in buf. 14855868Sbostic * Buf must be retained through all subsequent calls to cgetcap, cgetnum, 14955868Sbostic * cgetflag, and cgetstr, but may then be free'd. 0 is returned on success, 15055868Sbostic * -1 if the requested record couldn't be found, -2 if a system error was 15155868Sbostic * encountered (couldn't open/read a file, etc.), and -3 if a potential 15255868Sbostic * reference loop is detected. 15355868Sbostic */ 15455868Sbostic int 15555868Sbostic cgetent(buf, db_array, name) 15655868Sbostic char **buf, **db_array, *name; 15755868Sbostic { 15855868Sbostic u_int dummy; 15955868Sbostic 16055868Sbostic return (getent(buf, &dummy, db_array, -1, name, 0)); 16155868Sbostic } 16255868Sbostic 16355868Sbostic /* 16455868Sbostic * Getent implements the functions of cgetent. If fd is non-negative, 16555868Sbostic * *db_array has already been opened and fd is the open file descriptor. We 16655868Sbostic * do this to save time and avoid using up file descriptors for tc= 16755868Sbostic * recursions. 16855868Sbostic * 16955868Sbostic * Getent returns the same success/failure codes as cgetent. On success, a 17055868Sbostic * pointer to a malloc'ed capability record with all tc= capabilities fully 17155868Sbostic * expanded and its length (not including trailing ASCII NUL) are left in 17255868Sbostic * *cap and *len. 17355868Sbostic * 17455868Sbostic * Basic algorithm: 17555868Sbostic * + Allocate memory incrementally as needed in chunks of size BFRAG 17655868Sbostic * for capability buffer. 17755868Sbostic * + Recurse for each tc=name and interpolate result. Stop when all 17855868Sbostic * names interpolated, a name can't be found, or depth exceeds 17955868Sbostic * MAX_RECURSION. 18055868Sbostic */ 18155868Sbostic static int 18255868Sbostic getent(cap, len, db_array, fd, name, depth) 18355868Sbostic char **cap, **db_array, *name; 18455868Sbostic u_int *len; 18555868Sbostic int fd, depth; 18655868Sbostic { 18755868Sbostic register char *r_end, *rp, **db_p; 18855868Sbostic int myfd, eof, foundit; 18955868Sbostic char *record; 19055868Sbostic 19155868Sbostic /* 19255868Sbostic * Return with ``loop detected'' error if we've recursed more than 19355868Sbostic * MAX_RECURSION times. 19455868Sbostic */ 19555868Sbostic if (depth > MAX_RECURSION) 19655868Sbostic return (-3); 19755868Sbostic 19855868Sbostic /* 19955868Sbostic * Check if we have a top record from cgetset(). 20055868Sbostic */ 201*55876Selan if (depth == 0 && toprec != NULL && cgetmatch(toprec, name) == 0) { 20255868Sbostic if ((record = malloc (topreclen + BFRAG)) == NULL) { 20355868Sbostic errno = ENOMEM; 20455868Sbostic return (-2); 20555868Sbostic } 20655868Sbostic (void)strcpy(record, toprec); 20755868Sbostic myfd = 0; 20855868Sbostic db_p = db_array; 20955868Sbostic rp = record + topreclen + 1; 21055868Sbostic r_end = rp + BFRAG; 21155868Sbostic goto tc_exp; 21255868Sbostic } 21355868Sbostic /* 21455868Sbostic * Allocate first chunk of memory. 21555868Sbostic */ 21655868Sbostic if ((record = malloc(BFRAG)) == NULL) { 21755868Sbostic errno = ENOMEM; 21855868Sbostic return (-2); 21955868Sbostic } 22055868Sbostic r_end = record + BFRAG; 22155868Sbostic foundit = 0; 22255868Sbostic 22355868Sbostic /* 22455868Sbostic * Loop through database array until finding the record. 22555868Sbostic */ 22655868Sbostic 22755868Sbostic for (db_p = db_array; *db_p != NULL; db_p++) { 22855868Sbostic eof = 0; 22955868Sbostic 23055868Sbostic /* 23155868Sbostic * Open database if not already open. 23255868Sbostic */ 23355868Sbostic if (fd >= 0) { 23455868Sbostic (void)lseek(fd, 0L, L_SET); 23555868Sbostic myfd = 0; 23655868Sbostic } else { 23755868Sbostic fd = open(*db_p, O_RDONLY, 0); 23855868Sbostic if (fd < 0) { 23955868Sbostic free(record); 24055868Sbostic return (-2); 24155868Sbostic } 24255868Sbostic myfd = 1; 24355868Sbostic } 24455868Sbostic 24555868Sbostic /* 24655868Sbostic * Find the requested capability record ... 24755868Sbostic */ 24855868Sbostic { 24955868Sbostic char buf[BUFSIZ]; 25055868Sbostic register char *b_end, *bp; 25155868Sbostic register int c; 25255868Sbostic 25355868Sbostic /* 25455868Sbostic * Loop invariants: 25555868Sbostic * There is always room for one more character in record. 25655868Sbostic * R_end always points just past end of record. 25755868Sbostic * Rp always points just past last character in record. 25855868Sbostic * B_end always points just past last character in buf. 25955868Sbostic * Bp always points at next character in buf. 26055868Sbostic */ 26155868Sbostic b_end = buf; 26255868Sbostic bp = buf; 26355868Sbostic for (;;) { 26455868Sbostic 26555868Sbostic /* 26655868Sbostic * Read in a line implementing (\, newline) 26755868Sbostic * line continuation. 26855868Sbostic */ 26955868Sbostic rp = record; 27055868Sbostic for (;;) { 27155868Sbostic if (bp >= b_end) { 27255868Sbostic int n; 27355868Sbostic 27455868Sbostic n = read(fd, buf, sizeof(buf)); 27555868Sbostic if (n <= 0) { 27655868Sbostic if (myfd) 27755868Sbostic (void)close(fd); 27855868Sbostic if (n < 0) { 27955868Sbostic free(record); 28055868Sbostic return (-2); 28155868Sbostic } else { 28255868Sbostic fd = -1; 28355868Sbostic eof = 1; 28455868Sbostic break; 28555868Sbostic } 28655868Sbostic } 28755868Sbostic b_end = buf+n; 28855868Sbostic bp = buf; 28955868Sbostic } 29055868Sbostic 29155868Sbostic c = *bp++; 29255868Sbostic if (c == '\n') { 29355868Sbostic if (rp > record && *(rp-1) == '\\') { 29455868Sbostic rp--; 29555868Sbostic continue; 29655868Sbostic } else 29755868Sbostic break; 29855868Sbostic } 29955868Sbostic *rp++ = c; 30055868Sbostic 30155868Sbostic /* 30255868Sbostic * Enforce loop invariant: if no room 30355868Sbostic * left in record buffer, try to get 30455868Sbostic * some more. 30555868Sbostic */ 30655868Sbostic if (rp >= r_end) { 30755875Selan u_int pos; 30855875Selan size_t newsize; 30955868Sbostic 31055868Sbostic pos = rp - record; 31155868Sbostic newsize = r_end - record + BFRAG; 31255868Sbostic record = realloc(record, newsize); 31355868Sbostic if (record == NULL) { 31455868Sbostic errno = ENOMEM; 31555868Sbostic if (myfd) 31655868Sbostic (void)close(fd); 31755868Sbostic return (-2); 31855868Sbostic } 31955868Sbostic r_end = record + newsize; 32055868Sbostic rp = record + pos; 32155868Sbostic } 32255868Sbostic } 32355868Sbostic /* loop invariant let's us do this */ 32455868Sbostic *rp++ = '\0'; 32555868Sbostic 32655868Sbostic /* 32755868Sbostic * If encountered eof check next file. 32855868Sbostic */ 32955868Sbostic if (eof) 33055868Sbostic break; 33155868Sbostic 33255868Sbostic /* 33355868Sbostic * Toss blank lines and comments. 33455868Sbostic */ 33555868Sbostic if (*record == '\0' || *record == '#') 33655868Sbostic continue; 33755868Sbostic 33855868Sbostic /* 33955868Sbostic * See if this is the record we want ... 34055868Sbostic */ 34155868Sbostic if (cgetmatch(record, name) == 0) { 34255868Sbostic foundit = 1; 34355868Sbostic break; /* found it! */ 34455868Sbostic } 34555868Sbostic } 34655868Sbostic } 34755868Sbostic if (foundit) 34855868Sbostic break; 34955868Sbostic } 35055868Sbostic 35155868Sbostic if (!foundit) 35255868Sbostic return (-1); 353*55876Selan 35455868Sbostic /* 35555868Sbostic * Got the capability record, but now we have to expand all tc=name 35655868Sbostic * references in it ... 35755868Sbostic */ 35855868Sbostic tc_exp: { 35955868Sbostic register char *newicap, *s; 36055868Sbostic register int newilen; 36155868Sbostic u_int ilen; 36255868Sbostic int diff, iret, tclen; 36355868Sbostic char *icap, *scan, *tc, *tcstart, *tcend; 36455868Sbostic 36555868Sbostic /* 36655868Sbostic * Loop invariants: 36755868Sbostic * There is room for one more character in record. 36855868Sbostic * R_end points just past end of record. 36955868Sbostic * Rp points just past last character in record. 37055868Sbostic * Scan points at remainder of record that needs to be 37155868Sbostic * scanned for tc=name constructs. 37255868Sbostic */ 37355868Sbostic scan = record; 37455868Sbostic for (;;) { 37555868Sbostic if ((tc = cgetcap(scan, "tc", '=')) == NULL) 37655868Sbostic break; 37755868Sbostic 37855868Sbostic /* 37955868Sbostic * Find end of tc=name and stomp on the trailing `:' 38055868Sbostic * (if present) so we can use it to call ourselves. 38155868Sbostic */ 38255868Sbostic s = tc; 38355868Sbostic for (;;) 38455868Sbostic if (*s == '\0') 38555868Sbostic break; 38655868Sbostic else 38755868Sbostic if (*s++ == ':') { 38855868Sbostic *(s-1) = '\0'; 38955868Sbostic break; 39055868Sbostic } 39155868Sbostic tcstart = tc - 3; 39255868Sbostic tclen = s - tcstart; 39355868Sbostic tcend = s; 39455868Sbostic 39555868Sbostic iret = getent(&icap, &ilen, db_p, fd, tc, depth+1); 39655868Sbostic newicap = icap; /* Put into a register. */ 39755868Sbostic newilen = ilen; 39855868Sbostic if (iret != 0) { 39955868Sbostic /* an error or couldn't resolve tc= */ 40055868Sbostic if (myfd) 40155868Sbostic (void)close(fd); 40255868Sbostic free(record); 40355868Sbostic return (iret); 40455868Sbostic } 40555868Sbostic 40655868Sbostic /* not interested in name field of tc'ed record */ 40755868Sbostic s = newicap; 40855868Sbostic for (;;) 40955868Sbostic if (*s == '\0') 41055868Sbostic break; 41155868Sbostic else 41255868Sbostic if (*s++ == ':') 41355868Sbostic break; 41455868Sbostic newilen -= s - newicap; 41555868Sbostic newicap = s; 41655868Sbostic 41755868Sbostic /* make sure interpolated record is `:'-terminated */ 41855868Sbostic s += newilen; 41955868Sbostic if (*(s-1) != ':') { 42055868Sbostic *s = ':'; /* overwrite NUL with : */ 42155868Sbostic newilen++; 42255868Sbostic } 42355868Sbostic 42455868Sbostic /* 42555868Sbostic * Make sure there's enough room to insert the 42655868Sbostic * new record. 42755868Sbostic */ 42855868Sbostic diff = newilen - tclen; 42955868Sbostic if (diff >= r_end - rp) { 43055875Selan u_int pos, tcpos, tcposend; 43155875Selan size_t newsize; 43255868Sbostic 43355868Sbostic pos = rp - record; 43455868Sbostic newsize = r_end - record + diff + BFRAG; 43555868Sbostic tcpos = tcstart - record; 43655868Sbostic tcposend = tcend - record; 43755868Sbostic record = realloc(record, newsize); 43855868Sbostic if (record == NULL) { 43955868Sbostic errno = ENOMEM; 44055868Sbostic if (myfd) 44155868Sbostic (void)close(fd); 44255868Sbostic free(icap); 44355868Sbostic return (-2); 44455868Sbostic } 44555868Sbostic r_end = record + newsize; 44655868Sbostic rp = record + pos; 44755868Sbostic tcstart = record + tcpos; 44855868Sbostic tcend = record + tcposend; 44955868Sbostic } 45055868Sbostic 45155868Sbostic /* 45255868Sbostic * Insert tc'ed record into our record. 45355868Sbostic */ 45455868Sbostic s = tcstart + newilen; 45555868Sbostic bcopy(tcend, s, rp - tcend); 45655868Sbostic bcopy(newicap, tcstart, newilen); 45755868Sbostic rp += diff; 45855868Sbostic free(icap); 45955868Sbostic 46055868Sbostic /* 46155868Sbostic * Start scan on `:' so next cgetcap works properly 46255868Sbostic * (cgetcap always skips first field). 46355868Sbostic */ 46455868Sbostic scan = s-1; 46555868Sbostic } 46655868Sbostic } 46755868Sbostic 46855868Sbostic /* 46955868Sbostic * Close file (if we opened it), give back any extra memory, and 47055868Sbostic * return capability, length and success. 47155868Sbostic */ 47255868Sbostic if (myfd) 47355868Sbostic (void)close(fd); 47455868Sbostic *len = rp - record - 1; /* don't count NUL */ 47555868Sbostic if (r_end > rp) 47655875Selan record = realloc(record, (size_t)(rp - record)); 47755868Sbostic *cap = record; 47855868Sbostic return (0); 47955868Sbostic } 48055868Sbostic 48155868Sbostic /* 48255868Sbostic * Cgetmatch will return 0 if name is one of the names of the capability 48355868Sbostic * record buf, -1 if not. 48455868Sbostic */ 48555868Sbostic int 48655868Sbostic cgetmatch(buf, name) 48755868Sbostic char *buf, *name; 48855868Sbostic { 48955868Sbostic register char *np, *bp; 49055868Sbostic 49155868Sbostic /* 49255868Sbostic * Start search at beginning of record. 49355868Sbostic */ 49455868Sbostic bp = buf; 49555868Sbostic for (;;) { 49655868Sbostic /* 49755868Sbostic * Try to match a record name. 49855868Sbostic */ 49955868Sbostic np = name; 50055868Sbostic for (;;) 50155868Sbostic if (*np == '\0') 50255868Sbostic if (*bp == '|' || *bp == ':' || *bp == '\0') 50355868Sbostic return (0); 50455868Sbostic else 50555868Sbostic break; 50655868Sbostic else 50755868Sbostic if (*bp++ != *np++) 50855868Sbostic break; 50955868Sbostic 51055868Sbostic /* 51155868Sbostic * Match failed, skip to next name in record. 51255868Sbostic */ 51355868Sbostic bp--; /* a '|' or ':' may have stopped the match */ 51455868Sbostic for (;;) 51555868Sbostic if (*bp == '\0' || *bp == ':') 51655868Sbostic return (-1); /* match failed totally */ 51755868Sbostic else 51855868Sbostic if (*bp++ == '|') 51955868Sbostic break; /* found next name */ 52055868Sbostic } 52155868Sbostic } 52255868Sbostic 523*55876Selan 524*55876Selan 525*55876Selan 526*55876Selan 52755868Sbostic int 52855868Sbostic cgetfirst(buf, db_array) 52955868Sbostic char **buf, **db_array; 53055868Sbostic { 53155868Sbostic (void)cgetclose(); 53255868Sbostic return (cgetnext(buf, db_array)); 53355868Sbostic } 53455868Sbostic 53555868Sbostic static FILE *pfp; 53655868Sbostic static int slash; 53755868Sbostic static char **dbp; 53855868Sbostic 53955868Sbostic int 54055868Sbostic cgetclose() 54155868Sbostic { 54255868Sbostic if (pfp != NULL) { 54355868Sbostic (void)fclose(pfp); 54455868Sbostic pfp = NULL; 54555868Sbostic } 54655868Sbostic dbp = NULL; 54755875Selan gottoprec = 0; 54855868Sbostic slash = 0; 54955875Selan return(0); 55055868Sbostic } 55155868Sbostic 55255868Sbostic /* 55355868Sbostic * Cgetnext() gets either the first or next entry in the logical database 55455868Sbostic * specified by db_array. It returns 0 upon completion of the database, 1 55555868Sbostic * upon returning an entry with more remaining, and -1 if an error occurs. 55655868Sbostic */ 55755868Sbostic int 55855868Sbostic cgetnext(bp, db_array) 55955868Sbostic register char **bp; 56055868Sbostic char **db_array; 56155868Sbostic { 56255868Sbostic size_t len; 56355868Sbostic int status; 56455868Sbostic char *cp, *line, *rp, buf[BSIZE]; 565*55876Selan u_int dummy; 56655868Sbostic 567*55876Selan if (dbp == NULL) 56855868Sbostic dbp = db_array; 569*55876Selan 57055875Selan if (pfp == NULL && (pfp = fopen(*dbp, "r")) == NULL) { 57155875Selan (void)cgetclose(); 57255868Sbostic return (-1); 57355875Selan } 57455868Sbostic for(;;) { 575*55876Selan if (toprec && !gottoprec) { 576*55876Selan gottoprec = 1; 577*55876Selan line = toprec; 578*55876Selan } else { 579*55876Selan line = fgetline(pfp, &len); 580*55876Selan if (line == NULL && pfp) { 581*55876Selan (void)fclose(pfp); 582*55876Selan if (ferror(pfp)) { 58355875Selan (void)cgetclose(); 58455868Sbostic return (-1); 585*55876Selan } else { 586*55876Selan dbp++; 587*55876Selan if (*dbp == NULL) { 588*55876Selan (void)cgetclose(); 589*55876Selan return (0); 590*55876Selan } else if ((pfp = fopen(*dbp, "r")) == 591*55876Selan NULL) { 592*55876Selan (void)cgetclose(); 593*55876Selan return (-1); 594*55876Selan } else 595*55876Selan continue; 596*55876Selan } 59755868Sbostic } 598*55876Selan if (isspace(*line) || *line == ':' || *line == '#' 599*55876Selan || len == 0 || slash) { 600*55876Selan if (len > 0 && line[len - 1] == '\\') 601*55876Selan slash = 1; 602*55876Selan else 603*55876Selan slash = 0; 604*55876Selan continue; 605*55876Selan } 60655868Sbostic if (len > 0 && line[len - 1] == '\\') 60755868Sbostic slash = 1; 60855868Sbostic else 60955868Sbostic slash = 0; 610*55876Selan } 61155868Sbostic /* line points to a name line */ 61255868Sbostic 61355868Sbostic rp = buf; 61455868Sbostic for(cp = line; *cp != NULL; cp++) 61555868Sbostic if (*cp == '|' || *cp == ':') 61655868Sbostic break; 61755868Sbostic else 61855868Sbostic *rp++ = *cp; 61955868Sbostic 62055868Sbostic *rp = '\0'; 621*55876Selan status = getent(bp, &dummy, db_array, -1, buf, 0); 62255868Sbostic if (status == 0) 62355868Sbostic return (1); 62455868Sbostic if (status == -2 || status == -3) { 62555875Selan (void)cgetclose(); 62655868Sbostic return (status + 1); 62755868Sbostic } 62855868Sbostic } 62955868Sbostic /* NOTREACHED */ 63055868Sbostic } 63155868Sbostic 63255868Sbostic /* 63355868Sbostic * Cgetstr retrieves the value of the string capability cap from the 63455868Sbostic * capability record pointed to by buf. A pointer to a decoded, NUL 63555868Sbostic * terminated, malloc'd copy of the string is returned in the char * 63655868Sbostic * pointed to by str. The length of the string not including the trailing 63755868Sbostic * NUL is returned on success, -1 if the requested string capability 63855868Sbostic * couldn't be found, -2 if a system error was encountered (storage 63955868Sbostic * allocation failure). 64055868Sbostic */ 64155868Sbostic int 64255868Sbostic cgetstr(buf, cap, str) 64355868Sbostic char *buf, *cap; 64455868Sbostic char **str; 64555868Sbostic { 64655868Sbostic register u_int m_room; 64755868Sbostic register char *bp, *mp; 64855868Sbostic int len; 64955868Sbostic char *mem; 65055868Sbostic 65155868Sbostic /* 65255868Sbostic * Find string capability cap 65355868Sbostic */ 65455868Sbostic bp = cgetcap(buf, cap, '='); 65555868Sbostic if (bp == NULL) 65655868Sbostic return (-1); 65755868Sbostic 65855868Sbostic /* 65955868Sbostic * Conversion / storage allocation loop ... Allocate memory in 66055868Sbostic * chunks SFRAG in size. 66155868Sbostic */ 66255868Sbostic if ((mem = malloc(SFRAG)) == NULL) { 66355868Sbostic errno = ENOMEM; 66455868Sbostic return (-2); /* couldn't even allocate the first fragment */ 66555868Sbostic } 66655868Sbostic m_room = SFRAG; 66755868Sbostic mp = mem; 66855868Sbostic 66955868Sbostic while (*bp != ':' && *bp != '\0') { 67055868Sbostic /* 67155868Sbostic * Loop invariants: 67255868Sbostic * There is always room for one more character in mem. 67355868Sbostic * Mp always points just past last character in mem. 67455868Sbostic * Bp always points at next character in buf. 67555868Sbostic */ 67655868Sbostic if (*bp == '^') { 67755868Sbostic bp++; 67855868Sbostic if (*bp == ':' || *bp == '\0') 67955868Sbostic break; /* drop unfinished escape */ 68055868Sbostic *mp++ = *bp++ & 037; 68155868Sbostic } else if (*bp == '\\') { 68255868Sbostic bp++; 68355868Sbostic if (*bp == ':' || *bp == '\0') 68455868Sbostic break; /* drop unfinished escape */ 68555868Sbostic if ('0' <= *bp && *bp <= '7') { 68655868Sbostic register int n, i; 68755868Sbostic 68855868Sbostic n = 0; 68955868Sbostic i = 3; /* maximum of three octal digits */ 69055868Sbostic do { 69155868Sbostic n = n * 8 + (*bp++ - '0'); 69255868Sbostic } while (--i && '0' <= *bp && *bp <= '7'); 69355868Sbostic *mp++ = n; 69455868Sbostic } 69555868Sbostic else switch (*bp++) { 69655868Sbostic case 'b': case 'B': 69755868Sbostic *mp++ = '\b'; 69855868Sbostic break; 69955868Sbostic case 't': case 'T': 70055868Sbostic *mp++ = '\t'; 70155868Sbostic break; 70255868Sbostic case 'n': case 'N': 70355868Sbostic *mp++ = '\n'; 70455868Sbostic break; 70555868Sbostic case 'f': case 'F': 70655868Sbostic *mp++ = '\f'; 70755868Sbostic break; 70855868Sbostic case 'r': case 'R': 70955868Sbostic *mp++ = '\r'; 71055868Sbostic break; 71155868Sbostic case 'e': case 'E': 71255868Sbostic *mp++ = ESC; 71355868Sbostic break; 71455868Sbostic case 'c': case 'C': 71555868Sbostic *mp++ = ':'; 71655868Sbostic break; 71755868Sbostic default: 71855868Sbostic /* 71955868Sbostic * Catches '\', '^', and 72055868Sbostic * everything else. 72155868Sbostic */ 72255868Sbostic *mp++ = *(bp-1); 72355868Sbostic break; 72455868Sbostic } 72555868Sbostic } else 72655868Sbostic *mp++ = *bp++; 72755868Sbostic m_room--; 72855868Sbostic 72955868Sbostic /* 73055868Sbostic * Enforce loop invariant: if no room left in current 73155868Sbostic * buffer, try to get some more. 73255868Sbostic */ 73355868Sbostic if (m_room == 0) { 73455875Selan size_t size = mp - mem; 73555868Sbostic 73655868Sbostic if ((mem = realloc(mem, size + SFRAG)) == NULL) 73755868Sbostic return (-2); 73855868Sbostic m_room = SFRAG; 73955868Sbostic mp = mem + size; 74055868Sbostic } 74155868Sbostic } 74255868Sbostic *mp++ = '\0'; /* loop invariant let's us do this */ 74355868Sbostic m_room--; 74455868Sbostic len = mp - mem - 1; 74555868Sbostic 74655868Sbostic /* 74755868Sbostic * Give back any extra memory and return value and success. 74855868Sbostic */ 74955868Sbostic if (m_room != 0) 75055875Selan mem = realloc(mem, (size_t)(mp - mem)); 75155868Sbostic *str = mem; 75255868Sbostic return (len); 75355868Sbostic } 75455868Sbostic 75555868Sbostic /* 75655868Sbostic * Cgetustr retrieves the value of the string capability cap from the 75755868Sbostic * capability record pointed to by buf. The difference between cgetustr() 75855868Sbostic * and cgetstr() is that cgetustr does not decode escapes but rather treats 75955868Sbostic * all characters literally. A pointer to a NUL terminated malloc'd 76055868Sbostic * copy of the string is returned in the char pointed to by str. The 76155868Sbostic * length of the string not including the trailing NUL is returned on success, 76255868Sbostic * -1 if the requested string capability couldn't be found, -2 if a system 76355868Sbostic * error was encountered (storage allocation failure). 76455868Sbostic */ 76555868Sbostic int 76655868Sbostic cgetustr(buf, cap, str) 76755868Sbostic char *buf, *cap, **str; 76855868Sbostic { 76955868Sbostic register u_int m_room; 77055868Sbostic register char *bp, *mp; 77155868Sbostic int len; 77255868Sbostic char *mem; 77355868Sbostic 77455868Sbostic /* 77555868Sbostic * Find string capability cap 77655868Sbostic */ 77755868Sbostic if ((bp = cgetcap(buf, cap, '=')) == NULL) 77855868Sbostic return (-1); 77955868Sbostic 78055868Sbostic /* 78155868Sbostic * Conversion / storage allocation loop ... Allocate memory in 78255868Sbostic * chunks SFRAG in size. 78355868Sbostic */ 78455868Sbostic if ((mem = malloc(SFRAG)) == NULL) { 78555868Sbostic errno = ENOMEM; 78655868Sbostic return (-2); /* couldn't even allocate the first fragment */ 78755868Sbostic } 78855868Sbostic m_room = SFRAG; 78955868Sbostic mp = mem; 79055868Sbostic 79155868Sbostic while (*bp != ':' && *bp != '\0') { 79255868Sbostic /* 79355868Sbostic * Loop invariants: 79455868Sbostic * There is always room for one more character in mem. 79555868Sbostic * Mp always points just past last character in mem. 79655868Sbostic * Bp always points at next character in buf. 79755868Sbostic */ 79855868Sbostic *mp++ = *bp++; 79955868Sbostic m_room--; 80055868Sbostic 80155868Sbostic /* 80255868Sbostic * Enforce loop invariant: if no room left in current 80355868Sbostic * buffer, try to get some more. 80455868Sbostic */ 80555868Sbostic if (m_room == 0) { 80655875Selan size_t size = mp - mem; 80755868Sbostic 80855868Sbostic if ((mem = realloc(mem, size + SFRAG)) == NULL) 80955868Sbostic return (-2); 81055868Sbostic m_room = SFRAG; 81155868Sbostic mp = mem + size; 81255868Sbostic } 81355868Sbostic } 81455868Sbostic *mp++ = '\0'; /* loop invariant let's us do this */ 81555868Sbostic m_room--; 81655868Sbostic len = mp - mem - 1; 81755868Sbostic 81855868Sbostic /* 81955868Sbostic * Give back any extra memory and return value and success. 82055868Sbostic */ 82155868Sbostic if (m_room != 0) 82255875Selan mem = realloc(mem, (size_t)(mp - mem)); 82355868Sbostic *str = mem; 82455868Sbostic return (len); 82555868Sbostic } 82655868Sbostic 82755868Sbostic /* 82855868Sbostic * Cgetnum retrieves the value of the numeric capability cap from the 82955868Sbostic * capability record pointed to by buf. The numeric value is returned in 83055868Sbostic * the long pointed to by num. 0 is returned on success, -1 if the requested 83155868Sbostic * numeric capability couldn't be found. 83255868Sbostic */ 83355868Sbostic int 83455868Sbostic cgetnum(buf, cap, num) 83555868Sbostic char *buf, *cap; 83655868Sbostic long *num; 83755868Sbostic { 83855868Sbostic register long n; 83955868Sbostic register int base, digit; 84055868Sbostic register char *bp; 84155868Sbostic 84255868Sbostic /* 84355868Sbostic * Find numeric capability cap 84455868Sbostic */ 84555868Sbostic bp = cgetcap(buf, cap, '#'); 84655868Sbostic if (bp == NULL) 84755868Sbostic return (-1); 84855868Sbostic 84955868Sbostic /* 85055868Sbostic * Look at value and determine numeric base: 85155868Sbostic * 0x... or 0X... hexadecimal, 85255868Sbostic * else 0... octal, 85355868Sbostic * else decimal. 85455868Sbostic */ 85555868Sbostic if (*bp == '0') { 85655868Sbostic bp++; 85755868Sbostic if (*bp == 'x' || *bp == 'X') { 85855868Sbostic bp++; 85955868Sbostic base = 16; 86055868Sbostic } else 86155868Sbostic base = 8; 86255868Sbostic } else 86355868Sbostic base = 10; 86455868Sbostic 86555868Sbostic /* 86655868Sbostic * Conversion loop ... 86755868Sbostic */ 86855868Sbostic n = 0; 86955868Sbostic for (;;) { 87055868Sbostic if ('0' <= *bp && *bp <= '9') 87155868Sbostic digit = *bp - '0'; 87255868Sbostic else 87355868Sbostic if ( ('a' <= *bp && *bp <= 'f') 87455868Sbostic || ('A' <= *bp && *bp <= 'F')) 87555868Sbostic digit = 10 + *bp - 'a'; 87655868Sbostic else 87755868Sbostic break; 87855868Sbostic 87955868Sbostic if (digit >= base) 88055868Sbostic break; 88155868Sbostic 88255868Sbostic n = n * base + digit; 88355868Sbostic bp++; 88455868Sbostic } 88555868Sbostic 88655868Sbostic /* 88755868Sbostic * Return value and success. 88855868Sbostic */ 88955868Sbostic *num = n; 89055868Sbostic return (0); 89155868Sbostic } 892