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 */ 40ea8d448aSDavid E. O'Brien #include <sys/cdefs.h> 41ea8d448aSDavid E. O'Brien __FBSDID("$FreeBSD$"); 4258f0484fSRodney W. Grimes 43d201fe46SDaniel Eischen #include "namespace.h" 4458f0484fSRodney W. Grimes #include <sys/types.h> 4558f0484fSRodney W. Grimes 4658f0484fSRodney W. Grimes #include <ctype.h> 4758f0484fSRodney W. Grimes #include <errno.h> 4858f0484fSRodney W. Grimes #include <fcntl.h> 4958f0484fSRodney W. Grimes #include <limits.h> 5058f0484fSRodney W. Grimes #include <stdio.h> 5158f0484fSRodney W. Grimes #include <stdlib.h> 5258f0484fSRodney W. Grimes #include <string.h> 5358f0484fSRodney W. Grimes #include <unistd.h> 54d201fe46SDaniel Eischen #include "un-namespace.h" 55d201fe46SDaniel Eischen 56d201fe46SDaniel Eischen #include <db.h> 5758f0484fSRodney W. Grimes 5858f0484fSRodney W. Grimes #define BFRAG 1024 5958f0484fSRodney W. Grimes #define BSIZE 1024 6058f0484fSRodney W. Grimes #define ESC ('[' & 037) /* ASCII ESC */ 6158f0484fSRodney W. Grimes #define MAX_RECURSION 32 /* maximum getent recursion */ 6258f0484fSRodney W. Grimes #define SFRAG 100 /* cgetstr mallocs in SFRAG chunks */ 6358f0484fSRodney W. Grimes 6458f0484fSRodney W. Grimes #define RECOK (char)0 6558f0484fSRodney W. Grimes #define TCERR (char)1 6658f0484fSRodney W. Grimes #define SHADOW (char)2 6758f0484fSRodney W. Grimes 6858f0484fSRodney W. Grimes static size_t topreclen; /* toprec length */ 6958f0484fSRodney W. Grimes static char *toprec; /* Additional record specified by cgetset() */ 7058f0484fSRodney W. Grimes static int gottoprec; /* Flag indicating retrieval of toprecord */ 7158f0484fSRodney W. Grimes 72ea8d448aSDavid E. O'Brien static int cdbget(DB *, char **, char *); 73ea8d448aSDavid E. O'Brien static int getent(char **, u_int *, char **, int, char *, int, char *); 74ea8d448aSDavid E. O'Brien static int nfcmp(char *, char *); 7558f0484fSRodney W. Grimes 7658f0484fSRodney W. Grimes /* 7758f0484fSRodney W. Grimes * Cgetset() allows the addition of a user specified buffer to be added 7858f0484fSRodney W. Grimes * to the database array, in effect "pushing" the buffer on top of the 7958f0484fSRodney W. Grimes * virtual database. 0 is returned on success, -1 on failure. 8058f0484fSRodney W. Grimes */ 8158f0484fSRodney W. Grimes int 8258f0484fSRodney W. Grimes cgetset(ent) 8358f0484fSRodney W. Grimes char *ent; 8458f0484fSRodney W. Grimes { 8558f0484fSRodney W. Grimes if (ent == NULL) { 8658f0484fSRodney W. Grimes if (toprec) 8758f0484fSRodney W. Grimes free(toprec); 8858f0484fSRodney W. Grimes toprec = NULL; 8958f0484fSRodney W. Grimes topreclen = 0; 9058f0484fSRodney W. Grimes return (0); 9158f0484fSRodney W. Grimes } 9258f0484fSRodney W. Grimes topreclen = strlen(ent); 9358f0484fSRodney W. Grimes if ((toprec = malloc (topreclen + 1)) == NULL) { 9458f0484fSRodney W. Grimes errno = ENOMEM; 9558f0484fSRodney W. Grimes return (-1); 9658f0484fSRodney W. Grimes } 9758f0484fSRodney W. Grimes gottoprec = 0; 9858f0484fSRodney W. Grimes (void)strcpy(toprec, ent); 9958f0484fSRodney W. Grimes return (0); 10058f0484fSRodney W. Grimes } 10158f0484fSRodney W. Grimes 10258f0484fSRodney W. Grimes /* 10358f0484fSRodney W. Grimes * Cgetcap searches the capability record buf for the capability cap with 10458f0484fSRodney W. Grimes * type `type'. A pointer to the value of cap is returned on success, NULL 10558f0484fSRodney W. Grimes * if the requested capability couldn't be found. 10658f0484fSRodney W. Grimes * 10758f0484fSRodney W. Grimes * Specifying a type of ':' means that nothing should follow cap (:cap:). 10858f0484fSRodney W. Grimes * In this case a pointer to the terminating ':' or NUL will be returned if 10958f0484fSRodney W. Grimes * cap is found. 11058f0484fSRodney W. Grimes * 11158f0484fSRodney W. Grimes * If (cap, '@') or (cap, terminator, '@') is found before (cap, terminator) 11258f0484fSRodney W. Grimes * return NULL. 11358f0484fSRodney W. Grimes */ 11458f0484fSRodney W. Grimes char * 11558f0484fSRodney W. Grimes cgetcap(buf, cap, type) 11658f0484fSRodney W. Grimes char *buf, *cap; 11758f0484fSRodney W. Grimes int type; 11858f0484fSRodney W. Grimes { 119ea8d448aSDavid E. O'Brien char *bp, *cp; 12058f0484fSRodney W. Grimes 12158f0484fSRodney W. Grimes bp = buf; 12258f0484fSRodney W. Grimes for (;;) { 12358f0484fSRodney W. Grimes /* 12458f0484fSRodney W. Grimes * Skip past the current capability field - it's either the 12558f0484fSRodney W. Grimes * name field if this is the first time through the loop, or 12658f0484fSRodney W. Grimes * the remainder of a field whose name failed to match cap. 12758f0484fSRodney W. Grimes */ 12858f0484fSRodney W. Grimes for (;;) 12958f0484fSRodney W. Grimes if (*bp == '\0') 13058f0484fSRodney W. Grimes return (NULL); 13158f0484fSRodney W. Grimes else 13258f0484fSRodney W. Grimes if (*bp++ == ':') 13358f0484fSRodney W. Grimes break; 13458f0484fSRodney W. Grimes 13558f0484fSRodney W. Grimes /* 13658f0484fSRodney W. Grimes * Try to match (cap, type) in buf. 13758f0484fSRodney W. Grimes */ 13858f0484fSRodney W. Grimes for (cp = cap; *cp == *bp && *bp != '\0'; cp++, bp++) 13958f0484fSRodney W. Grimes continue; 14058f0484fSRodney W. Grimes if (*cp != '\0') 14158f0484fSRodney W. Grimes continue; 14258f0484fSRodney W. Grimes if (*bp == '@') 14358f0484fSRodney W. Grimes return (NULL); 14458f0484fSRodney W. Grimes if (type == ':') { 14558f0484fSRodney W. Grimes if (*bp != '\0' && *bp != ':') 14658f0484fSRodney W. Grimes continue; 14758f0484fSRodney W. Grimes return(bp); 14858f0484fSRodney W. Grimes } 14958f0484fSRodney W. Grimes if (*bp != type) 15058f0484fSRodney W. Grimes continue; 15158f0484fSRodney W. Grimes bp++; 15258f0484fSRodney W. Grimes return (*bp == '@' ? NULL : bp); 15358f0484fSRodney W. Grimes } 15458f0484fSRodney W. Grimes /* NOTREACHED */ 15558f0484fSRodney W. Grimes } 15658f0484fSRodney W. Grimes 15758f0484fSRodney W. Grimes /* 15858f0484fSRodney W. Grimes * Cgetent extracts the capability record name from the NULL terminated file 15958f0484fSRodney W. Grimes * array db_array and returns a pointer to a malloc'd copy of it in buf. 16058f0484fSRodney W. Grimes * Buf must be retained through all subsequent calls to cgetcap, cgetnum, 16158f0484fSRodney W. Grimes * cgetflag, and cgetstr, but may then be free'd. 0 is returned on success, 16258f0484fSRodney W. Grimes * -1 if the requested record couldn't be found, -2 if a system error was 16358f0484fSRodney W. Grimes * encountered (couldn't open/read a file, etc.), and -3 if a potential 16458f0484fSRodney W. Grimes * reference loop is detected. 16558f0484fSRodney W. Grimes */ 16658f0484fSRodney W. Grimes int 16758f0484fSRodney W. Grimes cgetent(buf, db_array, name) 16858f0484fSRodney W. Grimes char **buf, **db_array, *name; 16958f0484fSRodney W. Grimes { 17058f0484fSRodney W. Grimes u_int dummy; 17158f0484fSRodney W. Grimes 17258f0484fSRodney W. Grimes return (getent(buf, &dummy, db_array, -1, name, 0, NULL)); 17358f0484fSRodney W. Grimes } 17458f0484fSRodney W. Grimes 17558f0484fSRodney W. Grimes /* 17658f0484fSRodney W. Grimes * Getent implements the functions of cgetent. If fd is non-negative, 17758f0484fSRodney W. Grimes * *db_array has already been opened and fd is the open file descriptor. We 17858f0484fSRodney W. Grimes * do this to save time and avoid using up file descriptors for tc= 17958f0484fSRodney W. Grimes * recursions. 18058f0484fSRodney W. Grimes * 18158f0484fSRodney W. Grimes * Getent returns the same success/failure codes as cgetent. On success, a 18258f0484fSRodney W. Grimes * pointer to a malloc'ed capability record with all tc= capabilities fully 18358f0484fSRodney W. Grimes * expanded and its length (not including trailing ASCII NUL) are left in 18458f0484fSRodney W. Grimes * *cap and *len. 18558f0484fSRodney W. Grimes * 18658f0484fSRodney W. Grimes * Basic algorithm: 18758f0484fSRodney W. Grimes * + Allocate memory incrementally as needed in chunks of size BFRAG 18858f0484fSRodney W. Grimes * for capability buffer. 18958f0484fSRodney W. Grimes * + Recurse for each tc=name and interpolate result. Stop when all 19058f0484fSRodney W. Grimes * names interpolated, a name can't be found, or depth exceeds 19158f0484fSRodney W. Grimes * MAX_RECURSION. 19258f0484fSRodney W. Grimes */ 19358f0484fSRodney W. Grimes static int 19458f0484fSRodney W. Grimes getent(cap, len, db_array, fd, name, depth, nfield) 19558f0484fSRodney W. Grimes char **cap, **db_array, *name, *nfield; 19658f0484fSRodney W. Grimes u_int *len; 19758f0484fSRodney W. Grimes int fd, depth; 19858f0484fSRodney W. Grimes { 19958f0484fSRodney W. Grimes DB *capdbp; 200ea8d448aSDavid E. O'Brien char *r_end, *rp, **db_p; 20158f0484fSRodney W. Grimes int myfd, eof, foundit, retval, clen; 20258f0484fSRodney W. Grimes char *record, *cbuf; 20358f0484fSRodney W. Grimes int tc_not_resolved; 20458f0484fSRodney W. Grimes char pbuf[_POSIX_PATH_MAX]; 20558f0484fSRodney W. Grimes 20658f0484fSRodney W. Grimes /* 20758f0484fSRodney W. Grimes * Return with ``loop detected'' error if we've recursed more than 20858f0484fSRodney W. Grimes * MAX_RECURSION times. 20958f0484fSRodney W. Grimes */ 21058f0484fSRodney W. Grimes if (depth > MAX_RECURSION) 21158f0484fSRodney W. Grimes return (-3); 21258f0484fSRodney W. Grimes 21358f0484fSRodney W. Grimes /* 21458f0484fSRodney W. Grimes * Check if we have a top record from cgetset(). 21558f0484fSRodney W. Grimes */ 21658f0484fSRodney W. Grimes if (depth == 0 && toprec != NULL && cgetmatch(toprec, name) == 0) { 21758f0484fSRodney W. Grimes if ((record = malloc (topreclen + BFRAG)) == NULL) { 21858f0484fSRodney W. Grimes errno = ENOMEM; 21958f0484fSRodney W. Grimes return (-2); 22058f0484fSRodney W. Grimes } 22158f0484fSRodney W. Grimes (void)strcpy(record, toprec); 22258f0484fSRodney W. Grimes myfd = 0; 22358f0484fSRodney W. Grimes db_p = db_array; 22458f0484fSRodney W. Grimes rp = record + topreclen + 1; 22558f0484fSRodney W. Grimes r_end = rp + BFRAG; 22658f0484fSRodney W. Grimes goto tc_exp; 22758f0484fSRodney W. Grimes } 22858f0484fSRodney W. Grimes /* 22958f0484fSRodney W. Grimes * Allocate first chunk of memory. 23058f0484fSRodney W. Grimes */ 23158f0484fSRodney W. Grimes if ((record = malloc(BFRAG)) == NULL) { 23258f0484fSRodney W. Grimes errno = ENOMEM; 23358f0484fSRodney W. Grimes return (-2); 23458f0484fSRodney W. Grimes } 23558f0484fSRodney W. Grimes r_end = record + BFRAG; 23658f0484fSRodney W. Grimes foundit = 0; 23758f0484fSRodney W. Grimes /* 23858f0484fSRodney W. Grimes * Loop through database array until finding the record. 23958f0484fSRodney W. Grimes */ 24058f0484fSRodney W. Grimes 24158f0484fSRodney W. Grimes for (db_p = db_array; *db_p != NULL; db_p++) { 24258f0484fSRodney W. Grimes eof = 0; 24358f0484fSRodney W. Grimes 24458f0484fSRodney W. Grimes /* 24558f0484fSRodney W. Grimes * Open database if not already open. 24658f0484fSRodney W. Grimes */ 24758f0484fSRodney W. Grimes 24858f0484fSRodney W. Grimes if (fd >= 0) { 24911ea2762SJohn Polstra (void)lseek(fd, (off_t)0, SEEK_SET); 25058f0484fSRodney W. Grimes myfd = 0; 25158f0484fSRodney W. Grimes } else { 25258f0484fSRodney W. Grimes (void)snprintf(pbuf, sizeof(pbuf), "%s.db", *db_p); 25358f0484fSRodney W. Grimes if ((capdbp = dbopen(pbuf, O_RDONLY, 0, DB_HASH, 0)) 25458f0484fSRodney W. Grimes != NULL) { 25558f0484fSRodney W. Grimes free(record); 25658f0484fSRodney W. Grimes retval = cdbget(capdbp, &record, name); 25758f0484fSRodney W. Grimes if (retval < 0) { 25858f0484fSRodney W. Grimes /* no record available */ 25958f0484fSRodney W. Grimes (void)capdbp->close(capdbp); 26058f0484fSRodney W. Grimes return (retval); 26158f0484fSRodney W. Grimes } 26258f0484fSRodney W. Grimes /* save the data; close frees it */ 26358f0484fSRodney W. Grimes clen = strlen(record); 26458f0484fSRodney W. Grimes cbuf = malloc(clen + 1); 26558f0484fSRodney W. Grimes memcpy(cbuf, record, clen + 1); 26658f0484fSRodney W. Grimes if (capdbp->close(capdbp) < 0) { 26758f0484fSRodney W. Grimes free(cbuf); 26858f0484fSRodney W. Grimes return (-2); 26958f0484fSRodney W. Grimes } 27058f0484fSRodney W. Grimes *len = clen; 27158f0484fSRodney W. Grimes *cap = cbuf; 27258f0484fSRodney W. Grimes return (retval); 27358f0484fSRodney W. Grimes } else { 2749233c4d9SJason Evans fd = _open(*db_p, O_RDONLY, 0); 27543b4fd73SWarner Losh if (fd < 0) 27658f0484fSRodney W. Grimes continue; 27758f0484fSRodney W. Grimes myfd = 1; 27858f0484fSRodney W. Grimes } 27958f0484fSRodney W. Grimes } 28058f0484fSRodney W. Grimes /* 28158f0484fSRodney W. Grimes * Find the requested capability record ... 28258f0484fSRodney W. Grimes */ 28358f0484fSRodney W. Grimes { 28458f0484fSRodney W. Grimes char buf[BUFSIZ]; 285ea8d448aSDavid E. O'Brien char *b_end, *bp; 286ea8d448aSDavid E. O'Brien int c; 28758f0484fSRodney W. Grimes 28858f0484fSRodney W. Grimes /* 28958f0484fSRodney W. Grimes * Loop invariants: 29058f0484fSRodney W. Grimes * There is always room for one more character in record. 29158f0484fSRodney W. Grimes * R_end always points just past end of record. 29258f0484fSRodney W. Grimes * Rp always points just past last character in record. 29358f0484fSRodney W. Grimes * B_end always points just past last character in buf. 29458f0484fSRodney W. Grimes * Bp always points at next character in buf. 29558f0484fSRodney W. Grimes */ 29658f0484fSRodney W. Grimes b_end = buf; 29758f0484fSRodney W. Grimes bp = buf; 29858f0484fSRodney W. Grimes for (;;) { 29958f0484fSRodney W. Grimes 30058f0484fSRodney W. Grimes /* 30158f0484fSRodney W. Grimes * Read in a line implementing (\, newline) 30258f0484fSRodney W. Grimes * line continuation. 30358f0484fSRodney W. Grimes */ 30458f0484fSRodney W. Grimes rp = record; 30558f0484fSRodney W. Grimes for (;;) { 30658f0484fSRodney W. Grimes if (bp >= b_end) { 30758f0484fSRodney W. Grimes int n; 30858f0484fSRodney W. Grimes 3099233c4d9SJason Evans n = _read(fd, buf, sizeof(buf)); 31058f0484fSRodney W. Grimes if (n <= 0) { 31158f0484fSRodney W. Grimes if (myfd) 3129233c4d9SJason Evans (void)_close(fd); 31358f0484fSRodney W. Grimes if (n < 0) { 31458f0484fSRodney W. Grimes free(record); 31558f0484fSRodney W. Grimes return (-2); 31658f0484fSRodney W. Grimes } else { 31758f0484fSRodney W. Grimes fd = -1; 31858f0484fSRodney W. Grimes eof = 1; 31958f0484fSRodney W. Grimes break; 32058f0484fSRodney W. Grimes } 32158f0484fSRodney W. Grimes } 32258f0484fSRodney W. Grimes b_end = buf+n; 32358f0484fSRodney W. Grimes bp = buf; 32458f0484fSRodney W. Grimes } 32558f0484fSRodney W. Grimes 32658f0484fSRodney W. Grimes c = *bp++; 32758f0484fSRodney W. Grimes if (c == '\n') { 32858f0484fSRodney W. Grimes if (rp > record && *(rp-1) == '\\') { 32958f0484fSRodney W. Grimes rp--; 33058f0484fSRodney W. Grimes continue; 33158f0484fSRodney W. Grimes } else 33258f0484fSRodney W. Grimes break; 33358f0484fSRodney W. Grimes } 33458f0484fSRodney W. Grimes *rp++ = c; 33558f0484fSRodney W. Grimes 33658f0484fSRodney W. Grimes /* 33758f0484fSRodney W. Grimes * Enforce loop invariant: if no room 33858f0484fSRodney W. Grimes * left in record buffer, try to get 33958f0484fSRodney W. Grimes * some more. 34058f0484fSRodney W. Grimes */ 34158f0484fSRodney W. Grimes if (rp >= r_end) { 34258f0484fSRodney W. Grimes u_int pos; 34358f0484fSRodney W. Grimes size_t newsize; 34458f0484fSRodney W. Grimes 34558f0484fSRodney W. Grimes pos = rp - record; 34658f0484fSRodney W. Grimes newsize = r_end - record + BFRAG; 347e8420087SWarner Losh record = reallocf(record, newsize); 34858f0484fSRodney W. Grimes if (record == NULL) { 34958f0484fSRodney W. Grimes errno = ENOMEM; 35058f0484fSRodney W. Grimes if (myfd) 3519233c4d9SJason Evans (void)_close(fd); 35258f0484fSRodney W. Grimes return (-2); 35358f0484fSRodney W. Grimes } 35458f0484fSRodney W. Grimes r_end = record + newsize; 35558f0484fSRodney W. Grimes rp = record + pos; 35658f0484fSRodney W. Grimes } 35758f0484fSRodney W. Grimes } 35858f0484fSRodney W. Grimes /* loop invariant let's us do this */ 35958f0484fSRodney W. Grimes *rp++ = '\0'; 36058f0484fSRodney W. Grimes 36158f0484fSRodney W. Grimes /* 36258f0484fSRodney W. Grimes * If encountered eof check next file. 36358f0484fSRodney W. Grimes */ 36458f0484fSRodney W. Grimes if (eof) 36558f0484fSRodney W. Grimes break; 36658f0484fSRodney W. Grimes 36758f0484fSRodney W. Grimes /* 36858f0484fSRodney W. Grimes * Toss blank lines and comments. 36958f0484fSRodney W. Grimes */ 37058f0484fSRodney W. Grimes if (*record == '\0' || *record == '#') 37158f0484fSRodney W. Grimes continue; 37258f0484fSRodney W. Grimes 37358f0484fSRodney W. Grimes /* 37458f0484fSRodney W. Grimes * See if this is the record we want ... 37558f0484fSRodney W. Grimes */ 37658f0484fSRodney W. Grimes if (cgetmatch(record, name) == 0) { 37758f0484fSRodney W. Grimes if (nfield == NULL || !nfcmp(nfield, record)) { 37858f0484fSRodney W. Grimes foundit = 1; 37958f0484fSRodney W. Grimes break; /* found it! */ 38058f0484fSRodney W. Grimes } 38158f0484fSRodney W. Grimes } 38258f0484fSRodney W. Grimes } 38358f0484fSRodney W. Grimes } 38458f0484fSRodney W. Grimes if (foundit) 38558f0484fSRodney W. Grimes break; 38658f0484fSRodney W. Grimes } 38758f0484fSRodney W. Grimes 3888187dd1cSTim Vanderhoek if (!foundit) { 3898187dd1cSTim Vanderhoek free(record); 39058f0484fSRodney W. Grimes return (-1); 3918187dd1cSTim Vanderhoek } 39258f0484fSRodney W. Grimes 39358f0484fSRodney W. Grimes /* 39458f0484fSRodney W. Grimes * Got the capability record, but now we have to expand all tc=name 39558f0484fSRodney W. Grimes * references in it ... 39658f0484fSRodney W. Grimes */ 39758f0484fSRodney W. Grimes tc_exp: { 398ea8d448aSDavid E. O'Brien char *newicap, *s; 399ea8d448aSDavid E. O'Brien int newilen; 40058f0484fSRodney W. Grimes u_int ilen; 40158f0484fSRodney W. Grimes int diff, iret, tclen; 40258f0484fSRodney W. Grimes char *icap, *scan, *tc, *tcstart, *tcend; 40358f0484fSRodney W. Grimes 40458f0484fSRodney W. Grimes /* 40558f0484fSRodney W. Grimes * Loop invariants: 40658f0484fSRodney W. Grimes * There is room for one more character in record. 40758f0484fSRodney W. Grimes * R_end points just past end of record. 40858f0484fSRodney W. Grimes * Rp points just past last character in record. 40958f0484fSRodney W. Grimes * Scan points at remainder of record that needs to be 41058f0484fSRodney W. Grimes * scanned for tc=name constructs. 41158f0484fSRodney W. Grimes */ 41258f0484fSRodney W. Grimes scan = record; 41358f0484fSRodney W. Grimes tc_not_resolved = 0; 41458f0484fSRodney W. Grimes for (;;) { 41558f0484fSRodney W. Grimes if ((tc = cgetcap(scan, "tc", '=')) == NULL) 41658f0484fSRodney W. Grimes break; 41758f0484fSRodney W. Grimes 41858f0484fSRodney W. Grimes /* 41958f0484fSRodney W. Grimes * Find end of tc=name and stomp on the trailing `:' 42058f0484fSRodney W. Grimes * (if present) so we can use it to call ourselves. 42158f0484fSRodney W. Grimes */ 42258f0484fSRodney W. Grimes s = tc; 42358f0484fSRodney W. Grimes for (;;) 42458f0484fSRodney W. Grimes if (*s == '\0') 42558f0484fSRodney W. Grimes break; 42658f0484fSRodney W. Grimes else 42758f0484fSRodney W. Grimes if (*s++ == ':') { 42858f0484fSRodney W. Grimes *(s - 1) = '\0'; 42958f0484fSRodney W. Grimes break; 43058f0484fSRodney W. Grimes } 43158f0484fSRodney W. Grimes tcstart = tc - 3; 43258f0484fSRodney W. Grimes tclen = s - tcstart; 43358f0484fSRodney W. Grimes tcend = s; 43458f0484fSRodney W. Grimes 43558f0484fSRodney W. Grimes iret = getent(&icap, &ilen, db_p, fd, tc, depth+1, 43658f0484fSRodney W. Grimes NULL); 43758f0484fSRodney W. Grimes newicap = icap; /* Put into a register. */ 43858f0484fSRodney W. Grimes newilen = ilen; 43958f0484fSRodney W. Grimes if (iret != 0) { 44058f0484fSRodney W. Grimes /* an error */ 44158f0484fSRodney W. Grimes if (iret < -1) { 44258f0484fSRodney W. Grimes if (myfd) 4439233c4d9SJason Evans (void)_close(fd); 44458f0484fSRodney W. Grimes free(record); 44558f0484fSRodney W. Grimes return (iret); 44658f0484fSRodney W. Grimes } 44758f0484fSRodney W. Grimes if (iret == 1) 44858f0484fSRodney W. Grimes tc_not_resolved = 1; 44958f0484fSRodney W. Grimes /* couldn't resolve tc */ 45058f0484fSRodney W. Grimes if (iret == -1) { 45158f0484fSRodney W. Grimes *(s - 1) = ':'; 45258f0484fSRodney W. Grimes scan = s - 1; 45358f0484fSRodney W. Grimes tc_not_resolved = 1; 45458f0484fSRodney W. Grimes continue; 45558f0484fSRodney W. Grimes 45658f0484fSRodney W. Grimes } 45758f0484fSRodney W. Grimes } 45858f0484fSRodney W. Grimes /* not interested in name field of tc'ed record */ 45958f0484fSRodney W. Grimes s = newicap; 46058f0484fSRodney W. Grimes for (;;) 46158f0484fSRodney W. Grimes if (*s == '\0') 46258f0484fSRodney W. Grimes break; 46358f0484fSRodney W. Grimes else 46458f0484fSRodney W. Grimes if (*s++ == ':') 46558f0484fSRodney W. Grimes break; 46658f0484fSRodney W. Grimes newilen -= s - newicap; 46758f0484fSRodney W. Grimes newicap = s; 46858f0484fSRodney W. Grimes 46958f0484fSRodney W. Grimes /* make sure interpolated record is `:'-terminated */ 47058f0484fSRodney W. Grimes s += newilen; 47158f0484fSRodney W. Grimes if (*(s-1) != ':') { 47258f0484fSRodney W. Grimes *s = ':'; /* overwrite NUL with : */ 47358f0484fSRodney W. Grimes newilen++; 47458f0484fSRodney W. Grimes } 47558f0484fSRodney W. Grimes 47658f0484fSRodney W. Grimes /* 47758f0484fSRodney W. Grimes * Make sure there's enough room to insert the 47858f0484fSRodney W. Grimes * new record. 47958f0484fSRodney W. Grimes */ 48058f0484fSRodney W. Grimes diff = newilen - tclen; 48158f0484fSRodney W. Grimes if (diff >= r_end - rp) { 48258f0484fSRodney W. Grimes u_int pos, tcpos, tcposend; 48358f0484fSRodney W. Grimes size_t newsize; 48458f0484fSRodney W. Grimes 48558f0484fSRodney W. Grimes pos = rp - record; 48658f0484fSRodney W. Grimes newsize = r_end - record + diff + BFRAG; 48758f0484fSRodney W. Grimes tcpos = tcstart - record; 48858f0484fSRodney W. Grimes tcposend = tcend - record; 489e8420087SWarner Losh record = reallocf(record, newsize); 49058f0484fSRodney W. Grimes if (record == NULL) { 49158f0484fSRodney W. Grimes errno = ENOMEM; 49258f0484fSRodney W. Grimes if (myfd) 4939233c4d9SJason Evans (void)_close(fd); 49458f0484fSRodney W. Grimes free(icap); 49558f0484fSRodney W. Grimes return (-2); 49658f0484fSRodney W. Grimes } 49758f0484fSRodney W. Grimes r_end = record + newsize; 49858f0484fSRodney W. Grimes rp = record + pos; 49958f0484fSRodney W. Grimes tcstart = record + tcpos; 50058f0484fSRodney W. Grimes tcend = record + tcposend; 50158f0484fSRodney W. Grimes } 50258f0484fSRodney W. Grimes 50358f0484fSRodney W. Grimes /* 50458f0484fSRodney W. Grimes * Insert tc'ed record into our record. 50558f0484fSRodney W. Grimes */ 50658f0484fSRodney W. Grimes s = tcstart + newilen; 50758f0484fSRodney W. Grimes bcopy(tcend, s, rp - tcend); 50858f0484fSRodney W. Grimes bcopy(newicap, tcstart, newilen); 50958f0484fSRodney W. Grimes rp += diff; 51058f0484fSRodney W. Grimes free(icap); 51158f0484fSRodney W. Grimes 51258f0484fSRodney W. Grimes /* 51358f0484fSRodney W. Grimes * Start scan on `:' so next cgetcap works properly 51458f0484fSRodney W. Grimes * (cgetcap always skips first field). 51558f0484fSRodney W. Grimes */ 51658f0484fSRodney W. Grimes scan = s-1; 51758f0484fSRodney W. Grimes } 51858f0484fSRodney W. Grimes 51958f0484fSRodney W. Grimes } 52058f0484fSRodney W. Grimes /* 52158f0484fSRodney W. Grimes * Close file (if we opened it), give back any extra memory, and 52258f0484fSRodney W. Grimes * return capability, length and success. 52358f0484fSRodney W. Grimes */ 52458f0484fSRodney W. Grimes if (myfd) 5259233c4d9SJason Evans (void)_close(fd); 52658f0484fSRodney W. Grimes *len = rp - record - 1; /* don't count NUL */ 52758f0484fSRodney W. Grimes if (r_end > rp) 52858f0484fSRodney W. Grimes if ((record = 529e8420087SWarner Losh reallocf(record, (size_t)(rp - record))) == NULL) { 53058f0484fSRodney W. Grimes errno = ENOMEM; 53158f0484fSRodney W. Grimes return (-2); 53258f0484fSRodney W. Grimes } 53358f0484fSRodney W. Grimes 53458f0484fSRodney W. Grimes *cap = record; 53558f0484fSRodney W. Grimes if (tc_not_resolved) 53658f0484fSRodney W. Grimes return (1); 53758f0484fSRodney W. Grimes return (0); 53858f0484fSRodney W. Grimes } 53958f0484fSRodney W. Grimes 54058f0484fSRodney W. Grimes static int 54158f0484fSRodney W. Grimes cdbget(capdbp, bp, name) 54258f0484fSRodney W. Grimes DB *capdbp; 54358f0484fSRodney W. Grimes char **bp, *name; 54458f0484fSRodney W. Grimes { 54558f0484fSRodney W. Grimes DBT key, data; 54658f0484fSRodney W. Grimes 54758f0484fSRodney W. Grimes key.data = name; 54858f0484fSRodney W. Grimes key.size = strlen(name); 54958f0484fSRodney W. Grimes 55058f0484fSRodney W. Grimes for (;;) { 55158f0484fSRodney W. Grimes /* Get the reference. */ 55258f0484fSRodney W. Grimes switch(capdbp->get(capdbp, &key, &data, 0)) { 55358f0484fSRodney W. Grimes case -1: 55458f0484fSRodney W. Grimes return (-2); 55558f0484fSRodney W. Grimes case 1: 55658f0484fSRodney W. Grimes return (-1); 55758f0484fSRodney W. Grimes } 55858f0484fSRodney W. Grimes 55958f0484fSRodney W. Grimes /* If not an index to another record, leave. */ 56058f0484fSRodney W. Grimes if (((char *)data.data)[0] != SHADOW) 56158f0484fSRodney W. Grimes break; 56258f0484fSRodney W. Grimes 56358f0484fSRodney W. Grimes key.data = (char *)data.data + 1; 56458f0484fSRodney W. Grimes key.size = data.size - 1; 56558f0484fSRodney W. Grimes } 56658f0484fSRodney W. Grimes 56758f0484fSRodney W. Grimes *bp = (char *)data.data + 1; 56858f0484fSRodney W. Grimes return (((char *)(data.data))[0] == TCERR ? 1 : 0); 56958f0484fSRodney W. Grimes } 57058f0484fSRodney W. Grimes 57158f0484fSRodney W. Grimes /* 57258f0484fSRodney W. Grimes * Cgetmatch will return 0 if name is one of the names of the capability 57358f0484fSRodney W. Grimes * record buf, -1 if not. 57458f0484fSRodney W. Grimes */ 57558f0484fSRodney W. Grimes int 57658f0484fSRodney W. Grimes cgetmatch(buf, name) 57758f0484fSRodney W. Grimes char *buf, *name; 57858f0484fSRodney W. Grimes { 579ea8d448aSDavid E. O'Brien char *np, *bp; 58058f0484fSRodney W. Grimes 58158f0484fSRodney W. Grimes /* 58258f0484fSRodney W. Grimes * Start search at beginning of record. 58358f0484fSRodney W. Grimes */ 58458f0484fSRodney W. Grimes bp = buf; 58558f0484fSRodney W. Grimes for (;;) { 58658f0484fSRodney W. Grimes /* 58758f0484fSRodney W. Grimes * Try to match a record name. 58858f0484fSRodney W. Grimes */ 58958f0484fSRodney W. Grimes np = name; 59058f0484fSRodney W. Grimes for (;;) 59158f0484fSRodney W. Grimes if (*np == '\0') 59258f0484fSRodney W. Grimes if (*bp == '|' || *bp == ':' || *bp == '\0') 59358f0484fSRodney W. Grimes return (0); 59458f0484fSRodney W. Grimes else 59558f0484fSRodney W. Grimes break; 59658f0484fSRodney W. Grimes else 59758f0484fSRodney W. Grimes if (*bp++ != *np++) 59858f0484fSRodney W. Grimes break; 59958f0484fSRodney W. Grimes 60058f0484fSRodney W. Grimes /* 60158f0484fSRodney W. Grimes * Match failed, skip to next name in record. 60258f0484fSRodney W. Grimes */ 60358f0484fSRodney W. Grimes bp--; /* a '|' or ':' may have stopped the match */ 60458f0484fSRodney W. Grimes for (;;) 60558f0484fSRodney W. Grimes if (*bp == '\0' || *bp == ':') 60658f0484fSRodney W. Grimes return (-1); /* match failed totally */ 60758f0484fSRodney W. Grimes else 60858f0484fSRodney W. Grimes if (*bp++ == '|') 60958f0484fSRodney W. Grimes break; /* found next name */ 61058f0484fSRodney W. Grimes } 61158f0484fSRodney W. Grimes } 61258f0484fSRodney W. Grimes 61358f0484fSRodney W. Grimes 61458f0484fSRodney W. Grimes 61558f0484fSRodney W. Grimes 61658f0484fSRodney W. Grimes 61758f0484fSRodney W. Grimes int 61858f0484fSRodney W. Grimes cgetfirst(buf, db_array) 61958f0484fSRodney W. Grimes char **buf, **db_array; 62058f0484fSRodney W. Grimes { 62158f0484fSRodney W. Grimes (void)cgetclose(); 62258f0484fSRodney W. Grimes return (cgetnext(buf, db_array)); 62358f0484fSRodney W. Grimes } 62458f0484fSRodney W. Grimes 62558f0484fSRodney W. Grimes static FILE *pfp; 62658f0484fSRodney W. Grimes static int slash; 62758f0484fSRodney W. Grimes static char **dbp; 62858f0484fSRodney W. Grimes 62958f0484fSRodney W. Grimes int 63058f0484fSRodney W. Grimes cgetclose() 63158f0484fSRodney W. Grimes { 63258f0484fSRodney W. Grimes if (pfp != NULL) { 63358f0484fSRodney W. Grimes (void)fclose(pfp); 63458f0484fSRodney W. Grimes pfp = NULL; 63558f0484fSRodney W. Grimes } 63658f0484fSRodney W. Grimes dbp = NULL; 63758f0484fSRodney W. Grimes gottoprec = 0; 63858f0484fSRodney W. Grimes slash = 0; 63958f0484fSRodney W. Grimes return(0); 64058f0484fSRodney W. Grimes } 64158f0484fSRodney W. Grimes 64258f0484fSRodney W. Grimes /* 64358f0484fSRodney W. Grimes * Cgetnext() gets either the first or next entry in the logical database 64458f0484fSRodney W. Grimes * specified by db_array. It returns 0 upon completion of the database, 1 64558f0484fSRodney W. Grimes * upon returning an entry with more remaining, and -1 if an error occurs. 64658f0484fSRodney W. Grimes */ 64758f0484fSRodney W. Grimes int 64858f0484fSRodney W. Grimes cgetnext(bp, db_array) 649ea8d448aSDavid E. O'Brien char **bp; 65058f0484fSRodney W. Grimes char **db_array; 65158f0484fSRodney W. Grimes { 65258f0484fSRodney W. Grimes size_t len; 653bbe8edb0SGarance A Drosehn int done, hadreaderr, i, savederrno, status; 65458f0484fSRodney W. Grimes char *cp, *line, *rp, *np, buf[BSIZE], nbuf[BSIZE]; 65558f0484fSRodney W. Grimes u_int dummy; 65658f0484fSRodney W. Grimes 65758f0484fSRodney W. Grimes if (dbp == NULL) 65858f0484fSRodney W. Grimes dbp = db_array; 65958f0484fSRodney W. Grimes 66058f0484fSRodney W. Grimes if (pfp == NULL && (pfp = fopen(*dbp, "r")) == NULL) { 66158f0484fSRodney W. Grimes (void)cgetclose(); 66258f0484fSRodney W. Grimes return (-1); 66358f0484fSRodney W. Grimes } 66458f0484fSRodney W. Grimes for(;;) { 66558f0484fSRodney W. Grimes if (toprec && !gottoprec) { 66658f0484fSRodney W. Grimes gottoprec = 1; 66758f0484fSRodney W. Grimes line = toprec; 66858f0484fSRodney W. Grimes } else { 66958f0484fSRodney W. Grimes line = fgetln(pfp, &len); 67058f0484fSRodney W. Grimes if (line == NULL && pfp) { 671bbe8edb0SGarance A Drosehn hadreaderr = ferror(pfp); 672bbe8edb0SGarance A Drosehn if (hadreaderr) 673bbe8edb0SGarance A Drosehn savederrno = errno; 674bbe8edb0SGarance A Drosehn fclose(pfp); 675bbe8edb0SGarance A Drosehn pfp = NULL; 676bbe8edb0SGarance A Drosehn if (hadreaderr) { 677bbe8edb0SGarance A Drosehn cgetclose(); 678bbe8edb0SGarance A Drosehn errno = savederrno; 67958f0484fSRodney W. Grimes return (-1); 68058f0484fSRodney W. Grimes } else { 68158f0484fSRodney W. Grimes if (*++dbp == NULL) { 68258f0484fSRodney W. Grimes (void)cgetclose(); 68358f0484fSRodney W. Grimes return (0); 68458f0484fSRodney W. Grimes } else if ((pfp = 68558f0484fSRodney W. Grimes fopen(*dbp, "r")) == NULL) { 68658f0484fSRodney W. Grimes (void)cgetclose(); 68758f0484fSRodney W. Grimes return (-1); 68858f0484fSRodney W. Grimes } else 68958f0484fSRodney W. Grimes continue; 69058f0484fSRodney W. Grimes } 69158f0484fSRodney W. Grimes } else 69258f0484fSRodney W. Grimes line[len - 1] = '\0'; 69358f0484fSRodney W. Grimes if (len == 1) { 69458f0484fSRodney W. Grimes slash = 0; 69558f0484fSRodney W. Grimes continue; 69658f0484fSRodney W. Grimes } 69749435560SAndrey A. Chernov if (isspace((unsigned char)*line) || 69858f0484fSRodney W. Grimes *line == ':' || *line == '#' || slash) { 69958f0484fSRodney W. Grimes if (line[len - 2] == '\\') 70058f0484fSRodney W. Grimes slash = 1; 70158f0484fSRodney W. Grimes else 70258f0484fSRodney W. Grimes slash = 0; 70358f0484fSRodney W. Grimes continue; 70458f0484fSRodney W. Grimes } 70558f0484fSRodney W. Grimes if (line[len - 2] == '\\') 70658f0484fSRodney W. Grimes slash = 1; 70758f0484fSRodney W. Grimes else 70858f0484fSRodney W. Grimes slash = 0; 70958f0484fSRodney W. Grimes } 71058f0484fSRodney W. Grimes 71158f0484fSRodney W. Grimes 71258f0484fSRodney W. Grimes /* 71358f0484fSRodney W. Grimes * Line points to a name line. 71458f0484fSRodney W. Grimes */ 71558f0484fSRodney W. Grimes i = 0; 71658f0484fSRodney W. Grimes done = 0; 71758f0484fSRodney W. Grimes np = nbuf; 71858f0484fSRodney W. Grimes for (;;) { 71958f0484fSRodney W. Grimes for (cp = line; *cp != '\0'; cp++) { 72058f0484fSRodney W. Grimes if (*cp == ':') { 72158f0484fSRodney W. Grimes *np++ = ':'; 72258f0484fSRodney W. Grimes done = 1; 72358f0484fSRodney W. Grimes break; 72458f0484fSRodney W. Grimes } 72558f0484fSRodney W. Grimes if (*cp == '\\') 72658f0484fSRodney W. Grimes break; 72758f0484fSRodney W. Grimes *np++ = *cp; 72858f0484fSRodney W. Grimes } 72958f0484fSRodney W. Grimes if (done) { 73058f0484fSRodney W. Grimes *np = '\0'; 73158f0484fSRodney W. Grimes break; 73258f0484fSRodney W. Grimes } else { /* name field extends beyond the line */ 73358f0484fSRodney W. Grimes line = fgetln(pfp, &len); 73458f0484fSRodney W. Grimes if (line == NULL && pfp) { 735bbe8edb0SGarance A Drosehn /* Name extends beyond the EOF! */ 736bbe8edb0SGarance A Drosehn hadreaderr = ferror(pfp); 737bbe8edb0SGarance A Drosehn if (hadreaderr) 738bbe8edb0SGarance A Drosehn savederrno = errno; 739bbe8edb0SGarance A Drosehn fclose(pfp); 740bbe8edb0SGarance A Drosehn pfp = NULL; 741bbe8edb0SGarance A Drosehn if (hadreaderr) { 742bbe8edb0SGarance A Drosehn cgetclose(); 743bbe8edb0SGarance A Drosehn errno = savederrno; 744bbe8edb0SGarance A Drosehn return (-1); 745bbe8edb0SGarance A Drosehn } else { 746bbe8edb0SGarance A Drosehn cgetclose(); 74758f0484fSRodney W. Grimes return (-1); 74858f0484fSRodney W. Grimes } 74958f0484fSRodney W. Grimes } else 75058f0484fSRodney W. Grimes line[len - 1] = '\0'; 75158f0484fSRodney W. Grimes } 75258f0484fSRodney W. Grimes } 75358f0484fSRodney W. Grimes rp = buf; 754d030d2d2SPoul-Henning Kamp for(cp = nbuf; *cp != '\0'; cp++) 75558f0484fSRodney W. Grimes if (*cp == '|' || *cp == ':') 75658f0484fSRodney W. Grimes break; 75758f0484fSRodney W. Grimes else 75858f0484fSRodney W. Grimes *rp++ = *cp; 75958f0484fSRodney W. Grimes 76058f0484fSRodney W. Grimes *rp = '\0'; 76158f0484fSRodney W. Grimes /* 76258f0484fSRodney W. Grimes * XXX 76358f0484fSRodney W. Grimes * Last argument of getent here should be nbuf if we want true 76458f0484fSRodney W. Grimes * sequential access in the case of duplicates. 76558f0484fSRodney W. Grimes * With NULL, getent will return the first entry found 76658f0484fSRodney W. Grimes * rather than the duplicate entry record. This is a 76758f0484fSRodney W. Grimes * matter of semantics that should be resolved. 76858f0484fSRodney W. Grimes */ 76958f0484fSRodney W. Grimes status = getent(bp, &dummy, db_array, -1, buf, 0, NULL); 77058f0484fSRodney W. Grimes if (status == -2 || status == -3) 77158f0484fSRodney W. Grimes (void)cgetclose(); 77258f0484fSRodney W. Grimes 77358f0484fSRodney W. Grimes return (status + 1); 77458f0484fSRodney W. Grimes } 77558f0484fSRodney W. Grimes /* NOTREACHED */ 77658f0484fSRodney W. Grimes } 77758f0484fSRodney W. Grimes 77858f0484fSRodney W. Grimes /* 77958f0484fSRodney W. Grimes * Cgetstr retrieves the value of the string capability cap from the 78058f0484fSRodney W. Grimes * capability record pointed to by buf. A pointer to a decoded, NUL 78158f0484fSRodney W. Grimes * terminated, malloc'd copy of the string is returned in the char * 78258f0484fSRodney W. Grimes * pointed to by str. The length of the string not including the trailing 78358f0484fSRodney W. Grimes * NUL is returned on success, -1 if the requested string capability 78458f0484fSRodney W. Grimes * couldn't be found, -2 if a system error was encountered (storage 78558f0484fSRodney W. Grimes * allocation failure). 78658f0484fSRodney W. Grimes */ 78758f0484fSRodney W. Grimes int 78858f0484fSRodney W. Grimes cgetstr(buf, cap, str) 78958f0484fSRodney W. Grimes char *buf, *cap; 79058f0484fSRodney W. Grimes char **str; 79158f0484fSRodney W. Grimes { 792ea8d448aSDavid E. O'Brien u_int m_room; 793ea8d448aSDavid E. O'Brien char *bp, *mp; 79458f0484fSRodney W. Grimes int len; 79558f0484fSRodney W. Grimes char *mem; 79658f0484fSRodney W. Grimes 79758f0484fSRodney W. Grimes /* 79858f0484fSRodney W. Grimes * Find string capability cap 79958f0484fSRodney W. Grimes */ 80058f0484fSRodney W. Grimes bp = cgetcap(buf, cap, '='); 80158f0484fSRodney W. Grimes if (bp == NULL) 80258f0484fSRodney W. Grimes return (-1); 80358f0484fSRodney W. Grimes 80458f0484fSRodney W. Grimes /* 80558f0484fSRodney W. Grimes * Conversion / storage allocation loop ... Allocate memory in 80658f0484fSRodney W. Grimes * chunks SFRAG in size. 80758f0484fSRodney W. Grimes */ 80858f0484fSRodney W. Grimes if ((mem = malloc(SFRAG)) == NULL) { 80958f0484fSRodney W. Grimes errno = ENOMEM; 81058f0484fSRodney W. Grimes return (-2); /* couldn't even allocate the first fragment */ 81158f0484fSRodney W. Grimes } 81258f0484fSRodney W. Grimes m_room = SFRAG; 81358f0484fSRodney W. Grimes mp = mem; 81458f0484fSRodney W. Grimes 81558f0484fSRodney W. Grimes while (*bp != ':' && *bp != '\0') { 81658f0484fSRodney W. Grimes /* 81758f0484fSRodney W. Grimes * Loop invariants: 81858f0484fSRodney W. Grimes * There is always room for one more character in mem. 81958f0484fSRodney W. Grimes * Mp always points just past last character in mem. 82058f0484fSRodney W. Grimes * Bp always points at next character in buf. 82158f0484fSRodney W. Grimes */ 82258f0484fSRodney W. Grimes if (*bp == '^') { 82358f0484fSRodney W. Grimes bp++; 82458f0484fSRodney W. Grimes if (*bp == ':' || *bp == '\0') 82558f0484fSRodney W. Grimes break; /* drop unfinished escape */ 8264f512989SAndrey A. Chernov if (*bp == '?') { 8274f512989SAndrey A. Chernov *mp++ = '\177'; 8284f512989SAndrey A. Chernov bp++; 8294f512989SAndrey A. Chernov } else 83058f0484fSRodney W. Grimes *mp++ = *bp++ & 037; 83158f0484fSRodney W. Grimes } else if (*bp == '\\') { 83258f0484fSRodney W. Grimes bp++; 83358f0484fSRodney W. Grimes if (*bp == ':' || *bp == '\0') 83458f0484fSRodney W. Grimes break; /* drop unfinished escape */ 83558f0484fSRodney W. Grimes if ('0' <= *bp && *bp <= '7') { 836ea8d448aSDavid E. O'Brien int n, i; 83758f0484fSRodney W. Grimes 83858f0484fSRodney W. Grimes n = 0; 83958f0484fSRodney W. Grimes i = 3; /* maximum of three octal digits */ 84058f0484fSRodney W. Grimes do { 84158f0484fSRodney W. Grimes n = n * 8 + (*bp++ - '0'); 84258f0484fSRodney W. Grimes } while (--i && '0' <= *bp && *bp <= '7'); 84358f0484fSRodney W. Grimes *mp++ = n; 84458f0484fSRodney W. Grimes } 84558f0484fSRodney W. Grimes else switch (*bp++) { 84658f0484fSRodney W. Grimes case 'b': case 'B': 84758f0484fSRodney W. Grimes *mp++ = '\b'; 84858f0484fSRodney W. Grimes break; 84958f0484fSRodney W. Grimes case 't': case 'T': 85058f0484fSRodney W. Grimes *mp++ = '\t'; 85158f0484fSRodney W. Grimes break; 85258f0484fSRodney W. Grimes case 'n': case 'N': 85358f0484fSRodney W. Grimes *mp++ = '\n'; 85458f0484fSRodney W. Grimes break; 85558f0484fSRodney W. Grimes case 'f': case 'F': 85658f0484fSRodney W. Grimes *mp++ = '\f'; 85758f0484fSRodney W. Grimes break; 85858f0484fSRodney W. Grimes case 'r': case 'R': 85958f0484fSRodney W. Grimes *mp++ = '\r'; 86058f0484fSRodney W. Grimes break; 86158f0484fSRodney W. Grimes case 'e': case 'E': 86258f0484fSRodney W. Grimes *mp++ = ESC; 86358f0484fSRodney W. Grimes break; 86458f0484fSRodney W. Grimes case 'c': case 'C': 86558f0484fSRodney W. Grimes *mp++ = ':'; 86658f0484fSRodney W. Grimes break; 86758f0484fSRodney W. Grimes default: 86858f0484fSRodney W. Grimes /* 86958f0484fSRodney W. Grimes * Catches '\', '^', and 87058f0484fSRodney W. Grimes * everything else. 87158f0484fSRodney W. Grimes */ 87258f0484fSRodney W. Grimes *mp++ = *(bp-1); 87358f0484fSRodney W. Grimes break; 87458f0484fSRodney W. Grimes } 87558f0484fSRodney W. Grimes } else 87658f0484fSRodney W. Grimes *mp++ = *bp++; 87758f0484fSRodney W. Grimes m_room--; 87858f0484fSRodney W. Grimes 87958f0484fSRodney W. Grimes /* 88058f0484fSRodney W. Grimes * Enforce loop invariant: if no room left in current 88158f0484fSRodney W. Grimes * buffer, try to get some more. 88258f0484fSRodney W. Grimes */ 88358f0484fSRodney W. Grimes if (m_room == 0) { 88458f0484fSRodney W. Grimes size_t size = mp - mem; 88558f0484fSRodney W. Grimes 886e8420087SWarner Losh if ((mem = reallocf(mem, size + SFRAG)) == NULL) 88758f0484fSRodney W. Grimes return (-2); 88858f0484fSRodney W. Grimes m_room = SFRAG; 88958f0484fSRodney W. Grimes mp = mem + size; 89058f0484fSRodney W. Grimes } 89158f0484fSRodney W. Grimes } 89258f0484fSRodney W. Grimes *mp++ = '\0'; /* loop invariant let's us do this */ 89358f0484fSRodney W. Grimes m_room--; 89458f0484fSRodney W. Grimes len = mp - mem - 1; 89558f0484fSRodney W. Grimes 89658f0484fSRodney W. Grimes /* 89758f0484fSRodney W. Grimes * Give back any extra memory and return value and success. 89858f0484fSRodney W. Grimes */ 89958f0484fSRodney W. Grimes if (m_room != 0) 900e8420087SWarner Losh if ((mem = reallocf(mem, (size_t)(mp - mem))) == NULL) 90158f0484fSRodney W. Grimes return (-2); 90258f0484fSRodney W. Grimes *str = mem; 90358f0484fSRodney W. Grimes return (len); 90458f0484fSRodney W. Grimes } 90558f0484fSRodney W. Grimes 90658f0484fSRodney W. Grimes /* 90758f0484fSRodney W. Grimes * Cgetustr retrieves the value of the string capability cap from the 90858f0484fSRodney W. Grimes * capability record pointed to by buf. The difference between cgetustr() 90958f0484fSRodney W. Grimes * and cgetstr() is that cgetustr does not decode escapes but rather treats 91058f0484fSRodney W. Grimes * all characters literally. A pointer to a NUL terminated malloc'd 91158f0484fSRodney W. Grimes * copy of the string is returned in the char pointed to by str. The 91258f0484fSRodney W. Grimes * length of the string not including the trailing NUL is returned on success, 91358f0484fSRodney W. Grimes * -1 if the requested string capability couldn't be found, -2 if a system 91458f0484fSRodney W. Grimes * error was encountered (storage allocation failure). 91558f0484fSRodney W. Grimes */ 91658f0484fSRodney W. Grimes int 91758f0484fSRodney W. Grimes cgetustr(buf, cap, str) 91858f0484fSRodney W. Grimes char *buf, *cap, **str; 91958f0484fSRodney W. Grimes { 920ea8d448aSDavid E. O'Brien u_int m_room; 921ea8d448aSDavid E. O'Brien char *bp, *mp; 92258f0484fSRodney W. Grimes int len; 92358f0484fSRodney W. Grimes char *mem; 92458f0484fSRodney W. Grimes 92558f0484fSRodney W. Grimes /* 92658f0484fSRodney W. Grimes * Find string capability cap 92758f0484fSRodney W. Grimes */ 92858f0484fSRodney W. Grimes if ((bp = cgetcap(buf, cap, '=')) == NULL) 92958f0484fSRodney W. Grimes return (-1); 93058f0484fSRodney W. Grimes 93158f0484fSRodney W. Grimes /* 93258f0484fSRodney W. Grimes * Conversion / storage allocation loop ... Allocate memory in 93358f0484fSRodney W. Grimes * chunks SFRAG in size. 93458f0484fSRodney W. Grimes */ 93558f0484fSRodney W. Grimes if ((mem = malloc(SFRAG)) == NULL) { 93658f0484fSRodney W. Grimes errno = ENOMEM; 93758f0484fSRodney W. Grimes return (-2); /* couldn't even allocate the first fragment */ 93858f0484fSRodney W. Grimes } 93958f0484fSRodney W. Grimes m_room = SFRAG; 94058f0484fSRodney W. Grimes mp = mem; 94158f0484fSRodney W. Grimes 94258f0484fSRodney W. Grimes while (*bp != ':' && *bp != '\0') { 94358f0484fSRodney W. Grimes /* 94458f0484fSRodney W. Grimes * Loop invariants: 94558f0484fSRodney W. Grimes * There is always room for one more character in mem. 94658f0484fSRodney W. Grimes * Mp always points just past last character in mem. 94758f0484fSRodney W. Grimes * Bp always points at next character in buf. 94858f0484fSRodney W. Grimes */ 94958f0484fSRodney W. Grimes *mp++ = *bp++; 95058f0484fSRodney W. Grimes m_room--; 95158f0484fSRodney W. Grimes 95258f0484fSRodney W. Grimes /* 95358f0484fSRodney W. Grimes * Enforce loop invariant: if no room left in current 95458f0484fSRodney W. Grimes * buffer, try to get some more. 95558f0484fSRodney W. Grimes */ 95658f0484fSRodney W. Grimes if (m_room == 0) { 95758f0484fSRodney W. Grimes size_t size = mp - mem; 95858f0484fSRodney W. Grimes 959e8420087SWarner Losh if ((mem = reallocf(mem, size + SFRAG)) == NULL) 96058f0484fSRodney W. Grimes return (-2); 96158f0484fSRodney W. Grimes m_room = SFRAG; 96258f0484fSRodney W. Grimes mp = mem + size; 96358f0484fSRodney W. Grimes } 96458f0484fSRodney W. Grimes } 96558f0484fSRodney W. Grimes *mp++ = '\0'; /* loop invariant let's us do this */ 96658f0484fSRodney W. Grimes m_room--; 96758f0484fSRodney W. Grimes len = mp - mem - 1; 96858f0484fSRodney W. Grimes 96958f0484fSRodney W. Grimes /* 97058f0484fSRodney W. Grimes * Give back any extra memory and return value and success. 97158f0484fSRodney W. Grimes */ 97258f0484fSRodney W. Grimes if (m_room != 0) 973e8420087SWarner Losh if ((mem = reallocf(mem, (size_t)(mp - mem))) == NULL) 97458f0484fSRodney W. Grimes return (-2); 97558f0484fSRodney W. Grimes *str = mem; 97658f0484fSRodney W. Grimes return (len); 97758f0484fSRodney W. Grimes } 97858f0484fSRodney W. Grimes 97958f0484fSRodney W. Grimes /* 98058f0484fSRodney W. Grimes * Cgetnum retrieves the value of the numeric capability cap from the 98158f0484fSRodney W. Grimes * capability record pointed to by buf. The numeric value is returned in 98258f0484fSRodney W. Grimes * the long pointed to by num. 0 is returned on success, -1 if the requested 98358f0484fSRodney W. Grimes * numeric capability couldn't be found. 98458f0484fSRodney W. Grimes */ 98558f0484fSRodney W. Grimes int 98658f0484fSRodney W. Grimes cgetnum(buf, cap, num) 98758f0484fSRodney W. Grimes char *buf, *cap; 98858f0484fSRodney W. Grimes long *num; 98958f0484fSRodney W. Grimes { 990ea8d448aSDavid E. O'Brien long n; 991ea8d448aSDavid E. O'Brien int base, digit; 992ea8d448aSDavid E. O'Brien char *bp; 99358f0484fSRodney W. Grimes 99458f0484fSRodney W. Grimes /* 99558f0484fSRodney W. Grimes * Find numeric capability cap 99658f0484fSRodney W. Grimes */ 99758f0484fSRodney W. Grimes bp = cgetcap(buf, cap, '#'); 99858f0484fSRodney W. Grimes if (bp == NULL) 99958f0484fSRodney W. Grimes return (-1); 100058f0484fSRodney W. Grimes 100158f0484fSRodney W. Grimes /* 100258f0484fSRodney W. Grimes * Look at value and determine numeric base: 100358f0484fSRodney W. Grimes * 0x... or 0X... hexadecimal, 100458f0484fSRodney W. Grimes * else 0... octal, 100558f0484fSRodney W. Grimes * else decimal. 100658f0484fSRodney W. Grimes */ 100758f0484fSRodney W. Grimes if (*bp == '0') { 100858f0484fSRodney W. Grimes bp++; 100958f0484fSRodney W. Grimes if (*bp == 'x' || *bp == 'X') { 101058f0484fSRodney W. Grimes bp++; 101158f0484fSRodney W. Grimes base = 16; 101258f0484fSRodney W. Grimes } else 101358f0484fSRodney W. Grimes base = 8; 101458f0484fSRodney W. Grimes } else 101558f0484fSRodney W. Grimes base = 10; 101658f0484fSRodney W. Grimes 101758f0484fSRodney W. Grimes /* 101858f0484fSRodney W. Grimes * Conversion loop ... 101958f0484fSRodney W. Grimes */ 102058f0484fSRodney W. Grimes n = 0; 102158f0484fSRodney W. Grimes for (;;) { 102258f0484fSRodney W. Grimes if ('0' <= *bp && *bp <= '9') 102358f0484fSRodney W. Grimes digit = *bp - '0'; 102458f0484fSRodney W. Grimes else if ('a' <= *bp && *bp <= 'f') 102558f0484fSRodney W. Grimes digit = 10 + *bp - 'a'; 102658f0484fSRodney W. Grimes else if ('A' <= *bp && *bp <= 'F') 102758f0484fSRodney W. Grimes digit = 10 + *bp - 'A'; 102858f0484fSRodney W. Grimes else 102958f0484fSRodney W. Grimes break; 103058f0484fSRodney W. Grimes 103158f0484fSRodney W. Grimes if (digit >= base) 103258f0484fSRodney W. Grimes break; 103358f0484fSRodney W. Grimes 103458f0484fSRodney W. Grimes n = n * base + digit; 103558f0484fSRodney W. Grimes bp++; 103658f0484fSRodney W. Grimes } 103758f0484fSRodney W. Grimes 103858f0484fSRodney W. Grimes /* 103958f0484fSRodney W. Grimes * Return value and success. 104058f0484fSRodney W. Grimes */ 104158f0484fSRodney W. Grimes *num = n; 104258f0484fSRodney W. Grimes return (0); 104358f0484fSRodney W. Grimes } 104458f0484fSRodney W. Grimes 104558f0484fSRodney W. Grimes 104658f0484fSRodney W. Grimes /* 104758f0484fSRodney W. Grimes * Compare name field of record. 104858f0484fSRodney W. Grimes */ 104958f0484fSRodney W. Grimes static int 105058f0484fSRodney W. Grimes nfcmp(nf, rec) 105158f0484fSRodney W. Grimes char *nf, *rec; 105258f0484fSRodney W. Grimes { 105358f0484fSRodney W. Grimes char *cp, tmp; 105458f0484fSRodney W. Grimes int ret; 105558f0484fSRodney W. Grimes 105658f0484fSRodney W. Grimes for (cp = rec; *cp != ':'; cp++) 105758f0484fSRodney W. Grimes ; 105858f0484fSRodney W. Grimes 105958f0484fSRodney W. Grimes tmp = *(cp + 1); 106058f0484fSRodney W. Grimes *(cp + 1) = '\0'; 106158f0484fSRodney W. Grimes ret = strcmp(nf, rec); 106258f0484fSRodney W. Grimes *(cp + 1) = tmp; 106358f0484fSRodney W. Grimes 106458f0484fSRodney W. Grimes return (ret); 106558f0484fSRodney W. Grimes } 1066