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 * 4. Neither the name of the University nor the names of its contributors 1758f0484fSRodney W. Grimes * may be used to endorse or promote products derived from this software 1858f0484fSRodney W. Grimes * without specific prior written permission. 1958f0484fSRodney W. Grimes * 2058f0484fSRodney W. Grimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 2158f0484fSRodney W. Grimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2258f0484fSRodney W. Grimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2358f0484fSRodney W. Grimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 2458f0484fSRodney W. Grimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2558f0484fSRodney W. Grimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2658f0484fSRodney W. Grimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2758f0484fSRodney W. Grimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2858f0484fSRodney W. Grimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2958f0484fSRodney W. Grimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 3058f0484fSRodney W. Grimes * SUCH DAMAGE. 3158f0484fSRodney W. Grimes */ 3258f0484fSRodney W. Grimes 3358f0484fSRodney W. Grimes #if defined(LIBC_SCCS) && !defined(lint) 3458f0484fSRodney W. Grimes static char sccsid[] = "@(#)getcap.c 8.3 (Berkeley) 3/25/94"; 3558f0484fSRodney W. Grimes #endif /* LIBC_SCCS and not lint */ 36ea8d448aSDavid E. O'Brien #include <sys/cdefs.h> 37ea8d448aSDavid E. O'Brien __FBSDID("$FreeBSD$"); 3858f0484fSRodney W. Grimes 39d201fe46SDaniel Eischen #include "namespace.h" 4058f0484fSRodney W. Grimes #include <sys/types.h> 4158f0484fSRodney W. Grimes 4258f0484fSRodney W. Grimes #include <ctype.h> 4358f0484fSRodney W. Grimes #include <errno.h> 4458f0484fSRodney W. Grimes #include <fcntl.h> 4558f0484fSRodney W. Grimes #include <limits.h> 4658f0484fSRodney W. Grimes #include <stdio.h> 4758f0484fSRodney W. Grimes #include <stdlib.h> 4858f0484fSRodney W. Grimes #include <string.h> 4958f0484fSRodney W. Grimes #include <unistd.h> 50d201fe46SDaniel Eischen #include "un-namespace.h" 51d201fe46SDaniel Eischen 52d201fe46SDaniel Eischen #include <db.h> 5358f0484fSRodney W. Grimes 5458f0484fSRodney W. Grimes #define BFRAG 1024 5558f0484fSRodney W. Grimes #define BSIZE 1024 5658f0484fSRodney W. Grimes #define ESC ('[' & 037) /* ASCII ESC */ 5758f0484fSRodney W. Grimes #define MAX_RECURSION 32 /* maximum getent recursion */ 5858f0484fSRodney W. Grimes #define SFRAG 100 /* cgetstr mallocs in SFRAG chunks */ 5958f0484fSRodney W. Grimes 6058f0484fSRodney W. Grimes #define RECOK (char)0 6158f0484fSRodney W. Grimes #define TCERR (char)1 6258f0484fSRodney W. Grimes #define SHADOW (char)2 6358f0484fSRodney W. Grimes 6458f0484fSRodney W. Grimes static size_t topreclen; /* toprec length */ 6558f0484fSRodney W. Grimes static char *toprec; /* Additional record specified by cgetset() */ 6658f0484fSRodney W. Grimes static int gottoprec; /* Flag indicating retrieval of toprecord */ 6758f0484fSRodney W. Grimes 68beb24986SAlfred Perlstein static int cdbget(DB *, char **, const char *); 691372519bSDavid E. O'Brien static int getent(char **, u_int *, char **, int, const char *, int, char *); 70ea8d448aSDavid E. O'Brien static int nfcmp(char *, char *); 7158f0484fSRodney W. Grimes 7258f0484fSRodney W. Grimes /* 7358f0484fSRodney W. Grimes * Cgetset() allows the addition of a user specified buffer to be added 7458f0484fSRodney W. Grimes * to the database array, in effect "pushing" the buffer on top of the 7558f0484fSRodney W. Grimes * virtual database. 0 is returned on success, -1 on failure. 7658f0484fSRodney W. Grimes */ 7758f0484fSRodney W. Grimes int 7880578e90SWarner Losh cgetset(const 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 * 11080578e90SWarner Losh cgetcap(char *buf, const char *cap, int type) 11158f0484fSRodney W. Grimes { 1121372519bSDavid E. O'Brien char *bp; 1131372519bSDavid E. O'Brien const char *cp; 11458f0484fSRodney W. Grimes 11558f0484fSRodney W. Grimes bp = buf; 11658f0484fSRodney W. Grimes for (;;) { 11758f0484fSRodney W. Grimes /* 11858f0484fSRodney W. Grimes * Skip past the current capability field - it's either the 11958f0484fSRodney W. Grimes * name field if this is the first time through the loop, or 12058f0484fSRodney W. Grimes * the remainder of a field whose name failed to match cap. 12158f0484fSRodney W. Grimes */ 12258f0484fSRodney W. Grimes for (;;) 12358f0484fSRodney W. Grimes if (*bp == '\0') 12458f0484fSRodney W. Grimes return (NULL); 12558f0484fSRodney W. Grimes else 12658f0484fSRodney W. Grimes if (*bp++ == ':') 12758f0484fSRodney W. Grimes break; 12858f0484fSRodney W. Grimes 12958f0484fSRodney W. Grimes /* 13058f0484fSRodney W. Grimes * Try to match (cap, type) in buf. 13158f0484fSRodney W. Grimes */ 13258f0484fSRodney W. Grimes for (cp = cap; *cp == *bp && *bp != '\0'; cp++, bp++) 13358f0484fSRodney W. Grimes continue; 13458f0484fSRodney W. Grimes if (*cp != '\0') 13558f0484fSRodney W. Grimes continue; 13658f0484fSRodney W. Grimes if (*bp == '@') 13758f0484fSRodney W. Grimes return (NULL); 13858f0484fSRodney W. Grimes if (type == ':') { 13958f0484fSRodney W. Grimes if (*bp != '\0' && *bp != ':') 14058f0484fSRodney W. Grimes continue; 14158f0484fSRodney W. Grimes return(bp); 14258f0484fSRodney W. Grimes } 14358f0484fSRodney W. Grimes if (*bp != type) 14458f0484fSRodney W. Grimes continue; 14558f0484fSRodney W. Grimes bp++; 14658f0484fSRodney W. Grimes return (*bp == '@' ? NULL : bp); 14758f0484fSRodney W. Grimes } 14858f0484fSRodney W. Grimes /* NOTREACHED */ 14958f0484fSRodney W. Grimes } 15058f0484fSRodney W. Grimes 15158f0484fSRodney W. Grimes /* 15258f0484fSRodney W. Grimes * Cgetent extracts the capability record name from the NULL terminated file 15358f0484fSRodney W. Grimes * array db_array and returns a pointer to a malloc'd copy of it in buf. 15458f0484fSRodney W. Grimes * Buf must be retained through all subsequent calls to cgetcap, cgetnum, 15558f0484fSRodney W. Grimes * cgetflag, and cgetstr, but may then be free'd. 0 is returned on success, 15658f0484fSRodney W. Grimes * -1 if the requested record couldn't be found, -2 if a system error was 15758f0484fSRodney W. Grimes * encountered (couldn't open/read a file, etc.), and -3 if a potential 15858f0484fSRodney W. Grimes * reference loop is detected. 15958f0484fSRodney W. Grimes */ 16058f0484fSRodney W. Grimes int 16180578e90SWarner Losh cgetent(char **buf, char **db_array, const char *name) 16258f0484fSRodney W. Grimes { 16358f0484fSRodney W. Grimes u_int dummy; 16458f0484fSRodney W. Grimes 16558f0484fSRodney W. Grimes return (getent(buf, &dummy, db_array, -1, name, 0, NULL)); 16658f0484fSRodney W. Grimes } 16758f0484fSRodney W. Grimes 16858f0484fSRodney W. Grimes /* 16958f0484fSRodney W. Grimes * Getent implements the functions of cgetent. If fd is non-negative, 17058f0484fSRodney W. Grimes * *db_array has already been opened and fd is the open file descriptor. We 17158f0484fSRodney W. Grimes * do this to save time and avoid using up file descriptors for tc= 17258f0484fSRodney W. Grimes * recursions. 17358f0484fSRodney W. Grimes * 17458f0484fSRodney W. Grimes * Getent returns the same success/failure codes as cgetent. On success, a 17558f0484fSRodney W. Grimes * pointer to a malloc'ed capability record with all tc= capabilities fully 17658f0484fSRodney W. Grimes * expanded and its length (not including trailing ASCII NUL) are left in 17758f0484fSRodney W. Grimes * *cap and *len. 17858f0484fSRodney W. Grimes * 17958f0484fSRodney W. Grimes * Basic algorithm: 18058f0484fSRodney W. Grimes * + Allocate memory incrementally as needed in chunks of size BFRAG 18158f0484fSRodney W. Grimes * for capability buffer. 18258f0484fSRodney W. Grimes * + Recurse for each tc=name and interpolate result. Stop when all 18358f0484fSRodney W. Grimes * names interpolated, a name can't be found, or depth exceeds 18458f0484fSRodney W. Grimes * MAX_RECURSION. 18558f0484fSRodney W. Grimes */ 18658f0484fSRodney W. Grimes static int 1871372519bSDavid E. O'Brien getent(char **cap, u_int *len, char **db_array, int fd, const char *name, 1881372519bSDavid E. O'Brien int depth, char *nfield) 18958f0484fSRodney W. Grimes { 19058f0484fSRodney W. Grimes DB *capdbp; 191ea8d448aSDavid E. O'Brien char *r_end, *rp, **db_p; 1929b4dadd3SXin LI int myfd, eof, foundit, retval; 19358f0484fSRodney W. Grimes char *record, *cbuf; 19458f0484fSRodney W. Grimes int tc_not_resolved; 19558f0484fSRodney W. Grimes char pbuf[_POSIX_PATH_MAX]; 19658f0484fSRodney W. Grimes 19758f0484fSRodney W. Grimes /* 19858f0484fSRodney W. Grimes * Return with ``loop detected'' error if we've recursed more than 19958f0484fSRodney W. Grimes * MAX_RECURSION times. 20058f0484fSRodney W. Grimes */ 20158f0484fSRodney W. Grimes if (depth > MAX_RECURSION) 20258f0484fSRodney W. Grimes return (-3); 20358f0484fSRodney W. Grimes 20458f0484fSRodney W. Grimes /* 20558f0484fSRodney W. Grimes * Check if we have a top record from cgetset(). 20658f0484fSRodney W. Grimes */ 20758f0484fSRodney W. Grimes if (depth == 0 && toprec != NULL && cgetmatch(toprec, name) == 0) { 20858f0484fSRodney W. Grimes if ((record = malloc (topreclen + BFRAG)) == NULL) { 20958f0484fSRodney W. Grimes errno = ENOMEM; 21058f0484fSRodney W. Grimes return (-2); 21158f0484fSRodney W. Grimes } 21258f0484fSRodney W. Grimes (void)strcpy(record, toprec); 21358f0484fSRodney W. Grimes myfd = 0; 21458f0484fSRodney W. Grimes db_p = db_array; 21558f0484fSRodney W. Grimes rp = record + topreclen + 1; 21658f0484fSRodney W. Grimes r_end = rp + BFRAG; 21758f0484fSRodney W. Grimes goto tc_exp; 21858f0484fSRodney W. Grimes } 21958f0484fSRodney W. Grimes /* 22058f0484fSRodney W. Grimes * Allocate first chunk of memory. 22158f0484fSRodney W. Grimes */ 22258f0484fSRodney W. Grimes if ((record = malloc(BFRAG)) == NULL) { 22358f0484fSRodney W. Grimes errno = ENOMEM; 22458f0484fSRodney W. Grimes return (-2); 22558f0484fSRodney W. Grimes } 22658f0484fSRodney W. Grimes r_end = record + BFRAG; 22758f0484fSRodney W. Grimes foundit = 0; 22858f0484fSRodney W. Grimes /* 22958f0484fSRodney W. Grimes * Loop through database array until finding the record. 23058f0484fSRodney W. Grimes */ 23158f0484fSRodney W. Grimes 23258f0484fSRodney W. Grimes for (db_p = db_array; *db_p != NULL; db_p++) { 23358f0484fSRodney W. Grimes eof = 0; 23458f0484fSRodney W. Grimes 23558f0484fSRodney W. Grimes /* 23658f0484fSRodney W. Grimes * Open database if not already open. 23758f0484fSRodney W. Grimes */ 23858f0484fSRodney W. Grimes 23958f0484fSRodney W. Grimes if (fd >= 0) { 24011ea2762SJohn Polstra (void)lseek(fd, (off_t)0, SEEK_SET); 24158f0484fSRodney W. Grimes myfd = 0; 24258f0484fSRodney W. Grimes } else { 24358f0484fSRodney W. Grimes (void)snprintf(pbuf, sizeof(pbuf), "%s.db", *db_p); 24458f0484fSRodney W. Grimes if ((capdbp = dbopen(pbuf, O_RDONLY, 0, DB_HASH, 0)) 24558f0484fSRodney W. Grimes != NULL) { 24658f0484fSRodney W. Grimes free(record); 24758f0484fSRodney W. Grimes retval = cdbget(capdbp, &record, name); 24858f0484fSRodney W. Grimes if (retval < 0) { 24958f0484fSRodney W. Grimes /* no record available */ 25058f0484fSRodney W. Grimes (void)capdbp->close(capdbp); 25158f0484fSRodney W. Grimes return (retval); 25258f0484fSRodney W. Grimes } 25358f0484fSRodney W. Grimes /* save the data; close frees it */ 2549b4dadd3SXin LI cbuf = strdup(record); 25558f0484fSRodney W. Grimes if (capdbp->close(capdbp) < 0) { 25658f0484fSRodney W. Grimes free(cbuf); 25758f0484fSRodney W. Grimes return (-2); 25858f0484fSRodney W. Grimes } 2599b4dadd3SXin LI if (cbuf == NULL) { 2609b4dadd3SXin LI errno = ENOMEM; 2619b4dadd3SXin LI return (-2); 2629b4dadd3SXin LI } 263718d3b28SXin LI *len = strlen(cbuf); 26458f0484fSRodney W. Grimes *cap = cbuf; 26558f0484fSRodney W. Grimes return (retval); 26658f0484fSRodney W. Grimes } else { 26705eb11cbSJilles Tjoelker fd = _open(*db_p, O_RDONLY | O_CLOEXEC, 0); 26843b4fd73SWarner Losh if (fd < 0) 26958f0484fSRodney W. Grimes continue; 27058f0484fSRodney W. Grimes myfd = 1; 27158f0484fSRodney W. Grimes } 27258f0484fSRodney W. Grimes } 27358f0484fSRodney W. Grimes /* 27458f0484fSRodney W. Grimes * Find the requested capability record ... 27558f0484fSRodney W. Grimes */ 27658f0484fSRodney W. Grimes { 27758f0484fSRodney W. Grimes char buf[BUFSIZ]; 278ea8d448aSDavid E. O'Brien char *b_end, *bp; 279ea8d448aSDavid E. O'Brien int c; 28058f0484fSRodney W. Grimes 28158f0484fSRodney W. Grimes /* 28258f0484fSRodney W. Grimes * Loop invariants: 28358f0484fSRodney W. Grimes * There is always room for one more character in record. 28458f0484fSRodney W. Grimes * R_end always points just past end of record. 28558f0484fSRodney W. Grimes * Rp always points just past last character in record. 28658f0484fSRodney W. Grimes * B_end always points just past last character in buf. 28758f0484fSRodney W. Grimes * Bp always points at next character in buf. 28858f0484fSRodney W. Grimes */ 28958f0484fSRodney W. Grimes b_end = buf; 29058f0484fSRodney W. Grimes bp = buf; 29158f0484fSRodney W. Grimes for (;;) { 29258f0484fSRodney W. Grimes 29358f0484fSRodney W. Grimes /* 29458f0484fSRodney W. Grimes * Read in a line implementing (\, newline) 29558f0484fSRodney W. Grimes * line continuation. 29658f0484fSRodney W. Grimes */ 29758f0484fSRodney W. Grimes rp = record; 29858f0484fSRodney W. Grimes for (;;) { 29958f0484fSRodney W. Grimes if (bp >= b_end) { 30058f0484fSRodney W. Grimes int n; 30158f0484fSRodney W. Grimes 3029233c4d9SJason Evans n = _read(fd, buf, sizeof(buf)); 30358f0484fSRodney W. Grimes if (n <= 0) { 30458f0484fSRodney W. Grimes if (myfd) 3059233c4d9SJason Evans (void)_close(fd); 30658f0484fSRodney W. Grimes if (n < 0) { 30758f0484fSRodney W. Grimes free(record); 30858f0484fSRodney W. Grimes return (-2); 30958f0484fSRodney W. Grimes } else { 31058f0484fSRodney W. Grimes fd = -1; 31158f0484fSRodney W. Grimes eof = 1; 31258f0484fSRodney W. Grimes break; 31358f0484fSRodney W. Grimes } 31458f0484fSRodney W. Grimes } 31558f0484fSRodney W. Grimes b_end = buf+n; 31658f0484fSRodney W. Grimes bp = buf; 31758f0484fSRodney W. Grimes } 31858f0484fSRodney W. Grimes 31958f0484fSRodney W. Grimes c = *bp++; 32058f0484fSRodney W. Grimes if (c == '\n') { 32158f0484fSRodney W. Grimes if (rp > record && *(rp-1) == '\\') { 32258f0484fSRodney W. Grimes rp--; 32358f0484fSRodney W. Grimes continue; 32458f0484fSRodney W. Grimes } else 32558f0484fSRodney W. Grimes break; 32658f0484fSRodney W. Grimes } 32758f0484fSRodney W. Grimes *rp++ = c; 32858f0484fSRodney W. Grimes 32958f0484fSRodney W. Grimes /* 33058f0484fSRodney W. Grimes * Enforce loop invariant: if no room 33158f0484fSRodney W. Grimes * left in record buffer, try to get 33258f0484fSRodney W. Grimes * some more. 33358f0484fSRodney W. Grimes */ 33458f0484fSRodney W. Grimes if (rp >= r_end) { 33558f0484fSRodney W. Grimes u_int pos; 33658f0484fSRodney W. Grimes size_t newsize; 33758f0484fSRodney W. Grimes 33858f0484fSRodney W. Grimes pos = rp - record; 33958f0484fSRodney W. Grimes newsize = r_end - record + BFRAG; 340e8420087SWarner Losh record = reallocf(record, newsize); 34158f0484fSRodney W. Grimes if (record == NULL) { 34258f0484fSRodney W. Grimes errno = ENOMEM; 34358f0484fSRodney W. Grimes if (myfd) 3449233c4d9SJason Evans (void)_close(fd); 34558f0484fSRodney W. Grimes return (-2); 34658f0484fSRodney W. Grimes } 34758f0484fSRodney W. Grimes r_end = record + newsize; 34858f0484fSRodney W. Grimes rp = record + pos; 34958f0484fSRodney W. Grimes } 35058f0484fSRodney W. Grimes } 35158f0484fSRodney W. Grimes /* loop invariant let's us do this */ 35258f0484fSRodney W. Grimes *rp++ = '\0'; 35358f0484fSRodney W. Grimes 35458f0484fSRodney W. Grimes /* 35558f0484fSRodney W. Grimes * If encountered eof check next file. 35658f0484fSRodney W. Grimes */ 35758f0484fSRodney W. Grimes if (eof) 35858f0484fSRodney W. Grimes break; 35958f0484fSRodney W. Grimes 36058f0484fSRodney W. Grimes /* 36158f0484fSRodney W. Grimes * Toss blank lines and comments. 36258f0484fSRodney W. Grimes */ 36358f0484fSRodney W. Grimes if (*record == '\0' || *record == '#') 36458f0484fSRodney W. Grimes continue; 36558f0484fSRodney W. Grimes 36658f0484fSRodney W. Grimes /* 36758f0484fSRodney W. Grimes * See if this is the record we want ... 36858f0484fSRodney W. Grimes */ 36958f0484fSRodney W. Grimes if (cgetmatch(record, name) == 0) { 37058f0484fSRodney W. Grimes if (nfield == NULL || !nfcmp(nfield, record)) { 37158f0484fSRodney W. Grimes foundit = 1; 37258f0484fSRodney W. Grimes break; /* found it! */ 37358f0484fSRodney W. Grimes } 37458f0484fSRodney W. Grimes } 37558f0484fSRodney W. Grimes } 37658f0484fSRodney W. Grimes } 37758f0484fSRodney W. Grimes if (foundit) 37858f0484fSRodney W. Grimes break; 37958f0484fSRodney W. Grimes } 38058f0484fSRodney W. Grimes 3818187dd1cSTim Vanderhoek if (!foundit) { 3828187dd1cSTim Vanderhoek free(record); 38358f0484fSRodney W. Grimes return (-1); 3848187dd1cSTim Vanderhoek } 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: { 391ea8d448aSDavid E. O'Brien char *newicap, *s; 392ea8d448aSDavid E. O'Brien 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) 4369233c4d9SJason Evans (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) 4869233c4d9SJason Evans (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) 5189233c4d9SJason Evans (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 534beb24986SAlfred Perlstein cdbget(DB *capdbp, char **bp, const char *name) 53558f0484fSRodney W. Grimes { 53658f0484fSRodney W. Grimes DBT key, data; 537beb24986SAlfred Perlstein char *namebuf; 53858f0484fSRodney W. Grimes 539beb24986SAlfred Perlstein namebuf = strdup(name); 540beb24986SAlfred Perlstein if (namebuf == NULL) 541beb24986SAlfred Perlstein return (-2); 542beb24986SAlfred Perlstein key.data = namebuf; 543beb24986SAlfred Perlstein key.size = strlen(namebuf); 54458f0484fSRodney W. Grimes 54558f0484fSRodney W. Grimes for (;;) { 54658f0484fSRodney W. Grimes /* Get the reference. */ 54758f0484fSRodney W. Grimes switch(capdbp->get(capdbp, &key, &data, 0)) { 54858f0484fSRodney W. Grimes case -1: 549beb24986SAlfred Perlstein free(namebuf); 55058f0484fSRodney W. Grimes return (-2); 55158f0484fSRodney W. Grimes case 1: 552beb24986SAlfred Perlstein free(namebuf); 55358f0484fSRodney W. Grimes return (-1); 55458f0484fSRodney W. Grimes } 55558f0484fSRodney W. Grimes 55658f0484fSRodney W. Grimes /* If not an index to another record, leave. */ 55758f0484fSRodney W. Grimes if (((char *)data.data)[0] != SHADOW) 55858f0484fSRodney W. Grimes break; 55958f0484fSRodney W. Grimes 56058f0484fSRodney W. Grimes key.data = (char *)data.data + 1; 56158f0484fSRodney W. Grimes key.size = data.size - 1; 56258f0484fSRodney W. Grimes } 56358f0484fSRodney W. Grimes 56458f0484fSRodney W. Grimes *bp = (char *)data.data + 1; 565beb24986SAlfred Perlstein free(namebuf); 56658f0484fSRodney W. Grimes return (((char *)(data.data))[0] == TCERR ? 1 : 0); 56758f0484fSRodney W. Grimes } 56858f0484fSRodney W. Grimes 56958f0484fSRodney W. Grimes /* 57058f0484fSRodney W. Grimes * Cgetmatch will return 0 if name is one of the names of the capability 57158f0484fSRodney W. Grimes * record buf, -1 if not. 57258f0484fSRodney W. Grimes */ 57358f0484fSRodney W. Grimes int 57480578e90SWarner Losh cgetmatch(const char *buf, const char *name) 57558f0484fSRodney W. Grimes { 576beb24986SAlfred Perlstein const char *np, *bp; 57758f0484fSRodney W. Grimes 578464ef179SThomas Quinot if (name == NULL || *name == '\0') 579464ef179SThomas Quinot return -1; 580464ef179SThomas Quinot 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 61880578e90SWarner Losh cgetfirst(char **buf, char **db_array) 61958f0484fSRodney W. Grimes { 62058f0484fSRodney W. Grimes (void)cgetclose(); 62158f0484fSRodney W. Grimes return (cgetnext(buf, db_array)); 62258f0484fSRodney W. Grimes } 62358f0484fSRodney W. Grimes 62458f0484fSRodney W. Grimes static FILE *pfp; 62558f0484fSRodney W. Grimes static int slash; 62658f0484fSRodney W. Grimes static char **dbp; 62758f0484fSRodney W. Grimes 62858f0484fSRodney W. Grimes int 62980578e90SWarner Losh cgetclose(void) 63058f0484fSRodney W. Grimes { 63158f0484fSRodney W. Grimes if (pfp != NULL) { 63258f0484fSRodney W. Grimes (void)fclose(pfp); 63358f0484fSRodney W. Grimes pfp = NULL; 63458f0484fSRodney W. Grimes } 63558f0484fSRodney W. Grimes dbp = NULL; 63658f0484fSRodney W. Grimes gottoprec = 0; 63758f0484fSRodney W. Grimes slash = 0; 63858f0484fSRodney W. Grimes return(0); 63958f0484fSRodney W. Grimes } 64058f0484fSRodney W. Grimes 64158f0484fSRodney W. Grimes /* 64258f0484fSRodney W. Grimes * Cgetnext() gets either the first or next entry in the logical database 64358f0484fSRodney W. Grimes * specified by db_array. It returns 0 upon completion of the database, 1 64458f0484fSRodney W. Grimes * upon returning an entry with more remaining, and -1 if an error occurs. 64558f0484fSRodney W. Grimes */ 64658f0484fSRodney W. Grimes int 64780578e90SWarner Losh cgetnext(char **bp, char **db_array) 64858f0484fSRodney W. Grimes { 64958f0484fSRodney W. Grimes size_t len; 6500c0349bfSGarrett Wollman int done, hadreaderr, savederrno, status; 65158f0484fSRodney W. Grimes char *cp, *line, *rp, *np, buf[BSIZE], nbuf[BSIZE]; 65258f0484fSRodney W. Grimes u_int dummy; 65358f0484fSRodney W. Grimes 65458f0484fSRodney W. Grimes if (dbp == NULL) 65558f0484fSRodney W. Grimes dbp = db_array; 65658f0484fSRodney W. Grimes 657*1084b38bSJilles Tjoelker if (pfp == NULL && (pfp = fopen(*dbp, "re")) == NULL) { 65858f0484fSRodney W. Grimes (void)cgetclose(); 65958f0484fSRodney W. Grimes return (-1); 66058f0484fSRodney W. Grimes } 66158f0484fSRodney W. Grimes for (;;) { 66258f0484fSRodney W. Grimes if (toprec && !gottoprec) { 66358f0484fSRodney W. Grimes gottoprec = 1; 66458f0484fSRodney W. Grimes line = toprec; 66558f0484fSRodney W. Grimes } else { 66658f0484fSRodney W. Grimes line = fgetln(pfp, &len); 66758f0484fSRodney W. Grimes if (line == NULL && pfp) { 668bbe8edb0SGarance A Drosehn hadreaderr = ferror(pfp); 669bbe8edb0SGarance A Drosehn if (hadreaderr) 670bbe8edb0SGarance A Drosehn savederrno = errno; 671bbe8edb0SGarance A Drosehn fclose(pfp); 672bbe8edb0SGarance A Drosehn pfp = NULL; 673bbe8edb0SGarance A Drosehn if (hadreaderr) { 674bbe8edb0SGarance A Drosehn cgetclose(); 675bbe8edb0SGarance A Drosehn errno = savederrno; 67658f0484fSRodney W. Grimes return (-1); 67758f0484fSRodney W. Grimes } else { 67858f0484fSRodney W. Grimes if (*++dbp == NULL) { 67958f0484fSRodney W. Grimes (void)cgetclose(); 68058f0484fSRodney W. Grimes return (0); 68158f0484fSRodney W. Grimes } else if ((pfp = 682*1084b38bSJilles Tjoelker fopen(*dbp, "re")) == NULL) { 68358f0484fSRodney W. Grimes (void)cgetclose(); 68458f0484fSRodney W. Grimes return (-1); 68558f0484fSRodney W. Grimes } else 68658f0484fSRodney W. Grimes continue; 68758f0484fSRodney W. Grimes } 68858f0484fSRodney W. Grimes } else 68958f0484fSRodney W. Grimes line[len - 1] = '\0'; 69058f0484fSRodney W. Grimes if (len == 1) { 69158f0484fSRodney W. Grimes slash = 0; 69258f0484fSRodney W. Grimes continue; 69358f0484fSRodney W. Grimes } 69449435560SAndrey A. Chernov if (isspace((unsigned char)*line) || 69558f0484fSRodney W. Grimes *line == ':' || *line == '#' || slash) { 69658f0484fSRodney W. Grimes if (line[len - 2] == '\\') 69758f0484fSRodney W. Grimes slash = 1; 69858f0484fSRodney W. Grimes else 69958f0484fSRodney W. Grimes slash = 0; 70058f0484fSRodney W. Grimes continue; 70158f0484fSRodney W. Grimes } 70258f0484fSRodney W. Grimes if (line[len - 2] == '\\') 70358f0484fSRodney W. Grimes slash = 1; 70458f0484fSRodney W. Grimes else 70558f0484fSRodney W. Grimes slash = 0; 70658f0484fSRodney W. Grimes } 70758f0484fSRodney W. Grimes 70858f0484fSRodney W. Grimes 70958f0484fSRodney W. Grimes /* 71058f0484fSRodney W. Grimes * Line points to a name line. 71158f0484fSRodney W. Grimes */ 71258f0484fSRodney W. Grimes done = 0; 71358f0484fSRodney W. Grimes np = nbuf; 71458f0484fSRodney W. Grimes for (;;) { 71558f0484fSRodney W. Grimes for (cp = line; *cp != '\0'; cp++) { 71658f0484fSRodney W. Grimes if (*cp == ':') { 71758f0484fSRodney W. Grimes *np++ = ':'; 71858f0484fSRodney W. Grimes done = 1; 71958f0484fSRodney W. Grimes break; 72058f0484fSRodney W. Grimes } 72158f0484fSRodney W. Grimes if (*cp == '\\') 72258f0484fSRodney W. Grimes break; 72358f0484fSRodney W. Grimes *np++ = *cp; 72458f0484fSRodney W. Grimes } 72558f0484fSRodney W. Grimes if (done) { 72658f0484fSRodney W. Grimes *np = '\0'; 72758f0484fSRodney W. Grimes break; 72858f0484fSRodney W. Grimes } else { /* name field extends beyond the line */ 72958f0484fSRodney W. Grimes line = fgetln(pfp, &len); 73058f0484fSRodney W. Grimes if (line == NULL && pfp) { 731bbe8edb0SGarance A Drosehn /* Name extends beyond the EOF! */ 732bbe8edb0SGarance A Drosehn hadreaderr = ferror(pfp); 733bbe8edb0SGarance A Drosehn if (hadreaderr) 734bbe8edb0SGarance A Drosehn savederrno = errno; 735bbe8edb0SGarance A Drosehn fclose(pfp); 736bbe8edb0SGarance A Drosehn pfp = NULL; 737bbe8edb0SGarance A Drosehn if (hadreaderr) { 738bbe8edb0SGarance A Drosehn cgetclose(); 739bbe8edb0SGarance A Drosehn errno = savederrno; 740bbe8edb0SGarance A Drosehn return (-1); 741bbe8edb0SGarance A Drosehn } else { 742bbe8edb0SGarance A Drosehn cgetclose(); 74358f0484fSRodney W. Grimes return (-1); 74458f0484fSRodney W. Grimes } 74558f0484fSRodney W. Grimes } else 74658f0484fSRodney W. Grimes line[len - 1] = '\0'; 74758f0484fSRodney W. Grimes } 74858f0484fSRodney W. Grimes } 74958f0484fSRodney W. Grimes rp = buf; 750d030d2d2SPoul-Henning Kamp for(cp = nbuf; *cp != '\0'; cp++) 75158f0484fSRodney W. Grimes if (*cp == '|' || *cp == ':') 75258f0484fSRodney W. Grimes break; 75358f0484fSRodney W. Grimes else 75458f0484fSRodney W. Grimes *rp++ = *cp; 75558f0484fSRodney W. Grimes 75658f0484fSRodney W. Grimes *rp = '\0'; 75758f0484fSRodney W. Grimes /* 75858f0484fSRodney W. Grimes * XXX 75958f0484fSRodney W. Grimes * Last argument of getent here should be nbuf if we want true 76058f0484fSRodney W. Grimes * sequential access in the case of duplicates. 76158f0484fSRodney W. Grimes * With NULL, getent will return the first entry found 76258f0484fSRodney W. Grimes * rather than the duplicate entry record. This is a 76358f0484fSRodney W. Grimes * matter of semantics that should be resolved. 76458f0484fSRodney W. Grimes */ 76558f0484fSRodney W. Grimes status = getent(bp, &dummy, db_array, -1, buf, 0, NULL); 76658f0484fSRodney W. Grimes if (status == -2 || status == -3) 76758f0484fSRodney W. Grimes (void)cgetclose(); 76858f0484fSRodney W. Grimes 76958f0484fSRodney W. Grimes return (status + 1); 77058f0484fSRodney W. Grimes } 77158f0484fSRodney W. Grimes /* NOTREACHED */ 77258f0484fSRodney W. Grimes } 77358f0484fSRodney W. Grimes 77458f0484fSRodney W. Grimes /* 77558f0484fSRodney W. Grimes * Cgetstr retrieves the value of the string capability cap from the 77658f0484fSRodney W. Grimes * capability record pointed to by buf. A pointer to a decoded, NUL 77758f0484fSRodney W. Grimes * terminated, malloc'd copy of the string is returned in the char * 77858f0484fSRodney W. Grimes * pointed to by str. The length of the string not including the trailing 77958f0484fSRodney W. Grimes * NUL is returned on success, -1 if the requested string capability 78058f0484fSRodney W. Grimes * couldn't be found, -2 if a system error was encountered (storage 78158f0484fSRodney W. Grimes * allocation failure). 78258f0484fSRodney W. Grimes */ 78358f0484fSRodney W. Grimes int 78480578e90SWarner Losh cgetstr(char *buf, const char *cap, char **str) 78558f0484fSRodney W. Grimes { 786ea8d448aSDavid E. O'Brien u_int m_room; 787ea8d448aSDavid E. O'Brien char *bp, *mp; 78858f0484fSRodney W. Grimes int len; 78958f0484fSRodney W. Grimes char *mem; 79058f0484fSRodney W. Grimes 79158f0484fSRodney W. Grimes /* 79258f0484fSRodney W. Grimes * Find string capability cap 79358f0484fSRodney W. Grimes */ 79458f0484fSRodney W. Grimes bp = cgetcap(buf, cap, '='); 79558f0484fSRodney W. Grimes if (bp == NULL) 79658f0484fSRodney W. Grimes return (-1); 79758f0484fSRodney W. Grimes 79858f0484fSRodney W. Grimes /* 79958f0484fSRodney W. Grimes * Conversion / storage allocation loop ... Allocate memory in 80058f0484fSRodney W. Grimes * chunks SFRAG in size. 80158f0484fSRodney W. Grimes */ 80258f0484fSRodney W. Grimes if ((mem = malloc(SFRAG)) == NULL) { 80358f0484fSRodney W. Grimes errno = ENOMEM; 80458f0484fSRodney W. Grimes return (-2); /* couldn't even allocate the first fragment */ 80558f0484fSRodney W. Grimes } 80658f0484fSRodney W. Grimes m_room = SFRAG; 80758f0484fSRodney W. Grimes mp = mem; 80858f0484fSRodney W. Grimes 80958f0484fSRodney W. Grimes while (*bp != ':' && *bp != '\0') { 81058f0484fSRodney W. Grimes /* 81158f0484fSRodney W. Grimes * Loop invariants: 81258f0484fSRodney W. Grimes * There is always room for one more character in mem. 81358f0484fSRodney W. Grimes * Mp always points just past last character in mem. 81458f0484fSRodney W. Grimes * Bp always points at next character in buf. 81558f0484fSRodney W. Grimes */ 81658f0484fSRodney W. Grimes if (*bp == '^') { 81758f0484fSRodney W. Grimes bp++; 81858f0484fSRodney W. Grimes if (*bp == ':' || *bp == '\0') 81958f0484fSRodney W. Grimes break; /* drop unfinished escape */ 8204f512989SAndrey A. Chernov if (*bp == '?') { 8214f512989SAndrey A. Chernov *mp++ = '\177'; 8224f512989SAndrey A. Chernov bp++; 8234f512989SAndrey A. Chernov } else 82458f0484fSRodney W. Grimes *mp++ = *bp++ & 037; 82558f0484fSRodney W. Grimes } else if (*bp == '\\') { 82658f0484fSRodney W. Grimes bp++; 82758f0484fSRodney W. Grimes if (*bp == ':' || *bp == '\0') 82858f0484fSRodney W. Grimes break; /* drop unfinished escape */ 82958f0484fSRodney W. Grimes if ('0' <= *bp && *bp <= '7') { 830ea8d448aSDavid E. O'Brien int n, i; 83158f0484fSRodney W. Grimes 83258f0484fSRodney W. Grimes n = 0; 83358f0484fSRodney W. Grimes i = 3; /* maximum of three octal digits */ 83458f0484fSRodney W. Grimes do { 83558f0484fSRodney W. Grimes n = n * 8 + (*bp++ - '0'); 83658f0484fSRodney W. Grimes } while (--i && '0' <= *bp && *bp <= '7'); 83758f0484fSRodney W. Grimes *mp++ = n; 83858f0484fSRodney W. Grimes } 83958f0484fSRodney W. Grimes else switch (*bp++) { 84058f0484fSRodney W. Grimes case 'b': case 'B': 84158f0484fSRodney W. Grimes *mp++ = '\b'; 84258f0484fSRodney W. Grimes break; 84358f0484fSRodney W. Grimes case 't': case 'T': 84458f0484fSRodney W. Grimes *mp++ = '\t'; 84558f0484fSRodney W. Grimes break; 84658f0484fSRodney W. Grimes case 'n': case 'N': 84758f0484fSRodney W. Grimes *mp++ = '\n'; 84858f0484fSRodney W. Grimes break; 84958f0484fSRodney W. Grimes case 'f': case 'F': 85058f0484fSRodney W. Grimes *mp++ = '\f'; 85158f0484fSRodney W. Grimes break; 85258f0484fSRodney W. Grimes case 'r': case 'R': 85358f0484fSRodney W. Grimes *mp++ = '\r'; 85458f0484fSRodney W. Grimes break; 85558f0484fSRodney W. Grimes case 'e': case 'E': 85658f0484fSRodney W. Grimes *mp++ = ESC; 85758f0484fSRodney W. Grimes break; 85858f0484fSRodney W. Grimes case 'c': case 'C': 85958f0484fSRodney W. Grimes *mp++ = ':'; 86058f0484fSRodney W. Grimes break; 86158f0484fSRodney W. Grimes default: 86258f0484fSRodney W. Grimes /* 86358f0484fSRodney W. Grimes * Catches '\', '^', and 86458f0484fSRodney W. Grimes * everything else. 86558f0484fSRodney W. Grimes */ 86658f0484fSRodney W. Grimes *mp++ = *(bp-1); 86758f0484fSRodney W. Grimes break; 86858f0484fSRodney W. Grimes } 86958f0484fSRodney W. Grimes } else 87058f0484fSRodney W. Grimes *mp++ = *bp++; 87158f0484fSRodney W. Grimes m_room--; 87258f0484fSRodney W. Grimes 87358f0484fSRodney W. Grimes /* 87458f0484fSRodney W. Grimes * Enforce loop invariant: if no room left in current 87558f0484fSRodney W. Grimes * buffer, try to get some more. 87658f0484fSRodney W. Grimes */ 87758f0484fSRodney W. Grimes if (m_room == 0) { 87858f0484fSRodney W. Grimes size_t size = mp - mem; 87958f0484fSRodney W. Grimes 880e8420087SWarner Losh if ((mem = reallocf(mem, size + SFRAG)) == NULL) 88158f0484fSRodney W. Grimes return (-2); 88258f0484fSRodney W. Grimes m_room = SFRAG; 88358f0484fSRodney W. Grimes mp = mem + size; 88458f0484fSRodney W. Grimes } 88558f0484fSRodney W. Grimes } 88658f0484fSRodney W. Grimes *mp++ = '\0'; /* loop invariant let's us do this */ 88758f0484fSRodney W. Grimes m_room--; 88858f0484fSRodney W. Grimes len = mp - mem - 1; 88958f0484fSRodney W. Grimes 89058f0484fSRodney W. Grimes /* 89158f0484fSRodney W. Grimes * Give back any extra memory and return value and success. 89258f0484fSRodney W. Grimes */ 89358f0484fSRodney W. Grimes if (m_room != 0) 894e8420087SWarner Losh if ((mem = reallocf(mem, (size_t)(mp - mem))) == NULL) 89558f0484fSRodney W. Grimes return (-2); 89658f0484fSRodney W. Grimes *str = mem; 89758f0484fSRodney W. Grimes return (len); 89858f0484fSRodney W. Grimes } 89958f0484fSRodney W. Grimes 90058f0484fSRodney W. Grimes /* 90158f0484fSRodney W. Grimes * Cgetustr retrieves the value of the string capability cap from the 90258f0484fSRodney W. Grimes * capability record pointed to by buf. The difference between cgetustr() 90358f0484fSRodney W. Grimes * and cgetstr() is that cgetustr does not decode escapes but rather treats 90458f0484fSRodney W. Grimes * all characters literally. A pointer to a NUL terminated malloc'd 90558f0484fSRodney W. Grimes * copy of the string is returned in the char pointed to by str. The 90658f0484fSRodney W. Grimes * length of the string not including the trailing NUL is returned on success, 90758f0484fSRodney W. Grimes * -1 if the requested string capability couldn't be found, -2 if a system 90858f0484fSRodney W. Grimes * error was encountered (storage allocation failure). 90958f0484fSRodney W. Grimes */ 91058f0484fSRodney W. Grimes int 91180578e90SWarner Losh cgetustr(char *buf, const char *cap, char **str) 91258f0484fSRodney W. Grimes { 913ea8d448aSDavid E. O'Brien u_int m_room; 914ea8d448aSDavid E. O'Brien char *bp, *mp; 91558f0484fSRodney W. Grimes int len; 91658f0484fSRodney W. Grimes char *mem; 91758f0484fSRodney W. Grimes 91858f0484fSRodney W. Grimes /* 91958f0484fSRodney W. Grimes * Find string capability cap 92058f0484fSRodney W. Grimes */ 92158f0484fSRodney W. Grimes if ((bp = cgetcap(buf, cap, '=')) == NULL) 92258f0484fSRodney W. Grimes return (-1); 92358f0484fSRodney W. Grimes 92458f0484fSRodney W. Grimes /* 92558f0484fSRodney W. Grimes * Conversion / storage allocation loop ... Allocate memory in 92658f0484fSRodney W. Grimes * chunks SFRAG in size. 92758f0484fSRodney W. Grimes */ 92858f0484fSRodney W. Grimes if ((mem = malloc(SFRAG)) == NULL) { 92958f0484fSRodney W. Grimes errno = ENOMEM; 93058f0484fSRodney W. Grimes return (-2); /* couldn't even allocate the first fragment */ 93158f0484fSRodney W. Grimes } 93258f0484fSRodney W. Grimes m_room = SFRAG; 93358f0484fSRodney W. Grimes mp = mem; 93458f0484fSRodney W. Grimes 93558f0484fSRodney W. Grimes while (*bp != ':' && *bp != '\0') { 93658f0484fSRodney W. Grimes /* 93758f0484fSRodney W. Grimes * Loop invariants: 93858f0484fSRodney W. Grimes * There is always room for one more character in mem. 93958f0484fSRodney W. Grimes * Mp always points just past last character in mem. 94058f0484fSRodney W. Grimes * Bp always points at next character in buf. 94158f0484fSRodney W. Grimes */ 94258f0484fSRodney W. Grimes *mp++ = *bp++; 94358f0484fSRodney W. Grimes m_room--; 94458f0484fSRodney W. Grimes 94558f0484fSRodney W. Grimes /* 94658f0484fSRodney W. Grimes * Enforce loop invariant: if no room left in current 94758f0484fSRodney W. Grimes * buffer, try to get some more. 94858f0484fSRodney W. Grimes */ 94958f0484fSRodney W. Grimes if (m_room == 0) { 95058f0484fSRodney W. Grimes size_t size = mp - mem; 95158f0484fSRodney W. Grimes 952e8420087SWarner Losh if ((mem = reallocf(mem, size + SFRAG)) == NULL) 95358f0484fSRodney W. Grimes return (-2); 95458f0484fSRodney W. Grimes m_room = SFRAG; 95558f0484fSRodney W. Grimes mp = mem + size; 95658f0484fSRodney W. Grimes } 95758f0484fSRodney W. Grimes } 95858f0484fSRodney W. Grimes *mp++ = '\0'; /* loop invariant let's us do this */ 95958f0484fSRodney W. Grimes m_room--; 96058f0484fSRodney W. Grimes len = mp - mem - 1; 96158f0484fSRodney W. Grimes 96258f0484fSRodney W. Grimes /* 96358f0484fSRodney W. Grimes * Give back any extra memory and return value and success. 96458f0484fSRodney W. Grimes */ 96558f0484fSRodney W. Grimes if (m_room != 0) 966e8420087SWarner Losh if ((mem = reallocf(mem, (size_t)(mp - mem))) == NULL) 96758f0484fSRodney W. Grimes return (-2); 96858f0484fSRodney W. Grimes *str = mem; 96958f0484fSRodney W. Grimes return (len); 97058f0484fSRodney W. Grimes } 97158f0484fSRodney W. Grimes 97258f0484fSRodney W. Grimes /* 97358f0484fSRodney W. Grimes * Cgetnum retrieves the value of the numeric capability cap from the 97458f0484fSRodney W. Grimes * capability record pointed to by buf. The numeric value is returned in 97558f0484fSRodney W. Grimes * the long pointed to by num. 0 is returned on success, -1 if the requested 97658f0484fSRodney W. Grimes * numeric capability couldn't be found. 97758f0484fSRodney W. Grimes */ 97858f0484fSRodney W. Grimes int 97980578e90SWarner Losh cgetnum(char *buf, const char *cap, long *num) 98058f0484fSRodney W. Grimes { 981ea8d448aSDavid E. O'Brien long n; 982ea8d448aSDavid E. O'Brien int base, digit; 983ea8d448aSDavid E. O'Brien char *bp; 98458f0484fSRodney W. Grimes 98558f0484fSRodney W. Grimes /* 98658f0484fSRodney W. Grimes * Find numeric capability cap 98758f0484fSRodney W. Grimes */ 98858f0484fSRodney W. Grimes bp = cgetcap(buf, cap, '#'); 98958f0484fSRodney W. Grimes if (bp == NULL) 99058f0484fSRodney W. Grimes return (-1); 99158f0484fSRodney W. Grimes 99258f0484fSRodney W. Grimes /* 99358f0484fSRodney W. Grimes * Look at value and determine numeric base: 99458f0484fSRodney W. Grimes * 0x... or 0X... hexadecimal, 99558f0484fSRodney W. Grimes * else 0... octal, 99658f0484fSRodney W. Grimes * else decimal. 99758f0484fSRodney W. Grimes */ 99858f0484fSRodney W. Grimes if (*bp == '0') { 99958f0484fSRodney W. Grimes bp++; 100058f0484fSRodney W. Grimes if (*bp == 'x' || *bp == 'X') { 100158f0484fSRodney W. Grimes bp++; 100258f0484fSRodney W. Grimes base = 16; 100358f0484fSRodney W. Grimes } else 100458f0484fSRodney W. Grimes base = 8; 100558f0484fSRodney W. Grimes } else 100658f0484fSRodney W. Grimes base = 10; 100758f0484fSRodney W. Grimes 100858f0484fSRodney W. Grimes /* 100958f0484fSRodney W. Grimes * Conversion loop ... 101058f0484fSRodney W. Grimes */ 101158f0484fSRodney W. Grimes n = 0; 101258f0484fSRodney W. Grimes for (;;) { 101358f0484fSRodney W. Grimes if ('0' <= *bp && *bp <= '9') 101458f0484fSRodney W. Grimes digit = *bp - '0'; 101558f0484fSRodney W. Grimes else if ('a' <= *bp && *bp <= 'f') 101658f0484fSRodney W. Grimes digit = 10 + *bp - 'a'; 101758f0484fSRodney W. Grimes else if ('A' <= *bp && *bp <= 'F') 101858f0484fSRodney W. Grimes digit = 10 + *bp - 'A'; 101958f0484fSRodney W. Grimes else 102058f0484fSRodney W. Grimes break; 102158f0484fSRodney W. Grimes 102258f0484fSRodney W. Grimes if (digit >= base) 102358f0484fSRodney W. Grimes break; 102458f0484fSRodney W. Grimes 102558f0484fSRodney W. Grimes n = n * base + digit; 102658f0484fSRodney W. Grimes bp++; 102758f0484fSRodney W. Grimes } 102858f0484fSRodney W. Grimes 102958f0484fSRodney W. Grimes /* 103058f0484fSRodney W. Grimes * Return value and success. 103158f0484fSRodney W. Grimes */ 103258f0484fSRodney W. Grimes *num = n; 103358f0484fSRodney W. Grimes return (0); 103458f0484fSRodney W. Grimes } 103558f0484fSRodney W. Grimes 103658f0484fSRodney W. Grimes 103758f0484fSRodney W. Grimes /* 103858f0484fSRodney W. Grimes * Compare name field of record. 103958f0484fSRodney W. Grimes */ 104058f0484fSRodney W. Grimes static int 104180578e90SWarner Losh nfcmp(char *nf, char *rec) 104258f0484fSRodney W. Grimes { 104358f0484fSRodney W. Grimes char *cp, tmp; 104458f0484fSRodney W. Grimes int ret; 104558f0484fSRodney W. Grimes 104658f0484fSRodney W. Grimes for (cp = rec; *cp != ':'; cp++) 104758f0484fSRodney W. Grimes ; 104858f0484fSRodney W. Grimes 104958f0484fSRodney W. Grimes tmp = *(cp + 1); 105058f0484fSRodney W. Grimes *(cp + 1) = '\0'; 105158f0484fSRodney W. Grimes ret = strcmp(nf, rec); 105258f0484fSRodney W. Grimes *(cp + 1) = tmp; 105358f0484fSRodney W. Grimes 105458f0484fSRodney W. Grimes return (ret); 105558f0484fSRodney W. Grimes } 1056