158f0484fSRodney W. Grimes /*- 258f0484fSRodney W. Grimes * Copyright (c) 1992, 1993 358f0484fSRodney W. Grimes * The Regents of the University of California. All rights reserved. 458f0484fSRodney W. Grimes * 558f0484fSRodney W. Grimes * This code is derived from software contributed to Berkeley by 658f0484fSRodney W. Grimes * Casey Leedom of Lawrence Livermore National Laboratory. 758f0484fSRodney W. Grimes * 858f0484fSRodney W. Grimes * Redistribution and use in source and binary forms, with or without 958f0484fSRodney W. Grimes * modification, are permitted provided that the following conditions 1058f0484fSRodney W. Grimes * are met: 1158f0484fSRodney W. Grimes * 1. Redistributions of source code must retain the above copyright 1258f0484fSRodney W. Grimes * notice, this list of conditions and the following disclaimer. 1358f0484fSRodney W. Grimes * 2. Redistributions in binary form must reproduce the above copyright 1458f0484fSRodney W. Grimes * notice, this list of conditions and the following disclaimer in the 1558f0484fSRodney W. Grimes * documentation and/or other materials provided with the distribution. 1658f0484fSRodney W. Grimes * 3. All advertising materials mentioning features or use of this software 1758f0484fSRodney W. Grimes * must display the following acknowledgement: 1858f0484fSRodney W. Grimes * This product includes software developed by the University of 1958f0484fSRodney W. Grimes * California, Berkeley and its contributors. 2058f0484fSRodney W. Grimes * 4. Neither the name of the University nor the names of its contributors 2158f0484fSRodney W. Grimes * may be used to endorse or promote products derived from this software 2258f0484fSRodney W. Grimes * without specific prior written permission. 2358f0484fSRodney W. Grimes * 2458f0484fSRodney W. Grimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 2558f0484fSRodney W. Grimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2658f0484fSRodney W. Grimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2758f0484fSRodney W. Grimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 2858f0484fSRodney W. Grimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2958f0484fSRodney W. Grimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 3058f0484fSRodney W. Grimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 3158f0484fSRodney W. Grimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 3258f0484fSRodney W. Grimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 3358f0484fSRodney W. Grimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 3458f0484fSRodney W. Grimes * SUCH DAMAGE. 3558f0484fSRodney W. Grimes */ 3658f0484fSRodney W. Grimes 3758f0484fSRodney W. Grimes #if defined(LIBC_SCCS) && !defined(lint) 3858f0484fSRodney W. Grimes static char sccsid[] = "@(#)getcap.c 8.3 (Berkeley) 3/25/94"; 3958f0484fSRodney W. Grimes #endif /* LIBC_SCCS and not lint */ 4058f0484fSRodney W. Grimes 4158f0484fSRodney W. Grimes #include <sys/types.h> 4258f0484fSRodney W. Grimes 4358f0484fSRodney W. Grimes #include <ctype.h> 4458f0484fSRodney W. Grimes #include <db.h> 4558f0484fSRodney W. Grimes #include <errno.h> 4658f0484fSRodney W. Grimes #include <fcntl.h> 4758f0484fSRodney W. Grimes #include <limits.h> 4858f0484fSRodney W. Grimes #include <stdio.h> 4958f0484fSRodney W. Grimes #include <stdlib.h> 5058f0484fSRodney W. Grimes #include <string.h> 5158f0484fSRodney W. Grimes #include <unistd.h> 5258f0484fSRodney W. Grimes 5358f0484fSRodney W. Grimes #define BFRAG 1024 5458f0484fSRodney W. Grimes #define BSIZE 1024 5558f0484fSRodney W. Grimes #define ESC ('[' & 037) /* ASCII ESC */ 5658f0484fSRodney W. Grimes #define MAX_RECURSION 32 /* maximum getent recursion */ 5758f0484fSRodney W. Grimes #define SFRAG 100 /* cgetstr mallocs in SFRAG chunks */ 5858f0484fSRodney W. Grimes 5958f0484fSRodney W. Grimes #define RECOK (char)0 6058f0484fSRodney W. Grimes #define TCERR (char)1 6158f0484fSRodney W. Grimes #define SHADOW (char)2 6258f0484fSRodney W. Grimes 6358f0484fSRodney W. Grimes static size_t topreclen; /* toprec length */ 6458f0484fSRodney W. Grimes static char *toprec; /* Additional record specified by cgetset() */ 6558f0484fSRodney W. Grimes static int gottoprec; /* Flag indicating retrieval of toprecord */ 6658f0484fSRodney W. Grimes 6758f0484fSRodney W. Grimes static int cdbget __P((DB *, char **, char *)); 6858f0484fSRodney W. Grimes static int getent __P((char **, u_int *, char **, int, char *, int, char *)); 6958f0484fSRodney W. Grimes static int nfcmp __P((char *, char *)); 7058f0484fSRodney W. Grimes 7158f0484fSRodney W. Grimes /* 7258f0484fSRodney W. Grimes * Cgetset() allows the addition of a user specified buffer to be added 7358f0484fSRodney W. Grimes * to the database array, in effect "pushing" the buffer on top of the 7458f0484fSRodney W. Grimes * virtual database. 0 is returned on success, -1 on failure. 7558f0484fSRodney W. Grimes */ 7658f0484fSRodney W. Grimes int 7758f0484fSRodney W. Grimes cgetset(ent) 7858f0484fSRodney W. Grimes char *ent; 7958f0484fSRodney W. Grimes { 8058f0484fSRodney W. Grimes if (ent == NULL) { 8158f0484fSRodney W. Grimes if (toprec) 8258f0484fSRodney W. Grimes free(toprec); 8358f0484fSRodney W. Grimes toprec = NULL; 8458f0484fSRodney W. Grimes topreclen = 0; 8558f0484fSRodney W. Grimes return (0); 8658f0484fSRodney W. Grimes } 8758f0484fSRodney W. Grimes topreclen = strlen(ent); 8858f0484fSRodney W. Grimes if ((toprec = malloc (topreclen + 1)) == NULL) { 8958f0484fSRodney W. Grimes errno = ENOMEM; 9058f0484fSRodney W. Grimes return (-1); 9158f0484fSRodney W. Grimes } 9258f0484fSRodney W. Grimes gottoprec = 0; 9358f0484fSRodney W. Grimes (void)strcpy(toprec, ent); 9458f0484fSRodney W. Grimes return (0); 9558f0484fSRodney W. Grimes } 9658f0484fSRodney W. Grimes 9758f0484fSRodney W. Grimes /* 9858f0484fSRodney W. Grimes * Cgetcap searches the capability record buf for the capability cap with 9958f0484fSRodney W. Grimes * type `type'. A pointer to the value of cap is returned on success, NULL 10058f0484fSRodney W. Grimes * if the requested capability couldn't be found. 10158f0484fSRodney W. Grimes * 10258f0484fSRodney W. Grimes * Specifying a type of ':' means that nothing should follow cap (:cap:). 10358f0484fSRodney W. Grimes * In this case a pointer to the terminating ':' or NUL will be returned if 10458f0484fSRodney W. Grimes * cap is found. 10558f0484fSRodney W. Grimes * 10658f0484fSRodney W. Grimes * If (cap, '@') or (cap, terminator, '@') is found before (cap, terminator) 10758f0484fSRodney W. Grimes * return NULL. 10858f0484fSRodney W. Grimes */ 10958f0484fSRodney W. Grimes char * 11058f0484fSRodney W. Grimes cgetcap(buf, cap, type) 11158f0484fSRodney W. Grimes char *buf, *cap; 11258f0484fSRodney W. Grimes int type; 11358f0484fSRodney W. Grimes { 11458f0484fSRodney W. Grimes register char *bp, *cp; 11558f0484fSRodney W. Grimes 11658f0484fSRodney W. Grimes bp = buf; 11758f0484fSRodney W. Grimes for (;;) { 11858f0484fSRodney W. Grimes /* 11958f0484fSRodney W. Grimes * Skip past the current capability field - it's either the 12058f0484fSRodney W. Grimes * name field if this is the first time through the loop, or 12158f0484fSRodney W. Grimes * the remainder of a field whose name failed to match cap. 12258f0484fSRodney W. Grimes */ 12358f0484fSRodney W. Grimes for (;;) 12458f0484fSRodney W. Grimes if (*bp == '\0') 12558f0484fSRodney W. Grimes return (NULL); 12658f0484fSRodney W. Grimes else 12758f0484fSRodney W. Grimes if (*bp++ == ':') 12858f0484fSRodney W. Grimes break; 12958f0484fSRodney W. Grimes 13058f0484fSRodney W. Grimes /* 13158f0484fSRodney W. Grimes * Try to match (cap, type) in buf. 13258f0484fSRodney W. Grimes */ 13358f0484fSRodney W. Grimes for (cp = cap; *cp == *bp && *bp != '\0'; cp++, bp++) 13458f0484fSRodney W. Grimes continue; 13558f0484fSRodney W. Grimes if (*cp != '\0') 13658f0484fSRodney W. Grimes continue; 13758f0484fSRodney W. Grimes if (*bp == '@') 13858f0484fSRodney W. Grimes return (NULL); 13958f0484fSRodney W. Grimes if (type == ':') { 14058f0484fSRodney W. Grimes if (*bp != '\0' && *bp != ':') 14158f0484fSRodney W. Grimes continue; 14258f0484fSRodney W. Grimes return(bp); 14358f0484fSRodney W. Grimes } 14458f0484fSRodney W. Grimes if (*bp != type) 14558f0484fSRodney W. Grimes continue; 14658f0484fSRodney W. Grimes bp++; 14758f0484fSRodney W. Grimes return (*bp == '@' ? NULL : bp); 14858f0484fSRodney W. Grimes } 14958f0484fSRodney W. Grimes /* NOTREACHED */ 15058f0484fSRodney W. Grimes } 15158f0484fSRodney W. Grimes 15258f0484fSRodney W. Grimes /* 15358f0484fSRodney W. Grimes * Cgetent extracts the capability record name from the NULL terminated file 15458f0484fSRodney W. Grimes * array db_array and returns a pointer to a malloc'd copy of it in buf. 15558f0484fSRodney W. Grimes * Buf must be retained through all subsequent calls to cgetcap, cgetnum, 15658f0484fSRodney W. Grimes * cgetflag, and cgetstr, but may then be free'd. 0 is returned on success, 15758f0484fSRodney W. Grimes * -1 if the requested record couldn't be found, -2 if a system error was 15858f0484fSRodney W. Grimes * encountered (couldn't open/read a file, etc.), and -3 if a potential 15958f0484fSRodney W. Grimes * reference loop is detected. 16058f0484fSRodney W. Grimes */ 16158f0484fSRodney W. Grimes int 16258f0484fSRodney W. Grimes cgetent(buf, db_array, name) 16358f0484fSRodney W. Grimes char **buf, **db_array, *name; 16458f0484fSRodney W. Grimes { 16558f0484fSRodney W. Grimes u_int dummy; 16658f0484fSRodney W. Grimes 16758f0484fSRodney W. Grimes return (getent(buf, &dummy, db_array, -1, name, 0, NULL)); 16858f0484fSRodney W. Grimes } 16958f0484fSRodney W. Grimes 17058f0484fSRodney W. Grimes /* 17158f0484fSRodney W. Grimes * Getent implements the functions of cgetent. If fd is non-negative, 17258f0484fSRodney W. Grimes * *db_array has already been opened and fd is the open file descriptor. We 17358f0484fSRodney W. Grimes * do this to save time and avoid using up file descriptors for tc= 17458f0484fSRodney W. Grimes * recursions. 17558f0484fSRodney W. Grimes * 17658f0484fSRodney W. Grimes * Getent returns the same success/failure codes as cgetent. On success, a 17758f0484fSRodney W. Grimes * pointer to a malloc'ed capability record with all tc= capabilities fully 17858f0484fSRodney W. Grimes * expanded and its length (not including trailing ASCII NUL) are left in 17958f0484fSRodney W. Grimes * *cap and *len. 18058f0484fSRodney W. Grimes * 18158f0484fSRodney W. Grimes * Basic algorithm: 18258f0484fSRodney W. Grimes * + Allocate memory incrementally as needed in chunks of size BFRAG 18358f0484fSRodney W. Grimes * for capability buffer. 18458f0484fSRodney W. Grimes * + Recurse for each tc=name and interpolate result. Stop when all 18558f0484fSRodney W. Grimes * names interpolated, a name can't be found, or depth exceeds 18658f0484fSRodney W. Grimes * MAX_RECURSION. 18758f0484fSRodney W. Grimes */ 18858f0484fSRodney W. Grimes static int 18958f0484fSRodney W. Grimes getent(cap, len, db_array, fd, name, depth, nfield) 19058f0484fSRodney W. Grimes char **cap, **db_array, *name, *nfield; 19158f0484fSRodney W. Grimes u_int *len; 19258f0484fSRodney W. Grimes int fd, depth; 19358f0484fSRodney W. Grimes { 19458f0484fSRodney W. Grimes DB *capdbp; 19558f0484fSRodney W. Grimes register char *r_end, *rp, **db_p; 19658f0484fSRodney W. Grimes int myfd, eof, foundit, retval, clen; 19758f0484fSRodney W. Grimes char *record, *cbuf; 19858f0484fSRodney W. Grimes int tc_not_resolved; 19958f0484fSRodney W. Grimes char pbuf[_POSIX_PATH_MAX]; 20058f0484fSRodney W. Grimes 20158f0484fSRodney W. Grimes /* 20258f0484fSRodney W. Grimes * Return with ``loop detected'' error if we've recursed more than 20358f0484fSRodney W. Grimes * MAX_RECURSION times. 20458f0484fSRodney W. Grimes */ 20558f0484fSRodney W. Grimes if (depth > MAX_RECURSION) 20658f0484fSRodney W. Grimes return (-3); 20758f0484fSRodney W. Grimes 20858f0484fSRodney W. Grimes /* 20958f0484fSRodney W. Grimes * Check if we have a top record from cgetset(). 21058f0484fSRodney W. Grimes */ 21158f0484fSRodney W. Grimes if (depth == 0 && toprec != NULL && cgetmatch(toprec, name) == 0) { 21258f0484fSRodney W. Grimes if ((record = malloc (topreclen + BFRAG)) == NULL) { 21358f0484fSRodney W. Grimes errno = ENOMEM; 21458f0484fSRodney W. Grimes return (-2); 21558f0484fSRodney W. Grimes } 21658f0484fSRodney W. Grimes (void)strcpy(record, toprec); 21758f0484fSRodney W. Grimes myfd = 0; 21858f0484fSRodney W. Grimes db_p = db_array; 21958f0484fSRodney W. Grimes rp = record + topreclen + 1; 22058f0484fSRodney W. Grimes r_end = rp + BFRAG; 22158f0484fSRodney W. Grimes goto tc_exp; 22258f0484fSRodney W. Grimes } 22358f0484fSRodney W. Grimes /* 22458f0484fSRodney W. Grimes * Allocate first chunk of memory. 22558f0484fSRodney W. Grimes */ 22658f0484fSRodney W. Grimes if ((record = malloc(BFRAG)) == NULL) { 22758f0484fSRodney W. Grimes errno = ENOMEM; 22858f0484fSRodney W. Grimes return (-2); 22958f0484fSRodney W. Grimes } 23058f0484fSRodney W. Grimes r_end = record + BFRAG; 23158f0484fSRodney W. Grimes foundit = 0; 23258f0484fSRodney W. Grimes /* 23358f0484fSRodney W. Grimes * Loop through database array until finding the record. 23458f0484fSRodney W. Grimes */ 23558f0484fSRodney W. Grimes 23658f0484fSRodney W. Grimes for (db_p = db_array; *db_p != NULL; db_p++) { 23758f0484fSRodney W. Grimes eof = 0; 23858f0484fSRodney W. Grimes 23958f0484fSRodney W. Grimes /* 24058f0484fSRodney W. Grimes * Open database if not already open. 24158f0484fSRodney W. Grimes */ 24258f0484fSRodney W. Grimes 24358f0484fSRodney W. Grimes if (fd >= 0) { 24411ea2762SJohn Polstra (void)lseek(fd, (off_t)0, SEEK_SET); 24558f0484fSRodney W. Grimes myfd = 0; 24658f0484fSRodney W. Grimes } else { 24758f0484fSRodney W. Grimes (void)snprintf(pbuf, sizeof(pbuf), "%s.db", *db_p); 24858f0484fSRodney W. Grimes if ((capdbp = dbopen(pbuf, O_RDONLY, 0, DB_HASH, 0)) 24958f0484fSRodney W. Grimes != NULL) { 25058f0484fSRodney W. Grimes free(record); 25158f0484fSRodney W. Grimes retval = cdbget(capdbp, &record, name); 25258f0484fSRodney W. Grimes if (retval < 0) { 25358f0484fSRodney W. Grimes /* no record available */ 25458f0484fSRodney W. Grimes (void)capdbp->close(capdbp); 25558f0484fSRodney W. Grimes return (retval); 25658f0484fSRodney W. Grimes } 25758f0484fSRodney W. Grimes /* save the data; close frees it */ 25858f0484fSRodney W. Grimes clen = strlen(record); 25958f0484fSRodney W. Grimes cbuf = malloc(clen + 1); 26058f0484fSRodney W. Grimes memcpy(cbuf, record, clen + 1); 26158f0484fSRodney W. Grimes if (capdbp->close(capdbp) < 0) { 26258f0484fSRodney W. Grimes free(cbuf); 26358f0484fSRodney W. Grimes return (-2); 26458f0484fSRodney W. Grimes } 26558f0484fSRodney W. Grimes *len = clen; 26658f0484fSRodney W. Grimes *cap = cbuf; 26758f0484fSRodney W. Grimes return (retval); 26858f0484fSRodney W. Grimes } else { 26958f0484fSRodney W. Grimes fd = open(*db_p, O_RDONLY, 0); 27043b4fd73SWarner Losh if (fd < 0) 27158f0484fSRodney W. Grimes continue; 27258f0484fSRodney W. Grimes myfd = 1; 27358f0484fSRodney W. Grimes } 27458f0484fSRodney W. Grimes } 27558f0484fSRodney W. Grimes /* 27658f0484fSRodney W. Grimes * Find the requested capability record ... 27758f0484fSRodney W. Grimes */ 27858f0484fSRodney W. Grimes { 27958f0484fSRodney W. Grimes char buf[BUFSIZ]; 28058f0484fSRodney W. Grimes register char *b_end, *bp; 28158f0484fSRodney W. Grimes register int c; 28258f0484fSRodney W. Grimes 28358f0484fSRodney W. Grimes /* 28458f0484fSRodney W. Grimes * Loop invariants: 28558f0484fSRodney W. Grimes * There is always room for one more character in record. 28658f0484fSRodney W. Grimes * R_end always points just past end of record. 28758f0484fSRodney W. Grimes * Rp always points just past last character in record. 28858f0484fSRodney W. Grimes * B_end always points just past last character in buf. 28958f0484fSRodney W. Grimes * Bp always points at next character in buf. 29058f0484fSRodney W. Grimes */ 29158f0484fSRodney W. Grimes b_end = buf; 29258f0484fSRodney W. Grimes bp = buf; 29358f0484fSRodney W. Grimes for (;;) { 29458f0484fSRodney W. Grimes 29558f0484fSRodney W. Grimes /* 29658f0484fSRodney W. Grimes * Read in a line implementing (\, newline) 29758f0484fSRodney W. Grimes * line continuation. 29858f0484fSRodney W. Grimes */ 29958f0484fSRodney W. Grimes rp = record; 30058f0484fSRodney W. Grimes for (;;) { 30158f0484fSRodney W. Grimes if (bp >= b_end) { 30258f0484fSRodney W. Grimes int n; 30358f0484fSRodney W. Grimes 30458f0484fSRodney W. Grimes n = read(fd, buf, sizeof(buf)); 30558f0484fSRodney W. Grimes if (n <= 0) { 30658f0484fSRodney W. Grimes if (myfd) 30758f0484fSRodney W. Grimes (void)close(fd); 30858f0484fSRodney W. Grimes if (n < 0) { 30958f0484fSRodney W. Grimes free(record); 31058f0484fSRodney W. Grimes return (-2); 31158f0484fSRodney W. Grimes } else { 31258f0484fSRodney W. Grimes fd = -1; 31358f0484fSRodney W. Grimes eof = 1; 31458f0484fSRodney W. Grimes break; 31558f0484fSRodney W. Grimes } 31658f0484fSRodney W. Grimes } 31758f0484fSRodney W. Grimes b_end = buf+n; 31858f0484fSRodney W. Grimes bp = buf; 31958f0484fSRodney W. Grimes } 32058f0484fSRodney W. Grimes 32158f0484fSRodney W. Grimes c = *bp++; 32258f0484fSRodney W. Grimes if (c == '\n') { 32358f0484fSRodney W. Grimes if (rp > record && *(rp-1) == '\\') { 32458f0484fSRodney W. Grimes rp--; 32558f0484fSRodney W. Grimes continue; 32658f0484fSRodney W. Grimes } else 32758f0484fSRodney W. Grimes break; 32858f0484fSRodney W. Grimes } 32958f0484fSRodney W. Grimes *rp++ = c; 33058f0484fSRodney W. Grimes 33158f0484fSRodney W. Grimes /* 33258f0484fSRodney W. Grimes * Enforce loop invariant: if no room 33358f0484fSRodney W. Grimes * left in record buffer, try to get 33458f0484fSRodney W. Grimes * some more. 33558f0484fSRodney W. Grimes */ 33658f0484fSRodney W. Grimes if (rp >= r_end) { 33758f0484fSRodney W. Grimes u_int pos; 33858f0484fSRodney W. Grimes size_t newsize; 33958f0484fSRodney W. Grimes 34058f0484fSRodney W. Grimes pos = rp - record; 34158f0484fSRodney W. Grimes newsize = r_end - record + BFRAG; 342e8420087SWarner Losh record = reallocf(record, newsize); 34358f0484fSRodney W. Grimes if (record == NULL) { 34458f0484fSRodney W. Grimes errno = ENOMEM; 34558f0484fSRodney W. Grimes if (myfd) 34658f0484fSRodney W. Grimes (void)close(fd); 34758f0484fSRodney W. Grimes return (-2); 34858f0484fSRodney W. Grimes } 34958f0484fSRodney W. Grimes r_end = record + newsize; 35058f0484fSRodney W. Grimes rp = record + pos; 35158f0484fSRodney W. Grimes } 35258f0484fSRodney W. Grimes } 35358f0484fSRodney W. Grimes /* loop invariant let's us do this */ 35458f0484fSRodney W. Grimes *rp++ = '\0'; 35558f0484fSRodney W. Grimes 35658f0484fSRodney W. Grimes /* 35758f0484fSRodney W. Grimes * If encountered eof check next file. 35858f0484fSRodney W. Grimes */ 35958f0484fSRodney W. Grimes if (eof) 36058f0484fSRodney W. Grimes break; 36158f0484fSRodney W. Grimes 36258f0484fSRodney W. Grimes /* 36358f0484fSRodney W. Grimes * Toss blank lines and comments. 36458f0484fSRodney W. Grimes */ 36558f0484fSRodney W. Grimes if (*record == '\0' || *record == '#') 36658f0484fSRodney W. Grimes continue; 36758f0484fSRodney W. Grimes 36858f0484fSRodney W. Grimes /* 36958f0484fSRodney W. Grimes * See if this is the record we want ... 37058f0484fSRodney W. Grimes */ 37158f0484fSRodney W. Grimes if (cgetmatch(record, name) == 0) { 37258f0484fSRodney W. Grimes if (nfield == NULL || !nfcmp(nfield, record)) { 37358f0484fSRodney W. Grimes foundit = 1; 37458f0484fSRodney W. Grimes break; /* found it! */ 37558f0484fSRodney W. Grimes } 37658f0484fSRodney W. Grimes } 37758f0484fSRodney W. Grimes } 37858f0484fSRodney W. Grimes } 37958f0484fSRodney W. Grimes if (foundit) 38058f0484fSRodney W. Grimes break; 38158f0484fSRodney W. Grimes } 38258f0484fSRodney W. Grimes 38358f0484fSRodney W. Grimes if (!foundit) 38458f0484fSRodney W. Grimes return (-1); 38558f0484fSRodney W. Grimes 38658f0484fSRodney W. Grimes /* 38758f0484fSRodney W. Grimes * Got the capability record, but now we have to expand all tc=name 38858f0484fSRodney W. Grimes * references in it ... 38958f0484fSRodney W. Grimes */ 39058f0484fSRodney W. Grimes tc_exp: { 39158f0484fSRodney W. Grimes register char *newicap, *s; 39258f0484fSRodney W. Grimes register int newilen; 39358f0484fSRodney W. Grimes u_int ilen; 39458f0484fSRodney W. Grimes int diff, iret, tclen; 39558f0484fSRodney W. Grimes char *icap, *scan, *tc, *tcstart, *tcend; 39658f0484fSRodney W. Grimes 39758f0484fSRodney W. Grimes /* 39858f0484fSRodney W. Grimes * Loop invariants: 39958f0484fSRodney W. Grimes * There is room for one more character in record. 40058f0484fSRodney W. Grimes * R_end points just past end of record. 40158f0484fSRodney W. Grimes * Rp points just past last character in record. 40258f0484fSRodney W. Grimes * Scan points at remainder of record that needs to be 40358f0484fSRodney W. Grimes * scanned for tc=name constructs. 40458f0484fSRodney W. Grimes */ 40558f0484fSRodney W. Grimes scan = record; 40658f0484fSRodney W. Grimes tc_not_resolved = 0; 40758f0484fSRodney W. Grimes for (;;) { 40858f0484fSRodney W. Grimes if ((tc = cgetcap(scan, "tc", '=')) == NULL) 40958f0484fSRodney W. Grimes break; 41058f0484fSRodney W. Grimes 41158f0484fSRodney W. Grimes /* 41258f0484fSRodney W. Grimes * Find end of tc=name and stomp on the trailing `:' 41358f0484fSRodney W. Grimes * (if present) so we can use it to call ourselves. 41458f0484fSRodney W. Grimes */ 41558f0484fSRodney W. Grimes s = tc; 41658f0484fSRodney W. Grimes for (;;) 41758f0484fSRodney W. Grimes if (*s == '\0') 41858f0484fSRodney W. Grimes break; 41958f0484fSRodney W. Grimes else 42058f0484fSRodney W. Grimes if (*s++ == ':') { 42158f0484fSRodney W. Grimes *(s - 1) = '\0'; 42258f0484fSRodney W. Grimes break; 42358f0484fSRodney W. Grimes } 42458f0484fSRodney W. Grimes tcstart = tc - 3; 42558f0484fSRodney W. Grimes tclen = s - tcstart; 42658f0484fSRodney W. Grimes tcend = s; 42758f0484fSRodney W. Grimes 42858f0484fSRodney W. Grimes iret = getent(&icap, &ilen, db_p, fd, tc, depth+1, 42958f0484fSRodney W. Grimes NULL); 43058f0484fSRodney W. Grimes newicap = icap; /* Put into a register. */ 43158f0484fSRodney W. Grimes newilen = ilen; 43258f0484fSRodney W. Grimes if (iret != 0) { 43358f0484fSRodney W. Grimes /* an error */ 43458f0484fSRodney W. Grimes if (iret < -1) { 43558f0484fSRodney W. Grimes if (myfd) 43658f0484fSRodney W. Grimes (void)close(fd); 43758f0484fSRodney W. Grimes free(record); 43858f0484fSRodney W. Grimes return (iret); 43958f0484fSRodney W. Grimes } 44058f0484fSRodney W. Grimes if (iret == 1) 44158f0484fSRodney W. Grimes tc_not_resolved = 1; 44258f0484fSRodney W. Grimes /* couldn't resolve tc */ 44358f0484fSRodney W. Grimes if (iret == -1) { 44458f0484fSRodney W. Grimes *(s - 1) = ':'; 44558f0484fSRodney W. Grimes scan = s - 1; 44658f0484fSRodney W. Grimes tc_not_resolved = 1; 44758f0484fSRodney W. Grimes continue; 44858f0484fSRodney W. Grimes 44958f0484fSRodney W. Grimes } 45058f0484fSRodney W. Grimes } 45158f0484fSRodney W. Grimes /* not interested in name field of tc'ed record */ 45258f0484fSRodney W. Grimes s = newicap; 45358f0484fSRodney W. Grimes for (;;) 45458f0484fSRodney W. Grimes if (*s == '\0') 45558f0484fSRodney W. Grimes break; 45658f0484fSRodney W. Grimes else 45758f0484fSRodney W. Grimes if (*s++ == ':') 45858f0484fSRodney W. Grimes break; 45958f0484fSRodney W. Grimes newilen -= s - newicap; 46058f0484fSRodney W. Grimes newicap = s; 46158f0484fSRodney W. Grimes 46258f0484fSRodney W. Grimes /* make sure interpolated record is `:'-terminated */ 46358f0484fSRodney W. Grimes s += newilen; 46458f0484fSRodney W. Grimes if (*(s-1) != ':') { 46558f0484fSRodney W. Grimes *s = ':'; /* overwrite NUL with : */ 46658f0484fSRodney W. Grimes newilen++; 46758f0484fSRodney W. Grimes } 46858f0484fSRodney W. Grimes 46958f0484fSRodney W. Grimes /* 47058f0484fSRodney W. Grimes * Make sure there's enough room to insert the 47158f0484fSRodney W. Grimes * new record. 47258f0484fSRodney W. Grimes */ 47358f0484fSRodney W. Grimes diff = newilen - tclen; 47458f0484fSRodney W. Grimes if (diff >= r_end - rp) { 47558f0484fSRodney W. Grimes u_int pos, tcpos, tcposend; 47658f0484fSRodney W. Grimes size_t newsize; 47758f0484fSRodney W. Grimes 47858f0484fSRodney W. Grimes pos = rp - record; 47958f0484fSRodney W. Grimes newsize = r_end - record + diff + BFRAG; 48058f0484fSRodney W. Grimes tcpos = tcstart - record; 48158f0484fSRodney W. Grimes tcposend = tcend - record; 482e8420087SWarner Losh record = reallocf(record, newsize); 48358f0484fSRodney W. Grimes if (record == NULL) { 48458f0484fSRodney W. Grimes errno = ENOMEM; 48558f0484fSRodney W. Grimes if (myfd) 48658f0484fSRodney W. Grimes (void)close(fd); 48758f0484fSRodney W. Grimes free(icap); 48858f0484fSRodney W. Grimes return (-2); 48958f0484fSRodney W. Grimes } 49058f0484fSRodney W. Grimes r_end = record + newsize; 49158f0484fSRodney W. Grimes rp = record + pos; 49258f0484fSRodney W. Grimes tcstart = record + tcpos; 49358f0484fSRodney W. Grimes tcend = record + tcposend; 49458f0484fSRodney W. Grimes } 49558f0484fSRodney W. Grimes 49658f0484fSRodney W. Grimes /* 49758f0484fSRodney W. Grimes * Insert tc'ed record into our record. 49858f0484fSRodney W. Grimes */ 49958f0484fSRodney W. Grimes s = tcstart + newilen; 50058f0484fSRodney W. Grimes bcopy(tcend, s, rp - tcend); 50158f0484fSRodney W. Grimes bcopy(newicap, tcstart, newilen); 50258f0484fSRodney W. Grimes rp += diff; 50358f0484fSRodney W. Grimes free(icap); 50458f0484fSRodney W. Grimes 50558f0484fSRodney W. Grimes /* 50658f0484fSRodney W. Grimes * Start scan on `:' so next cgetcap works properly 50758f0484fSRodney W. Grimes * (cgetcap always skips first field). 50858f0484fSRodney W. Grimes */ 50958f0484fSRodney W. Grimes scan = s-1; 51058f0484fSRodney W. Grimes } 51158f0484fSRodney W. Grimes 51258f0484fSRodney W. Grimes } 51358f0484fSRodney W. Grimes /* 51458f0484fSRodney W. Grimes * Close file (if we opened it), give back any extra memory, and 51558f0484fSRodney W. Grimes * return capability, length and success. 51658f0484fSRodney W. Grimes */ 51758f0484fSRodney W. Grimes if (myfd) 51858f0484fSRodney W. Grimes (void)close(fd); 51958f0484fSRodney W. Grimes *len = rp - record - 1; /* don't count NUL */ 52058f0484fSRodney W. Grimes if (r_end > rp) 52158f0484fSRodney W. Grimes if ((record = 522e8420087SWarner Losh reallocf(record, (size_t)(rp - record))) == NULL) { 52358f0484fSRodney W. Grimes errno = ENOMEM; 52458f0484fSRodney W. Grimes return (-2); 52558f0484fSRodney W. Grimes } 52658f0484fSRodney W. Grimes 52758f0484fSRodney W. Grimes *cap = record; 52858f0484fSRodney W. Grimes if (tc_not_resolved) 52958f0484fSRodney W. Grimes return (1); 53058f0484fSRodney W. Grimes return (0); 53158f0484fSRodney W. Grimes } 53258f0484fSRodney W. Grimes 53358f0484fSRodney W. Grimes static int 53458f0484fSRodney W. Grimes cdbget(capdbp, bp, name) 53558f0484fSRodney W. Grimes DB *capdbp; 53658f0484fSRodney W. Grimes char **bp, *name; 53758f0484fSRodney W. Grimes { 53858f0484fSRodney W. Grimes DBT key, data; 53958f0484fSRodney W. Grimes 54058f0484fSRodney W. Grimes key.data = name; 54158f0484fSRodney W. Grimes key.size = strlen(name); 54258f0484fSRodney W. Grimes 54358f0484fSRodney W. Grimes for (;;) { 54458f0484fSRodney W. Grimes /* Get the reference. */ 54558f0484fSRodney W. Grimes switch(capdbp->get(capdbp, &key, &data, 0)) { 54658f0484fSRodney W. Grimes case -1: 54758f0484fSRodney W. Grimes return (-2); 54858f0484fSRodney W. Grimes case 1: 54958f0484fSRodney W. Grimes return (-1); 55058f0484fSRodney W. Grimes } 55158f0484fSRodney W. Grimes 55258f0484fSRodney W. Grimes /* If not an index to another record, leave. */ 55358f0484fSRodney W. Grimes if (((char *)data.data)[0] != SHADOW) 55458f0484fSRodney W. Grimes break; 55558f0484fSRodney W. Grimes 55658f0484fSRodney W. Grimes key.data = (char *)data.data + 1; 55758f0484fSRodney W. Grimes key.size = data.size - 1; 55858f0484fSRodney W. Grimes } 55958f0484fSRodney W. Grimes 56058f0484fSRodney W. Grimes *bp = (char *)data.data + 1; 56158f0484fSRodney W. Grimes return (((char *)(data.data))[0] == TCERR ? 1 : 0); 56258f0484fSRodney W. Grimes } 56358f0484fSRodney W. Grimes 56458f0484fSRodney W. Grimes /* 56558f0484fSRodney W. Grimes * Cgetmatch will return 0 if name is one of the names of the capability 56658f0484fSRodney W. Grimes * record buf, -1 if not. 56758f0484fSRodney W. Grimes */ 56858f0484fSRodney W. Grimes int 56958f0484fSRodney W. Grimes cgetmatch(buf, name) 57058f0484fSRodney W. Grimes char *buf, *name; 57158f0484fSRodney W. Grimes { 57258f0484fSRodney W. Grimes register char *np, *bp; 57358f0484fSRodney W. Grimes 57458f0484fSRodney W. Grimes /* 57558f0484fSRodney W. Grimes * Start search at beginning of record. 57658f0484fSRodney W. Grimes */ 57758f0484fSRodney W. Grimes bp = buf; 57858f0484fSRodney W. Grimes for (;;) { 57958f0484fSRodney W. Grimes /* 58058f0484fSRodney W. Grimes * Try to match a record name. 58158f0484fSRodney W. Grimes */ 58258f0484fSRodney W. Grimes np = name; 58358f0484fSRodney W. Grimes for (;;) 58458f0484fSRodney W. Grimes if (*np == '\0') 58558f0484fSRodney W. Grimes if (*bp == '|' || *bp == ':' || *bp == '\0') 58658f0484fSRodney W. Grimes return (0); 58758f0484fSRodney W. Grimes else 58858f0484fSRodney W. Grimes break; 58958f0484fSRodney W. Grimes else 59058f0484fSRodney W. Grimes if (*bp++ != *np++) 59158f0484fSRodney W. Grimes break; 59258f0484fSRodney W. Grimes 59358f0484fSRodney W. Grimes /* 59458f0484fSRodney W. Grimes * Match failed, skip to next name in record. 59558f0484fSRodney W. Grimes */ 59658f0484fSRodney W. Grimes bp--; /* a '|' or ':' may have stopped the match */ 59758f0484fSRodney W. Grimes for (;;) 59858f0484fSRodney W. Grimes if (*bp == '\0' || *bp == ':') 59958f0484fSRodney W. Grimes return (-1); /* match failed totally */ 60058f0484fSRodney W. Grimes else 60158f0484fSRodney W. Grimes if (*bp++ == '|') 60258f0484fSRodney W. Grimes break; /* found next name */ 60358f0484fSRodney W. Grimes } 60458f0484fSRodney W. Grimes } 60558f0484fSRodney W. Grimes 60658f0484fSRodney W. Grimes 60758f0484fSRodney W. Grimes 60858f0484fSRodney W. Grimes 60958f0484fSRodney W. Grimes 61058f0484fSRodney W. Grimes int 61158f0484fSRodney W. Grimes cgetfirst(buf, db_array) 61258f0484fSRodney W. Grimes char **buf, **db_array; 61358f0484fSRodney W. Grimes { 61458f0484fSRodney W. Grimes (void)cgetclose(); 61558f0484fSRodney W. Grimes return (cgetnext(buf, db_array)); 61658f0484fSRodney W. Grimes } 61758f0484fSRodney W. Grimes 61858f0484fSRodney W. Grimes static FILE *pfp; 61958f0484fSRodney W. Grimes static int slash; 62058f0484fSRodney W. Grimes static char **dbp; 62158f0484fSRodney W. Grimes 62258f0484fSRodney W. Grimes int 62358f0484fSRodney W. Grimes cgetclose() 62458f0484fSRodney W. Grimes { 62558f0484fSRodney W. Grimes if (pfp != NULL) { 62658f0484fSRodney W. Grimes (void)fclose(pfp); 62758f0484fSRodney W. Grimes pfp = NULL; 62858f0484fSRodney W. Grimes } 62958f0484fSRodney W. Grimes dbp = NULL; 63058f0484fSRodney W. Grimes gottoprec = 0; 63158f0484fSRodney W. Grimes slash = 0; 63258f0484fSRodney W. Grimes return(0); 63358f0484fSRodney W. Grimes } 63458f0484fSRodney W. Grimes 63558f0484fSRodney W. Grimes /* 63658f0484fSRodney W. Grimes * Cgetnext() gets either the first or next entry in the logical database 63758f0484fSRodney W. Grimes * specified by db_array. It returns 0 upon completion of the database, 1 63858f0484fSRodney W. Grimes * upon returning an entry with more remaining, and -1 if an error occurs. 63958f0484fSRodney W. Grimes */ 64058f0484fSRodney W. Grimes int 64158f0484fSRodney W. Grimes cgetnext(bp, db_array) 64258f0484fSRodney W. Grimes register char **bp; 64358f0484fSRodney W. Grimes char **db_array; 64458f0484fSRodney W. Grimes { 64558f0484fSRodney W. Grimes size_t len; 64658f0484fSRodney W. Grimes int status, i, done; 64758f0484fSRodney W. Grimes char *cp, *line, *rp, *np, buf[BSIZE], nbuf[BSIZE]; 64858f0484fSRodney W. Grimes u_int dummy; 64958f0484fSRodney W. Grimes 65058f0484fSRodney W. Grimes if (dbp == NULL) 65158f0484fSRodney W. Grimes dbp = db_array; 65258f0484fSRodney W. Grimes 65358f0484fSRodney W. Grimes if (pfp == NULL && (pfp = fopen(*dbp, "r")) == NULL) { 65458f0484fSRodney W. Grimes (void)cgetclose(); 65558f0484fSRodney W. Grimes return (-1); 65658f0484fSRodney W. Grimes } 65758f0484fSRodney W. Grimes for(;;) { 65858f0484fSRodney W. Grimes if (toprec && !gottoprec) { 65958f0484fSRodney W. Grimes gottoprec = 1; 66058f0484fSRodney W. Grimes line = toprec; 66158f0484fSRodney W. Grimes } else { 66258f0484fSRodney W. Grimes line = fgetln(pfp, &len); 66358f0484fSRodney W. Grimes if (line == NULL && pfp) { 66458f0484fSRodney W. Grimes (void)fclose(pfp); 66558f0484fSRodney W. Grimes if (ferror(pfp)) { 66658f0484fSRodney W. Grimes (void)cgetclose(); 66758f0484fSRodney W. Grimes return (-1); 66858f0484fSRodney W. Grimes } else { 66958f0484fSRodney W. Grimes if (*++dbp == NULL) { 67058f0484fSRodney W. Grimes (void)cgetclose(); 67158f0484fSRodney W. Grimes return (0); 67258f0484fSRodney W. Grimes } else if ((pfp = 67358f0484fSRodney W. Grimes fopen(*dbp, "r")) == NULL) { 67458f0484fSRodney W. Grimes (void)cgetclose(); 67558f0484fSRodney W. Grimes return (-1); 67658f0484fSRodney W. Grimes } else 67758f0484fSRodney W. Grimes continue; 67858f0484fSRodney W. Grimes } 67958f0484fSRodney W. Grimes } else 68058f0484fSRodney W. Grimes line[len - 1] = '\0'; 68158f0484fSRodney W. Grimes if (len == 1) { 68258f0484fSRodney W. Grimes slash = 0; 68358f0484fSRodney W. Grimes continue; 68458f0484fSRodney W. Grimes } 68558f0484fSRodney W. Grimes if (isspace(*line) || 68658f0484fSRodney W. Grimes *line == ':' || *line == '#' || slash) { 68758f0484fSRodney W. Grimes if (line[len - 2] == '\\') 68858f0484fSRodney W. Grimes slash = 1; 68958f0484fSRodney W. Grimes else 69058f0484fSRodney W. Grimes slash = 0; 69158f0484fSRodney W. Grimes continue; 69258f0484fSRodney W. Grimes } 69358f0484fSRodney W. Grimes if (line[len - 2] == '\\') 69458f0484fSRodney W. Grimes slash = 1; 69558f0484fSRodney W. Grimes else 69658f0484fSRodney W. Grimes slash = 0; 69758f0484fSRodney W. Grimes } 69858f0484fSRodney W. Grimes 69958f0484fSRodney W. Grimes 70058f0484fSRodney W. Grimes /* 70158f0484fSRodney W. Grimes * Line points to a name line. 70258f0484fSRodney W. Grimes */ 70358f0484fSRodney W. Grimes i = 0; 70458f0484fSRodney W. Grimes done = 0; 70558f0484fSRodney W. Grimes np = nbuf; 70658f0484fSRodney W. Grimes for (;;) { 70758f0484fSRodney W. Grimes for (cp = line; *cp != '\0'; cp++) { 70858f0484fSRodney W. Grimes if (*cp == ':') { 70958f0484fSRodney W. Grimes *np++ = ':'; 71058f0484fSRodney W. Grimes done = 1; 71158f0484fSRodney W. Grimes break; 71258f0484fSRodney W. Grimes } 71358f0484fSRodney W. Grimes if (*cp == '\\') 71458f0484fSRodney W. Grimes break; 71558f0484fSRodney W. Grimes *np++ = *cp; 71658f0484fSRodney W. Grimes } 71758f0484fSRodney W. Grimes if (done) { 71858f0484fSRodney W. Grimes *np = '\0'; 71958f0484fSRodney W. Grimes break; 72058f0484fSRodney W. Grimes } else { /* name field extends beyond the line */ 72158f0484fSRodney W. Grimes line = fgetln(pfp, &len); 72258f0484fSRodney W. Grimes if (line == NULL && pfp) { 72358f0484fSRodney W. Grimes (void)fclose(pfp); 72458f0484fSRodney W. Grimes if (ferror(pfp)) { 72558f0484fSRodney W. Grimes (void)cgetclose(); 72658f0484fSRodney W. Grimes return (-1); 72758f0484fSRodney W. Grimes } 72858f0484fSRodney W. Grimes } else 72958f0484fSRodney W. Grimes line[len - 1] = '\0'; 73058f0484fSRodney W. Grimes } 73158f0484fSRodney W. Grimes } 73258f0484fSRodney W. Grimes rp = buf; 733d030d2d2SPoul-Henning Kamp for(cp = nbuf; *cp != '\0'; cp++) 73458f0484fSRodney W. Grimes if (*cp == '|' || *cp == ':') 73558f0484fSRodney W. Grimes break; 73658f0484fSRodney W. Grimes else 73758f0484fSRodney W. Grimes *rp++ = *cp; 73858f0484fSRodney W. Grimes 73958f0484fSRodney W. Grimes *rp = '\0'; 74058f0484fSRodney W. Grimes /* 74158f0484fSRodney W. Grimes * XXX 74258f0484fSRodney W. Grimes * Last argument of getent here should be nbuf if we want true 74358f0484fSRodney W. Grimes * sequential access in the case of duplicates. 74458f0484fSRodney W. Grimes * With NULL, getent will return the first entry found 74558f0484fSRodney W. Grimes * rather than the duplicate entry record. This is a 74658f0484fSRodney W. Grimes * matter of semantics that should be resolved. 74758f0484fSRodney W. Grimes */ 74858f0484fSRodney W. Grimes status = getent(bp, &dummy, db_array, -1, buf, 0, NULL); 74958f0484fSRodney W. Grimes if (status == -2 || status == -3) 75058f0484fSRodney W. Grimes (void)cgetclose(); 75158f0484fSRodney W. Grimes 75258f0484fSRodney W. Grimes return (status + 1); 75358f0484fSRodney W. Grimes } 75458f0484fSRodney W. Grimes /* NOTREACHED */ 75558f0484fSRodney W. Grimes } 75658f0484fSRodney W. Grimes 75758f0484fSRodney W. Grimes /* 75858f0484fSRodney W. Grimes * Cgetstr retrieves the value of the string capability cap from the 75958f0484fSRodney W. Grimes * capability record pointed to by buf. A pointer to a decoded, NUL 76058f0484fSRodney W. Grimes * terminated, malloc'd copy of the string is returned in the char * 76158f0484fSRodney W. Grimes * pointed to by str. The length of the string not including the trailing 76258f0484fSRodney W. Grimes * NUL is returned on success, -1 if the requested string capability 76358f0484fSRodney W. Grimes * couldn't be found, -2 if a system error was encountered (storage 76458f0484fSRodney W. Grimes * allocation failure). 76558f0484fSRodney W. Grimes */ 76658f0484fSRodney W. Grimes int 76758f0484fSRodney W. Grimes cgetstr(buf, cap, str) 76858f0484fSRodney W. Grimes char *buf, *cap; 76958f0484fSRodney W. Grimes char **str; 77058f0484fSRodney W. Grimes { 77158f0484fSRodney W. Grimes register u_int m_room; 77258f0484fSRodney W. Grimes register char *bp, *mp; 77358f0484fSRodney W. Grimes int len; 77458f0484fSRodney W. Grimes char *mem; 77558f0484fSRodney W. Grimes 77658f0484fSRodney W. Grimes /* 77758f0484fSRodney W. Grimes * Find string capability cap 77858f0484fSRodney W. Grimes */ 77958f0484fSRodney W. Grimes bp = cgetcap(buf, cap, '='); 78058f0484fSRodney W. Grimes if (bp == NULL) 78158f0484fSRodney W. Grimes return (-1); 78258f0484fSRodney W. Grimes 78358f0484fSRodney W. Grimes /* 78458f0484fSRodney W. Grimes * Conversion / storage allocation loop ... Allocate memory in 78558f0484fSRodney W. Grimes * chunks SFRAG in size. 78658f0484fSRodney W. Grimes */ 78758f0484fSRodney W. Grimes if ((mem = malloc(SFRAG)) == NULL) { 78858f0484fSRodney W. Grimes errno = ENOMEM; 78958f0484fSRodney W. Grimes return (-2); /* couldn't even allocate the first fragment */ 79058f0484fSRodney W. Grimes } 79158f0484fSRodney W. Grimes m_room = SFRAG; 79258f0484fSRodney W. Grimes mp = mem; 79358f0484fSRodney W. Grimes 79458f0484fSRodney W. Grimes while (*bp != ':' && *bp != '\0') { 79558f0484fSRodney W. Grimes /* 79658f0484fSRodney W. Grimes * Loop invariants: 79758f0484fSRodney W. Grimes * There is always room for one more character in mem. 79858f0484fSRodney W. Grimes * Mp always points just past last character in mem. 79958f0484fSRodney W. Grimes * Bp always points at next character in buf. 80058f0484fSRodney W. Grimes */ 80158f0484fSRodney W. Grimes if (*bp == '^') { 80258f0484fSRodney W. Grimes bp++; 80358f0484fSRodney W. Grimes if (*bp == ':' || *bp == '\0') 80458f0484fSRodney W. Grimes break; /* drop unfinished escape */ 8054f512989SAndrey A. Chernov if (*bp == '?') { 8064f512989SAndrey A. Chernov *mp++ = '\177'; 8074f512989SAndrey A. Chernov bp++; 8084f512989SAndrey A. Chernov } else 80958f0484fSRodney W. Grimes *mp++ = *bp++ & 037; 81058f0484fSRodney W. Grimes } else if (*bp == '\\') { 81158f0484fSRodney W. Grimes bp++; 81258f0484fSRodney W. Grimes if (*bp == ':' || *bp == '\0') 81358f0484fSRodney W. Grimes break; /* drop unfinished escape */ 81458f0484fSRodney W. Grimes if ('0' <= *bp && *bp <= '7') { 81558f0484fSRodney W. Grimes register int n, i; 81658f0484fSRodney W. Grimes 81758f0484fSRodney W. Grimes n = 0; 81858f0484fSRodney W. Grimes i = 3; /* maximum of three octal digits */ 81958f0484fSRodney W. Grimes do { 82058f0484fSRodney W. Grimes n = n * 8 + (*bp++ - '0'); 82158f0484fSRodney W. Grimes } while (--i && '0' <= *bp && *bp <= '7'); 82258f0484fSRodney W. Grimes *mp++ = n; 82358f0484fSRodney W. Grimes } 82458f0484fSRodney W. Grimes else switch (*bp++) { 82558f0484fSRodney W. Grimes case 'b': case 'B': 82658f0484fSRodney W. Grimes *mp++ = '\b'; 82758f0484fSRodney W. Grimes break; 82858f0484fSRodney W. Grimes case 't': case 'T': 82958f0484fSRodney W. Grimes *mp++ = '\t'; 83058f0484fSRodney W. Grimes break; 83158f0484fSRodney W. Grimes case 'n': case 'N': 83258f0484fSRodney W. Grimes *mp++ = '\n'; 83358f0484fSRodney W. Grimes break; 83458f0484fSRodney W. Grimes case 'f': case 'F': 83558f0484fSRodney W. Grimes *mp++ = '\f'; 83658f0484fSRodney W. Grimes break; 83758f0484fSRodney W. Grimes case 'r': case 'R': 83858f0484fSRodney W. Grimes *mp++ = '\r'; 83958f0484fSRodney W. Grimes break; 84058f0484fSRodney W. Grimes case 'e': case 'E': 84158f0484fSRodney W. Grimes *mp++ = ESC; 84258f0484fSRodney W. Grimes break; 84358f0484fSRodney W. Grimes case 'c': case 'C': 84458f0484fSRodney W. Grimes *mp++ = ':'; 84558f0484fSRodney W. Grimes break; 84658f0484fSRodney W. Grimes default: 84758f0484fSRodney W. Grimes /* 84858f0484fSRodney W. Grimes * Catches '\', '^', and 84958f0484fSRodney W. Grimes * everything else. 85058f0484fSRodney W. Grimes */ 85158f0484fSRodney W. Grimes *mp++ = *(bp-1); 85258f0484fSRodney W. Grimes break; 85358f0484fSRodney W. Grimes } 85458f0484fSRodney W. Grimes } else 85558f0484fSRodney W. Grimes *mp++ = *bp++; 85658f0484fSRodney W. Grimes m_room--; 85758f0484fSRodney W. Grimes 85858f0484fSRodney W. Grimes /* 85958f0484fSRodney W. Grimes * Enforce loop invariant: if no room left in current 86058f0484fSRodney W. Grimes * buffer, try to get some more. 86158f0484fSRodney W. Grimes */ 86258f0484fSRodney W. Grimes if (m_room == 0) { 86358f0484fSRodney W. Grimes size_t size = mp - mem; 86458f0484fSRodney W. Grimes 865e8420087SWarner Losh if ((mem = reallocf(mem, size + SFRAG)) == NULL) 86658f0484fSRodney W. Grimes return (-2); 86758f0484fSRodney W. Grimes m_room = SFRAG; 86858f0484fSRodney W. Grimes mp = mem + size; 86958f0484fSRodney W. Grimes } 87058f0484fSRodney W. Grimes } 87158f0484fSRodney W. Grimes *mp++ = '\0'; /* loop invariant let's us do this */ 87258f0484fSRodney W. Grimes m_room--; 87358f0484fSRodney W. Grimes len = mp - mem - 1; 87458f0484fSRodney W. Grimes 87558f0484fSRodney W. Grimes /* 87658f0484fSRodney W. Grimes * Give back any extra memory and return value and success. 87758f0484fSRodney W. Grimes */ 87858f0484fSRodney W. Grimes if (m_room != 0) 879e8420087SWarner Losh if ((mem = reallocf(mem, (size_t)(mp - mem))) == NULL) 88058f0484fSRodney W. Grimes return (-2); 88158f0484fSRodney W. Grimes *str = mem; 88258f0484fSRodney W. Grimes return (len); 88358f0484fSRodney W. Grimes } 88458f0484fSRodney W. Grimes 88558f0484fSRodney W. Grimes /* 88658f0484fSRodney W. Grimes * Cgetustr retrieves the value of the string capability cap from the 88758f0484fSRodney W. Grimes * capability record pointed to by buf. The difference between cgetustr() 88858f0484fSRodney W. Grimes * and cgetstr() is that cgetustr does not decode escapes but rather treats 88958f0484fSRodney W. Grimes * all characters literally. A pointer to a NUL terminated malloc'd 89058f0484fSRodney W. Grimes * copy of the string is returned in the char pointed to by str. The 89158f0484fSRodney W. Grimes * length of the string not including the trailing NUL is returned on success, 89258f0484fSRodney W. Grimes * -1 if the requested string capability couldn't be found, -2 if a system 89358f0484fSRodney W. Grimes * error was encountered (storage allocation failure). 89458f0484fSRodney W. Grimes */ 89558f0484fSRodney W. Grimes int 89658f0484fSRodney W. Grimes cgetustr(buf, cap, str) 89758f0484fSRodney W. Grimes char *buf, *cap, **str; 89858f0484fSRodney W. Grimes { 89958f0484fSRodney W. Grimes register u_int m_room; 90058f0484fSRodney W. Grimes register char *bp, *mp; 90158f0484fSRodney W. Grimes int len; 90258f0484fSRodney W. Grimes char *mem; 90358f0484fSRodney W. Grimes 90458f0484fSRodney W. Grimes /* 90558f0484fSRodney W. Grimes * Find string capability cap 90658f0484fSRodney W. Grimes */ 90758f0484fSRodney W. Grimes if ((bp = cgetcap(buf, cap, '=')) == NULL) 90858f0484fSRodney W. Grimes return (-1); 90958f0484fSRodney W. Grimes 91058f0484fSRodney W. Grimes /* 91158f0484fSRodney W. Grimes * Conversion / storage allocation loop ... Allocate memory in 91258f0484fSRodney W. Grimes * chunks SFRAG in size. 91358f0484fSRodney W. Grimes */ 91458f0484fSRodney W. Grimes if ((mem = malloc(SFRAG)) == NULL) { 91558f0484fSRodney W. Grimes errno = ENOMEM; 91658f0484fSRodney W. Grimes return (-2); /* couldn't even allocate the first fragment */ 91758f0484fSRodney W. Grimes } 91858f0484fSRodney W. Grimes m_room = SFRAG; 91958f0484fSRodney W. Grimes mp = mem; 92058f0484fSRodney W. Grimes 92158f0484fSRodney W. Grimes while (*bp != ':' && *bp != '\0') { 92258f0484fSRodney W. Grimes /* 92358f0484fSRodney W. Grimes * Loop invariants: 92458f0484fSRodney W. Grimes * There is always room for one more character in mem. 92558f0484fSRodney W. Grimes * Mp always points just past last character in mem. 92658f0484fSRodney W. Grimes * Bp always points at next character in buf. 92758f0484fSRodney W. Grimes */ 92858f0484fSRodney W. Grimes *mp++ = *bp++; 92958f0484fSRodney W. Grimes m_room--; 93058f0484fSRodney W. Grimes 93158f0484fSRodney W. Grimes /* 93258f0484fSRodney W. Grimes * Enforce loop invariant: if no room left in current 93358f0484fSRodney W. Grimes * buffer, try to get some more. 93458f0484fSRodney W. Grimes */ 93558f0484fSRodney W. Grimes if (m_room == 0) { 93658f0484fSRodney W. Grimes size_t size = mp - mem; 93758f0484fSRodney W. Grimes 938e8420087SWarner Losh if ((mem = reallocf(mem, size + SFRAG)) == NULL) 93958f0484fSRodney W. Grimes return (-2); 94058f0484fSRodney W. Grimes m_room = SFRAG; 94158f0484fSRodney W. Grimes mp = mem + size; 94258f0484fSRodney W. Grimes } 94358f0484fSRodney W. Grimes } 94458f0484fSRodney W. Grimes *mp++ = '\0'; /* loop invariant let's us do this */ 94558f0484fSRodney W. Grimes m_room--; 94658f0484fSRodney W. Grimes len = mp - mem - 1; 94758f0484fSRodney W. Grimes 94858f0484fSRodney W. Grimes /* 94958f0484fSRodney W. Grimes * Give back any extra memory and return value and success. 95058f0484fSRodney W. Grimes */ 95158f0484fSRodney W. Grimes if (m_room != 0) 952e8420087SWarner Losh if ((mem = reallocf(mem, (size_t)(mp - mem))) == NULL) 95358f0484fSRodney W. Grimes return (-2); 95458f0484fSRodney W. Grimes *str = mem; 95558f0484fSRodney W. Grimes return (len); 95658f0484fSRodney W. Grimes } 95758f0484fSRodney W. Grimes 95858f0484fSRodney W. Grimes /* 95958f0484fSRodney W. Grimes * Cgetnum retrieves the value of the numeric capability cap from the 96058f0484fSRodney W. Grimes * capability record pointed to by buf. The numeric value is returned in 96158f0484fSRodney W. Grimes * the long pointed to by num. 0 is returned on success, -1 if the requested 96258f0484fSRodney W. Grimes * numeric capability couldn't be found. 96358f0484fSRodney W. Grimes */ 96458f0484fSRodney W. Grimes int 96558f0484fSRodney W. Grimes cgetnum(buf, cap, num) 96658f0484fSRodney W. Grimes char *buf, *cap; 96758f0484fSRodney W. Grimes long *num; 96858f0484fSRodney W. Grimes { 96958f0484fSRodney W. Grimes register long n; 97058f0484fSRodney W. Grimes register int base, digit; 97158f0484fSRodney W. Grimes register char *bp; 97258f0484fSRodney W. Grimes 97358f0484fSRodney W. Grimes /* 97458f0484fSRodney W. Grimes * Find numeric capability cap 97558f0484fSRodney W. Grimes */ 97658f0484fSRodney W. Grimes bp = cgetcap(buf, cap, '#'); 97758f0484fSRodney W. Grimes if (bp == NULL) 97858f0484fSRodney W. Grimes return (-1); 97958f0484fSRodney W. Grimes 98058f0484fSRodney W. Grimes /* 98158f0484fSRodney W. Grimes * Look at value and determine numeric base: 98258f0484fSRodney W. Grimes * 0x... or 0X... hexadecimal, 98358f0484fSRodney W. Grimes * else 0... octal, 98458f0484fSRodney W. Grimes * else decimal. 98558f0484fSRodney W. Grimes */ 98658f0484fSRodney W. Grimes if (*bp == '0') { 98758f0484fSRodney W. Grimes bp++; 98858f0484fSRodney W. Grimes if (*bp == 'x' || *bp == 'X') { 98958f0484fSRodney W. Grimes bp++; 99058f0484fSRodney W. Grimes base = 16; 99158f0484fSRodney W. Grimes } else 99258f0484fSRodney W. Grimes base = 8; 99358f0484fSRodney W. Grimes } else 99458f0484fSRodney W. Grimes base = 10; 99558f0484fSRodney W. Grimes 99658f0484fSRodney W. Grimes /* 99758f0484fSRodney W. Grimes * Conversion loop ... 99858f0484fSRodney W. Grimes */ 99958f0484fSRodney W. Grimes n = 0; 100058f0484fSRodney W. Grimes for (;;) { 100158f0484fSRodney W. Grimes if ('0' <= *bp && *bp <= '9') 100258f0484fSRodney W. Grimes digit = *bp - '0'; 100358f0484fSRodney W. Grimes else if ('a' <= *bp && *bp <= 'f') 100458f0484fSRodney W. Grimes digit = 10 + *bp - 'a'; 100558f0484fSRodney W. Grimes else if ('A' <= *bp && *bp <= 'F') 100658f0484fSRodney W. Grimes digit = 10 + *bp - 'A'; 100758f0484fSRodney W. Grimes else 100858f0484fSRodney W. Grimes break; 100958f0484fSRodney W. Grimes 101058f0484fSRodney W. Grimes if (digit >= base) 101158f0484fSRodney W. Grimes break; 101258f0484fSRodney W. Grimes 101358f0484fSRodney W. Grimes n = n * base + digit; 101458f0484fSRodney W. Grimes bp++; 101558f0484fSRodney W. Grimes } 101658f0484fSRodney W. Grimes 101758f0484fSRodney W. Grimes /* 101858f0484fSRodney W. Grimes * Return value and success. 101958f0484fSRodney W. Grimes */ 102058f0484fSRodney W. Grimes *num = n; 102158f0484fSRodney W. Grimes return (0); 102258f0484fSRodney W. Grimes } 102358f0484fSRodney W. Grimes 102458f0484fSRodney W. Grimes 102558f0484fSRodney W. Grimes /* 102658f0484fSRodney W. Grimes * Compare name field of record. 102758f0484fSRodney W. Grimes */ 102858f0484fSRodney W. Grimes static int 102958f0484fSRodney W. Grimes nfcmp(nf, rec) 103058f0484fSRodney W. Grimes char *nf, *rec; 103158f0484fSRodney W. Grimes { 103258f0484fSRodney W. Grimes char *cp, tmp; 103358f0484fSRodney W. Grimes int ret; 103458f0484fSRodney W. Grimes 103558f0484fSRodney W. Grimes for (cp = rec; *cp != ':'; cp++) 103658f0484fSRodney W. Grimes ; 103758f0484fSRodney W. Grimes 103858f0484fSRodney W. Grimes tmp = *(cp + 1); 103958f0484fSRodney W. Grimes *(cp + 1) = '\0'; 104058f0484fSRodney W. Grimes ret = strcmp(nf, rec); 104158f0484fSRodney W. Grimes *(cp + 1) = tmp; 104258f0484fSRodney W. Grimes 104358f0484fSRodney W. Grimes return (ret); 104458f0484fSRodney W. Grimes } 1045