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