1*0a6a1f1dSLionel Sambuc /* $NetBSD: getcap.c,v 1.56 2014/09/24 13:18:52 christos Exp $ */
22fe8fb19SBen Gras
32fe8fb19SBen Gras /*-
42fe8fb19SBen Gras * Copyright (c) 1992, 1993
52fe8fb19SBen Gras * The Regents of the University of California. All rights reserved.
62fe8fb19SBen Gras *
72fe8fb19SBen Gras * This code is derived from software contributed to Berkeley by
82fe8fb19SBen Gras * Casey Leedom of Lawrence Livermore National Laboratory.
92fe8fb19SBen Gras *
102fe8fb19SBen Gras * Redistribution and use in source and binary forms, with or without
112fe8fb19SBen Gras * modification, are permitted provided that the following conditions
122fe8fb19SBen Gras * are met:
132fe8fb19SBen Gras * 1. Redistributions of source code must retain the above copyright
142fe8fb19SBen Gras * notice, this list of conditions and the following disclaimer.
152fe8fb19SBen Gras * 2. Redistributions in binary form must reproduce the above copyright
162fe8fb19SBen Gras * notice, this list of conditions and the following disclaimer in the
172fe8fb19SBen Gras * documentation and/or other materials provided with the distribution.
182fe8fb19SBen Gras * 3. Neither the name of the University nor the names of its contributors
192fe8fb19SBen Gras * may be used to endorse or promote products derived from this software
202fe8fb19SBen Gras * without specific prior written permission.
212fe8fb19SBen Gras *
222fe8fb19SBen Gras * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
232fe8fb19SBen Gras * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
242fe8fb19SBen Gras * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
252fe8fb19SBen Gras * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
262fe8fb19SBen Gras * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
272fe8fb19SBen Gras * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
282fe8fb19SBen Gras * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
292fe8fb19SBen Gras * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
302fe8fb19SBen Gras * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
312fe8fb19SBen Gras * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
322fe8fb19SBen Gras * SUCH DAMAGE.
332fe8fb19SBen Gras */
342fe8fb19SBen Gras
352fe8fb19SBen Gras #if HAVE_NBTOOL_CONFIG_H
362fe8fb19SBen Gras #include "nbtool_config.h"
372fe8fb19SBen Gras #endif
382fe8fb19SBen Gras
392fe8fb19SBen Gras #include <sys/cdefs.h>
402fe8fb19SBen Gras #if defined(LIBC_SCCS) && !defined(lint)
412fe8fb19SBen Gras #if 0
422fe8fb19SBen Gras static char sccsid[] = "@(#)getcap.c 8.3 (Berkeley) 3/25/94";
432fe8fb19SBen Gras #else
44*0a6a1f1dSLionel Sambuc __RCSID("$NetBSD: getcap.c,v 1.56 2014/09/24 13:18:52 christos Exp $");
452fe8fb19SBen Gras #endif
462fe8fb19SBen Gras #endif /* LIBC_SCCS and not lint */
472fe8fb19SBen Gras
482fe8fb19SBen Gras #ifndef SMALL
492fe8fb19SBen Gras #include "namespace.h"
502fe8fb19SBen Gras #endif
512fe8fb19SBen Gras #include <sys/types.h>
522fe8fb19SBen Gras #include <sys/param.h>
532fe8fb19SBen Gras
542fe8fb19SBen Gras #include <assert.h>
55f14fb602SLionel Sambuc #include <stddef.h>
562fe8fb19SBen Gras #include <ctype.h>
572fe8fb19SBen Gras #ifndef SMALL
582fe8fb19SBen Gras #include <db.h>
592fe8fb19SBen Gras #endif
602fe8fb19SBen Gras #include <errno.h>
612fe8fb19SBen Gras #include <fcntl.h>
622fe8fb19SBen Gras #include <limits.h>
632fe8fb19SBen Gras #include <stdio.h>
642fe8fb19SBen Gras #include <stdlib.h>
652fe8fb19SBen Gras #include <string.h>
662fe8fb19SBen Gras #include <unistd.h>
672fe8fb19SBen Gras
68f14fb602SLionel Sambuc #if defined(__weak_alias) && !defined(SMALL)
692fe8fb19SBen Gras __weak_alias(cgetcap,_cgetcap)
702fe8fb19SBen Gras __weak_alias(cgetclose,_cgetclose)
712fe8fb19SBen Gras __weak_alias(cgetent,_cgetent)
722fe8fb19SBen Gras __weak_alias(cgetfirst,_cgetfirst)
732fe8fb19SBen Gras __weak_alias(cgetmatch,_cgetmatch)
742fe8fb19SBen Gras __weak_alias(cgetnext,_cgetnext)
752fe8fb19SBen Gras __weak_alias(cgetnum,_cgetnum)
762fe8fb19SBen Gras __weak_alias(cgetset,_cgetset)
772fe8fb19SBen Gras __weak_alias(cgetstr,_cgetstr)
782fe8fb19SBen Gras __weak_alias(cgetustr,_cgetustr)
792fe8fb19SBen Gras __weak_alias(csetexpandtc,_csetexpandtc)
802fe8fb19SBen Gras #endif
812fe8fb19SBen Gras
822fe8fb19SBen Gras #define BFRAG 1024
832fe8fb19SBen Gras #define BSIZE 1024
842fe8fb19SBen Gras #define ESC ('[' & 037) /* ASCII ESC */
852fe8fb19SBen Gras #define MAX_RECURSION 32 /* maximum getent recursion */
862fe8fb19SBen Gras #define SFRAG 100 /* cgetstr mallocs in SFRAG chunks */
872fe8fb19SBen Gras
882fe8fb19SBen Gras #define RECOK (char)0
892fe8fb19SBen Gras #define TCERR (char)1
902fe8fb19SBen Gras #define SHADOW (char)2
912fe8fb19SBen Gras
922fe8fb19SBen Gras static size_t topreclen; /* toprec length */
932fe8fb19SBen Gras static char *toprec; /* Additional record specified by cgetset() */
942fe8fb19SBen Gras static int gottoprec; /* Flag indicating retrieval of toprecord */
952fe8fb19SBen Gras static int expandtc = 1; /* flag to expand tc= or not */
962fe8fb19SBen Gras
972fe8fb19SBen Gras #ifndef SMALL
982fe8fb19SBen Gras static int cdbget(DB *, char **, const char *);
992fe8fb19SBen Gras #endif
1002fe8fb19SBen Gras static int getent(char **, size_t *, const char * const *, int,
1012fe8fb19SBen Gras const char *, int, char *);
1022fe8fb19SBen Gras static int nfcmp(char *, char *);
1032fe8fb19SBen Gras
1042fe8fb19SBen Gras /*
1052fe8fb19SBen Gras * Cgetset() allows the addition of a user specified buffer to be added
1062fe8fb19SBen Gras * to the database array, in effect "pushing" the buffer on top of the
1072fe8fb19SBen Gras * virtual database. 0 is returned on success, -1 on failure.
1082fe8fb19SBen Gras */
1092fe8fb19SBen Gras int
cgetset(const char * ent)1102fe8fb19SBen Gras cgetset(const char *ent)
1112fe8fb19SBen Gras {
1122fe8fb19SBen Gras const char *source, *check;
1132fe8fb19SBen Gras char *dest;
1142fe8fb19SBen Gras
1152fe8fb19SBen Gras if (ent == NULL) {
1162fe8fb19SBen Gras if (toprec != NULL)
1172fe8fb19SBen Gras free(toprec);
1182fe8fb19SBen Gras toprec = NULL;
1192fe8fb19SBen Gras topreclen = 0;
1202fe8fb19SBen Gras return 0;
1212fe8fb19SBen Gras }
1222fe8fb19SBen Gras topreclen = strlen(ent);
1232fe8fb19SBen Gras if ((toprec = malloc(topreclen + 1)) == NULL) {
1242fe8fb19SBen Gras errno = ENOMEM;
1252fe8fb19SBen Gras return -1;
1262fe8fb19SBen Gras }
1272fe8fb19SBen Gras gottoprec = 0;
1282fe8fb19SBen Gras
1292fe8fb19SBen Gras source = ent;
1302fe8fb19SBen Gras dest = toprec;
1312fe8fb19SBen Gras while (*source != '\0') { /* Strip whitespace */
1322fe8fb19SBen Gras *dest++ = *source++; /* Do not check first field */
1332fe8fb19SBen Gras while (*source == ':') {
1342fe8fb19SBen Gras check = source + 1;
1352fe8fb19SBen Gras while (*check && (isspace((unsigned char)*check) ||
1362fe8fb19SBen Gras (*check=='\\' && isspace((unsigned char)check[1]))))
1372fe8fb19SBen Gras ++check;
1382fe8fb19SBen Gras if (*check == ':')
1392fe8fb19SBen Gras source = check;
1402fe8fb19SBen Gras else
1412fe8fb19SBen Gras break;
1422fe8fb19SBen Gras
1432fe8fb19SBen Gras }
1442fe8fb19SBen Gras }
1452fe8fb19SBen Gras *dest = 0;
1462fe8fb19SBen Gras
1472fe8fb19SBen Gras return 0;
1482fe8fb19SBen Gras }
1492fe8fb19SBen Gras
1502fe8fb19SBen Gras /*
1512fe8fb19SBen Gras * Cgetcap searches the capability record buf for the capability cap with
1522fe8fb19SBen Gras * type `type'. A pointer to the value of cap is returned on success, NULL
1532fe8fb19SBen Gras * if the requested capability couldn't be found.
1542fe8fb19SBen Gras *
1552fe8fb19SBen Gras * Specifying a type of ':' means that nothing should follow cap (:cap:).
1562fe8fb19SBen Gras * In this case a pointer to the terminating ':' or NUL will be returned if
1572fe8fb19SBen Gras * cap is found.
1582fe8fb19SBen Gras *
1592fe8fb19SBen Gras * If (cap, '@') or (cap, terminator, '@') is found before (cap, terminator)
1602fe8fb19SBen Gras * return NULL.
1612fe8fb19SBen Gras */
1622fe8fb19SBen Gras char *
cgetcap(char * buf,const char * cap,int type)163f14fb602SLionel Sambuc cgetcap(char *buf, const char *cap, int type)
1642fe8fb19SBen Gras {
1652fe8fb19SBen Gras char *bp;
1662fe8fb19SBen Gras const char *cp;
1672fe8fb19SBen Gras
1682fe8fb19SBen Gras _DIAGASSERT(buf != NULL);
1692fe8fb19SBen Gras _DIAGASSERT(cap != NULL);
1702fe8fb19SBen Gras
1712fe8fb19SBen Gras bp = buf;
1722fe8fb19SBen Gras for (;;) {
1732fe8fb19SBen Gras /*
1742fe8fb19SBen Gras * Skip past the current capability field - it's either the
1752fe8fb19SBen Gras * name field if this is the first time through the loop, or
1762fe8fb19SBen Gras * the remainder of a field whose name failed to match cap.
1772fe8fb19SBen Gras */
1782fe8fb19SBen Gras for (;;)
1792fe8fb19SBen Gras if (*bp == '\0')
1802fe8fb19SBen Gras return NULL;
1812fe8fb19SBen Gras else if (*bp++ == ':')
1822fe8fb19SBen Gras break;
1832fe8fb19SBen Gras
1842fe8fb19SBen Gras /*
1852fe8fb19SBen Gras * Try to match (cap, type) in buf.
1862fe8fb19SBen Gras */
1872fe8fb19SBen Gras for (cp = cap; *cp == *bp && *bp != '\0'; cp++, bp++)
1882fe8fb19SBen Gras continue;
1892fe8fb19SBen Gras if (*cp != '\0')
1902fe8fb19SBen Gras continue;
1912fe8fb19SBen Gras if (*bp == '@')
1922fe8fb19SBen Gras return NULL;
1932fe8fb19SBen Gras if (type == ':') {
1942fe8fb19SBen Gras if (*bp != '\0' && *bp != ':')
1952fe8fb19SBen Gras continue;
1962fe8fb19SBen Gras return bp;
1972fe8fb19SBen Gras }
1982fe8fb19SBen Gras if (*bp != type)
1992fe8fb19SBen Gras continue;
2002fe8fb19SBen Gras bp++;
2012fe8fb19SBen Gras return *bp == '@' ? NULL : bp;
2022fe8fb19SBen Gras }
2032fe8fb19SBen Gras /* NOTREACHED */
2042fe8fb19SBen Gras }
2052fe8fb19SBen Gras
2062fe8fb19SBen Gras /*
2072fe8fb19SBen Gras * Cgetent extracts the capability record name from the NULL terminated file
2082fe8fb19SBen Gras * array db_array and returns a pointer to a malloc'd copy of it in buf.
2092fe8fb19SBen Gras * Buf must be retained through all subsequent calls to cgetcap, cgetnum,
2102fe8fb19SBen Gras * cgetflag, and cgetstr, but may then be free'd. 0 is returned on success,
2112fe8fb19SBen Gras * -1 if the requested record couldn't be found, -2 if a system error was
2122fe8fb19SBen Gras * encountered (couldn't open/read a file, etc.), and -3 if a potential
2132fe8fb19SBen Gras * reference loop is detected.
2142fe8fb19SBen Gras */
2152fe8fb19SBen Gras /* coverity[+alloc : arg-*0] */
2162fe8fb19SBen Gras int
cgetent(char ** buf,const char * const * db_array,const char * name)2172fe8fb19SBen Gras cgetent(char **buf, const char * const *db_array, const char *name)
2182fe8fb19SBen Gras {
2192fe8fb19SBen Gras size_t dummy;
2202fe8fb19SBen Gras
2212fe8fb19SBen Gras _DIAGASSERT(buf != NULL);
2222fe8fb19SBen Gras _DIAGASSERT(db_array != NULL);
2232fe8fb19SBen Gras _DIAGASSERT(name != NULL);
2242fe8fb19SBen Gras
2252fe8fb19SBen Gras return getent(buf, &dummy, db_array, -1, name, 0, NULL);
2262fe8fb19SBen Gras }
2272fe8fb19SBen Gras
2282fe8fb19SBen Gras void
csetexpandtc(int etc)2292fe8fb19SBen Gras csetexpandtc(int etc)
2302fe8fb19SBen Gras {
2312fe8fb19SBen Gras expandtc = etc;
2322fe8fb19SBen Gras }
2332fe8fb19SBen Gras
2342fe8fb19SBen Gras /*
2352fe8fb19SBen Gras * Getent implements the functions of cgetent. If fd is non-negative,
2362fe8fb19SBen Gras * *db_array has already been opened and fd is the open file descriptor. We
2372fe8fb19SBen Gras * do this to save time and avoid using up file descriptors for tc=
2382fe8fb19SBen Gras * recursions.
2392fe8fb19SBen Gras *
2402fe8fb19SBen Gras * Getent returns the same success/failure codes as cgetent. On success, a
2412fe8fb19SBen Gras * pointer to a malloc'ed capability record with all tc= capabilities fully
2422fe8fb19SBen Gras * expanded and its length (not including trailing ASCII NUL) are left in
2432fe8fb19SBen Gras * *cap and *len.
2442fe8fb19SBen Gras *
2452fe8fb19SBen Gras * Basic algorithm:
2462fe8fb19SBen Gras * + Allocate memory incrementally as needed in chunks of size BFRAG
2472fe8fb19SBen Gras * for capability buffer.
2482fe8fb19SBen Gras * + Recurse for each tc=name and interpolate result. Stop when all
2492fe8fb19SBen Gras * names interpolated, a name can't be found, or depth exceeds
2502fe8fb19SBen Gras * MAX_RECURSION.
2512fe8fb19SBen Gras */
2522fe8fb19SBen Gras /* coverity[+alloc : arg-*0] */
2532fe8fb19SBen Gras static int
getent(char ** cap,size_t * len,const char * const * db_array,int fd,const char * name,int depth,char * nfield)2542fe8fb19SBen Gras getent(char **cap, size_t *len, const char * const *db_array, int fd,
2552fe8fb19SBen Gras const char *name, int depth, char *nfield)
2562fe8fb19SBen Gras {
2572fe8fb19SBen Gras char *record, *newrecord;
2582fe8fb19SBen Gras char *r_end, *rp; /* pacify gcc */
2592fe8fb19SBen Gras const char * const *db_p;
2602fe8fb19SBen Gras int myfd, eof, foundit;
2612fe8fb19SBen Gras int tc_not_resolved;
2622fe8fb19SBen Gras
2632fe8fb19SBen Gras _DIAGASSERT(cap != NULL);
2642fe8fb19SBen Gras _DIAGASSERT(len != NULL);
2652fe8fb19SBen Gras _DIAGASSERT(db_array != NULL);
2662fe8fb19SBen Gras /* fd may be -1 */
2672fe8fb19SBen Gras _DIAGASSERT(name != NULL);
2682fe8fb19SBen Gras /* nfield may be NULL */
2692fe8fb19SBen Gras
2702fe8fb19SBen Gras myfd = 0;
2712fe8fb19SBen Gras rp = NULL;
2722fe8fb19SBen Gras
2732fe8fb19SBen Gras /*
2742fe8fb19SBen Gras * Return with ``loop detected'' error if we've recursed more than
2752fe8fb19SBen Gras * MAX_RECURSION times.
2762fe8fb19SBen Gras */
2772fe8fb19SBen Gras if (depth > MAX_RECURSION)
2782fe8fb19SBen Gras return -3;
2792fe8fb19SBen Gras
2802fe8fb19SBen Gras /*
2812fe8fb19SBen Gras * Check if we have a top record from cgetset().
2822fe8fb19SBen Gras */
2832fe8fb19SBen Gras if (depth == 0 && toprec != NULL && cgetmatch(toprec, name) == 0) {
2842fe8fb19SBen Gras if ((record = malloc(topreclen + BFRAG)) == NULL) {
2852fe8fb19SBen Gras errno = ENOMEM;
2862fe8fb19SBen Gras return -2;
2872fe8fb19SBen Gras }
2882fe8fb19SBen Gras (void)strcpy(record, toprec); /* XXX: strcpy is safe */
2892fe8fb19SBen Gras db_p = db_array;
2902fe8fb19SBen Gras rp = record + topreclen + 1;
2912fe8fb19SBen Gras r_end = rp + BFRAG;
2922fe8fb19SBen Gras goto tc_exp;
2932fe8fb19SBen Gras }
2942fe8fb19SBen Gras /*
2952fe8fb19SBen Gras * Allocate first chunk of memory.
2962fe8fb19SBen Gras */
2972fe8fb19SBen Gras if ((record = malloc(BFRAG)) == NULL) {
2982fe8fb19SBen Gras errno = ENOMEM;
2992fe8fb19SBen Gras return -2;
3002fe8fb19SBen Gras }
3012fe8fb19SBen Gras r_end = record + BFRAG;
3022fe8fb19SBen Gras foundit = 0;
3032fe8fb19SBen Gras /*
3042fe8fb19SBen Gras * Loop through database array until finding the record.
3052fe8fb19SBen Gras */
3062fe8fb19SBen Gras
3072fe8fb19SBen Gras for (db_p = db_array; *db_p != NULL; db_p++) {
3082fe8fb19SBen Gras eof = 0;
3092fe8fb19SBen Gras
3102fe8fb19SBen Gras /*
3112fe8fb19SBen Gras * Open database if not already open.
3122fe8fb19SBen Gras */
3132fe8fb19SBen Gras
3142fe8fb19SBen Gras if (fd >= 0) {
3152fe8fb19SBen Gras (void)lseek(fd, (off_t)0, SEEK_SET);
3162fe8fb19SBen Gras } else {
3172fe8fb19SBen Gras #ifndef SMALL
318*0a6a1f1dSLionel Sambuc DB *capdbp;
319*0a6a1f1dSLionel Sambuc char pbuf[MAXPATHLEN];
320*0a6a1f1dSLionel Sambuc char *cbuf;
321*0a6a1f1dSLionel Sambuc int retval;
322*0a6a1f1dSLionel Sambuc size_t clen;
323*0a6a1f1dSLionel Sambuc
3242fe8fb19SBen Gras (void)snprintf(pbuf, sizeof(pbuf), "%s.db", *db_p);
325*0a6a1f1dSLionel Sambuc if ((capdbp = dbopen(pbuf, O_RDONLY | O_CLOEXEC, 0,
326*0a6a1f1dSLionel Sambuc DB_HASH, 0)) != NULL) {
3272fe8fb19SBen Gras free(record);
3282fe8fb19SBen Gras retval = cdbget(capdbp, &record, name);
3292fe8fb19SBen Gras if (retval < 0) {
3302fe8fb19SBen Gras /* no record available */
3312fe8fb19SBen Gras (void)capdbp->close(capdbp);
3322fe8fb19SBen Gras return retval;
3332fe8fb19SBen Gras }
3342fe8fb19SBen Gras /* save the data; close frees it */
3352fe8fb19SBen Gras clen = strlen(record);
3362fe8fb19SBen Gras if ((cbuf = malloc(clen + 1)) == NULL) {
3372fe8fb19SBen Gras (void)capdbp->close(capdbp);
3382fe8fb19SBen Gras errno = ENOMEM;
3392fe8fb19SBen Gras return -2;
3402fe8fb19SBen Gras }
3412fe8fb19SBen Gras memmove(cbuf, record, clen + 1);
3422fe8fb19SBen Gras if (capdbp->close(capdbp) < 0) {
3432fe8fb19SBen Gras int serrno = errno;
3442fe8fb19SBen Gras
3452fe8fb19SBen Gras free(cbuf);
3462fe8fb19SBen Gras errno = serrno;
3472fe8fb19SBen Gras return -2;
3482fe8fb19SBen Gras }
3492fe8fb19SBen Gras *len = clen;
3502fe8fb19SBen Gras *cap = cbuf;
3512fe8fb19SBen Gras return retval;
3522fe8fb19SBen Gras } else
3532fe8fb19SBen Gras #endif
3542fe8fb19SBen Gras {
355*0a6a1f1dSLionel Sambuc fd = open(*db_p, O_RDONLY | O_CLOEXEC, 0);
3562fe8fb19SBen Gras if (fd < 0) {
3572fe8fb19SBen Gras /* No error on unfound file. */
3582fe8fb19SBen Gras continue;
3592fe8fb19SBen Gras }
3602fe8fb19SBen Gras myfd = 1;
3612fe8fb19SBen Gras }
3622fe8fb19SBen Gras }
3632fe8fb19SBen Gras /*
3642fe8fb19SBen Gras * Find the requested capability record ...
3652fe8fb19SBen Gras */
3662fe8fb19SBen Gras {
3672fe8fb19SBen Gras char buf[BUFSIZ];
3682fe8fb19SBen Gras char *b_end, *bp, *cp;
3692fe8fb19SBen Gras int c, slash;
3702fe8fb19SBen Gras
3712fe8fb19SBen Gras /*
3722fe8fb19SBen Gras * Loop invariants:
3732fe8fb19SBen Gras * There is always room for one more character in record.
3742fe8fb19SBen Gras * R_end always points just past end of record.
3752fe8fb19SBen Gras * Rp always points just past last character in record.
3762fe8fb19SBen Gras * B_end always points just past last character in buf.
3772fe8fb19SBen Gras * Bp always points at next character in buf.
3782fe8fb19SBen Gras * Cp remembers where the last colon was.
3792fe8fb19SBen Gras */
3802fe8fb19SBen Gras b_end = buf;
3812fe8fb19SBen Gras bp = buf;
3822fe8fb19SBen Gras cp = NULL;
3832fe8fb19SBen Gras slash = 0;
3842fe8fb19SBen Gras for (;;) {
3852fe8fb19SBen Gras /*
3862fe8fb19SBen Gras * Read in a line implementing (\, newline)
3872fe8fb19SBen Gras * line continuation.
3882fe8fb19SBen Gras */
3892fe8fb19SBen Gras rp = record;
3902fe8fb19SBen Gras for (;;) {
3912fe8fb19SBen Gras if (bp >= b_end) {
392f14fb602SLionel Sambuc ssize_t n;
3932fe8fb19SBen Gras
3942fe8fb19SBen Gras n = read(fd, buf, sizeof(buf));
3952fe8fb19SBen Gras if (n <= 0) {
3962fe8fb19SBen Gras if (myfd)
3972fe8fb19SBen Gras (void)close(fd);
3982fe8fb19SBen Gras if (n < 0) {
3992fe8fb19SBen Gras int serrno = errno;
4002fe8fb19SBen Gras
4012fe8fb19SBen Gras free(record);
4022fe8fb19SBen Gras errno = serrno;
4032fe8fb19SBen Gras return -2;
4042fe8fb19SBen Gras } else {
4052fe8fb19SBen Gras fd = -1;
4062fe8fb19SBen Gras eof = 1;
4072fe8fb19SBen Gras break;
4082fe8fb19SBen Gras }
4092fe8fb19SBen Gras }
4102fe8fb19SBen Gras b_end = buf+n;
4112fe8fb19SBen Gras bp = buf;
4122fe8fb19SBen Gras }
4132fe8fb19SBen Gras
4142fe8fb19SBen Gras c = *bp++;
4152fe8fb19SBen Gras if (c == '\n') {
4162fe8fb19SBen Gras if (slash) {
4172fe8fb19SBen Gras slash = 0;
4182fe8fb19SBen Gras rp--;
4192fe8fb19SBen Gras continue;
4202fe8fb19SBen Gras } else
4212fe8fb19SBen Gras break;
4222fe8fb19SBen Gras }
4232fe8fb19SBen Gras if (slash) {
4242fe8fb19SBen Gras slash = 0;
4252fe8fb19SBen Gras cp = 0;
4262fe8fb19SBen Gras }
4272fe8fb19SBen Gras if (c == ':') {
4282fe8fb19SBen Gras /*
4292fe8fb19SBen Gras * If the field was `empty' (i.e.
4302fe8fb19SBen Gras * contained only white space), back up
4312fe8fb19SBen Gras * to the colon (eliminating the
4322fe8fb19SBen Gras * field).
4332fe8fb19SBen Gras */
4342fe8fb19SBen Gras if (cp != NULL)
4352fe8fb19SBen Gras rp = cp;
4362fe8fb19SBen Gras else
4372fe8fb19SBen Gras cp = rp;
4382fe8fb19SBen Gras } else if (c == '\\') {
4392fe8fb19SBen Gras slash = 1;
4402fe8fb19SBen Gras } else if (c != ' ' && c != '\t') {
4412fe8fb19SBen Gras /*
4422fe8fb19SBen Gras * Forget where the colon was, as this
4432fe8fb19SBen Gras * is not an empty field.
4442fe8fb19SBen Gras */
4452fe8fb19SBen Gras cp = 0;
4462fe8fb19SBen Gras }
4472fe8fb19SBen Gras *rp++ = c;
4482fe8fb19SBen Gras
4492fe8fb19SBen Gras /*
4502fe8fb19SBen Gras * Enforce loop invariant: if no room
4512fe8fb19SBen Gras * left in record buffer, try to get
4522fe8fb19SBen Gras * some more.
4532fe8fb19SBen Gras */
4542fe8fb19SBen Gras if (rp >= r_end) {
455f14fb602SLionel Sambuc ptrdiff_t pos;
4562fe8fb19SBen Gras size_t newsize;
4572fe8fb19SBen Gras
4582fe8fb19SBen Gras pos = rp - record;
4592fe8fb19SBen Gras newsize = r_end - record + BFRAG;
4602fe8fb19SBen Gras newrecord = realloc(record, newsize);
4612fe8fb19SBen Gras if (newrecord == NULL) {
4622fe8fb19SBen Gras free(record);
4632fe8fb19SBen Gras if (myfd)
4642fe8fb19SBen Gras (void)close(fd);
4652fe8fb19SBen Gras errno = ENOMEM;
4662fe8fb19SBen Gras return -2;
4672fe8fb19SBen Gras }
4682fe8fb19SBen Gras record = newrecord;
4692fe8fb19SBen Gras r_end = record + newsize;
4702fe8fb19SBen Gras rp = record + pos;
4712fe8fb19SBen Gras }
4722fe8fb19SBen Gras }
4732fe8fb19SBen Gras /* Eliminate any white space after the last colon. */
4742fe8fb19SBen Gras if (cp)
4752fe8fb19SBen Gras rp = cp + 1;
4762fe8fb19SBen Gras /* Loop invariant lets us do this. */
4772fe8fb19SBen Gras *rp++ = '\0';
4782fe8fb19SBen Gras
4792fe8fb19SBen Gras /*
4802fe8fb19SBen Gras * If encountered eof check next file.
4812fe8fb19SBen Gras */
4822fe8fb19SBen Gras if (eof)
4832fe8fb19SBen Gras break;
4842fe8fb19SBen Gras
4852fe8fb19SBen Gras /*
4862fe8fb19SBen Gras * Toss blank lines and comments.
4872fe8fb19SBen Gras */
4882fe8fb19SBen Gras if (*record == '\0' || *record == '#')
4892fe8fb19SBen Gras continue;
4902fe8fb19SBen Gras
4912fe8fb19SBen Gras /*
4922fe8fb19SBen Gras * See if this is the record we want ...
4932fe8fb19SBen Gras */
4942fe8fb19SBen Gras if (cgetmatch(record, name) == 0)
4952fe8fb19SBen Gras if (nfield == NULL || !nfcmp(nfield, record)) {
4962fe8fb19SBen Gras foundit = 1;
4972fe8fb19SBen Gras break; /* found it! */
4982fe8fb19SBen Gras }
4992fe8fb19SBen Gras }
5002fe8fb19SBen Gras }
5012fe8fb19SBen Gras if (foundit)
5022fe8fb19SBen Gras break;
5032fe8fb19SBen Gras }
5042fe8fb19SBen Gras
5052fe8fb19SBen Gras if (!foundit)
5062fe8fb19SBen Gras return -1;
5072fe8fb19SBen Gras
5082fe8fb19SBen Gras /*
5092fe8fb19SBen Gras * Got the capability record, but now we have to expand all tc=name
5102fe8fb19SBen Gras * references in it ...
5112fe8fb19SBen Gras */
5122fe8fb19SBen Gras tc_exp:
5132fe8fb19SBen Gras tc_not_resolved = 0;
5142fe8fb19SBen Gras if (expandtc) {
5152fe8fb19SBen Gras char *newicap, *s;
5162fe8fb19SBen Gras size_t ilen, newilen;
517f14fb602SLionel Sambuc int iret;
518f14fb602SLionel Sambuc ptrdiff_t diff, tclen;
5192fe8fb19SBen Gras char *icap, *scan, *tc, *tcstart, *tcend;
5202fe8fb19SBen Gras
5212fe8fb19SBen Gras /*
5222fe8fb19SBen Gras * Loop invariants:
5232fe8fb19SBen Gras * There is room for one more character in record.
5242fe8fb19SBen Gras * R_end points just past end of record.
5252fe8fb19SBen Gras * Rp points just past last character in record.
5262fe8fb19SBen Gras * Scan points at remainder of record that needs to be
5272fe8fb19SBen Gras * scanned for tc=name constructs.
5282fe8fb19SBen Gras */
5292fe8fb19SBen Gras scan = record;
5302fe8fb19SBen Gras for (;;) {
5312fe8fb19SBen Gras if ((tc = cgetcap(scan, "tc", '=')) == NULL)
5322fe8fb19SBen Gras break;
5332fe8fb19SBen Gras
5342fe8fb19SBen Gras /*
5352fe8fb19SBen Gras * Find end of tc=name and stomp on the trailing `:'
5362fe8fb19SBen Gras * (if present) so we can use it to call ourselves.
5372fe8fb19SBen Gras */
5382fe8fb19SBen Gras s = tc;
5392fe8fb19SBen Gras for (;;)
5402fe8fb19SBen Gras if (*s == '\0')
5412fe8fb19SBen Gras break;
5422fe8fb19SBen Gras else
5432fe8fb19SBen Gras if (*s++ == ':') {
5442fe8fb19SBen Gras *(s - 1) = '\0';
5452fe8fb19SBen Gras break;
5462fe8fb19SBen Gras }
5472fe8fb19SBen Gras tcstart = tc - 3;
5482fe8fb19SBen Gras tclen = s - tcstart;
5492fe8fb19SBen Gras tcend = s;
5502fe8fb19SBen Gras
5512fe8fb19SBen Gras iret = getent(&icap, &ilen, db_p, fd, tc, depth+1,
5522fe8fb19SBen Gras NULL);
5532fe8fb19SBen Gras newicap = icap; /* Put into a register. */
5542fe8fb19SBen Gras newilen = ilen;
5552fe8fb19SBen Gras if (iret != 0) {
5562fe8fb19SBen Gras /* an error */
5572fe8fb19SBen Gras if (iret < -1) {
5582fe8fb19SBen Gras if (myfd)
5592fe8fb19SBen Gras (void)close(fd);
5602fe8fb19SBen Gras free(record);
5612fe8fb19SBen Gras return iret;
5622fe8fb19SBen Gras }
5632fe8fb19SBen Gras if (iret == 1)
5642fe8fb19SBen Gras tc_not_resolved = 1;
5652fe8fb19SBen Gras /* couldn't resolve tc */
5662fe8fb19SBen Gras if (iret == -1) {
5672fe8fb19SBen Gras *(s - 1) = ':';
5682fe8fb19SBen Gras scan = s - 1;
5692fe8fb19SBen Gras tc_not_resolved = 1;
5702fe8fb19SBen Gras continue;
5712fe8fb19SBen Gras
5722fe8fb19SBen Gras }
5732fe8fb19SBen Gras }
5742fe8fb19SBen Gras /* not interested in name field of tc'ed record */
5752fe8fb19SBen Gras s = newicap;
5762fe8fb19SBen Gras for (;;)
5772fe8fb19SBen Gras if (*s == '\0')
5782fe8fb19SBen Gras break;
5792fe8fb19SBen Gras else if (*s++ == ':')
5802fe8fb19SBen Gras break;
5812fe8fb19SBen Gras newilen -= s - newicap;
5822fe8fb19SBen Gras newicap = s;
5832fe8fb19SBen Gras
5842fe8fb19SBen Gras /* make sure interpolated record is `:'-terminated */
5852fe8fb19SBen Gras s += newilen;
5862fe8fb19SBen Gras if (*(s - 1) != ':') {
5872fe8fb19SBen Gras *s = ':'; /* overwrite NUL with : */
5882fe8fb19SBen Gras newilen++;
5892fe8fb19SBen Gras }
5902fe8fb19SBen Gras
5912fe8fb19SBen Gras /*
5922fe8fb19SBen Gras * Make sure there's enough room to insert the
5932fe8fb19SBen Gras * new record.
5942fe8fb19SBen Gras */
5952fe8fb19SBen Gras diff = newilen - tclen;
5962fe8fb19SBen Gras if (diff >= r_end - rp) {
597f14fb602SLionel Sambuc ptrdiff_t pos, tcpos, tcposend;
5982fe8fb19SBen Gras size_t newsize;
5992fe8fb19SBen Gras
6002fe8fb19SBen Gras pos = rp - record;
6012fe8fb19SBen Gras newsize = r_end - record + diff + BFRAG;
6022fe8fb19SBen Gras tcpos = tcstart - record;
6032fe8fb19SBen Gras tcposend = tcend - record;
6042fe8fb19SBen Gras newrecord = realloc(record, newsize);
6052fe8fb19SBen Gras if (newrecord == NULL) {
6062fe8fb19SBen Gras free(record);
6072fe8fb19SBen Gras if (myfd)
6082fe8fb19SBen Gras (void)close(fd);
6092fe8fb19SBen Gras free(icap);
6102fe8fb19SBen Gras errno = ENOMEM;
6112fe8fb19SBen Gras return -2;
6122fe8fb19SBen Gras }
6132fe8fb19SBen Gras record = newrecord;
6142fe8fb19SBen Gras r_end = record + newsize;
6152fe8fb19SBen Gras rp = record + pos;
6162fe8fb19SBen Gras tcstart = record + tcpos;
6172fe8fb19SBen Gras tcend = record + tcposend;
6182fe8fb19SBen Gras }
6192fe8fb19SBen Gras
6202fe8fb19SBen Gras /*
6212fe8fb19SBen Gras * Insert tc'ed record into our record.
6222fe8fb19SBen Gras */
6232fe8fb19SBen Gras s = tcstart + newilen;
6242fe8fb19SBen Gras memmove(s, tcend, (size_t)(rp - tcend));
6252fe8fb19SBen Gras memmove(tcstart, newicap, newilen);
6262fe8fb19SBen Gras rp += diff;
6272fe8fb19SBen Gras free(icap);
6282fe8fb19SBen Gras
6292fe8fb19SBen Gras /*
6302fe8fb19SBen Gras * Start scan on `:' so next cgetcap works properly
6312fe8fb19SBen Gras * (cgetcap always skips first field).
6322fe8fb19SBen Gras */
6332fe8fb19SBen Gras scan = s - 1;
6342fe8fb19SBen Gras }
6352fe8fb19SBen Gras
6362fe8fb19SBen Gras }
6372fe8fb19SBen Gras /*
6382fe8fb19SBen Gras * Close file (if we opened it), give back any extra memory, and
6392fe8fb19SBen Gras * return capability, length and success.
6402fe8fb19SBen Gras */
6412fe8fb19SBen Gras if (myfd)
6422fe8fb19SBen Gras (void)close(fd);
6432fe8fb19SBen Gras *len = rp - record - 1; /* don't count NUL */
6442fe8fb19SBen Gras if (r_end > rp) {
6452fe8fb19SBen Gras if ((newrecord =
6462fe8fb19SBen Gras realloc(record, (size_t)(rp - record))) == NULL) {
6472fe8fb19SBen Gras free(record);
6482fe8fb19SBen Gras errno = ENOMEM;
6492fe8fb19SBen Gras return -2;
6502fe8fb19SBen Gras }
6512fe8fb19SBen Gras record = newrecord;
6522fe8fb19SBen Gras }
6532fe8fb19SBen Gras
6542fe8fb19SBen Gras *cap = record;
6552fe8fb19SBen Gras if (tc_not_resolved)
6562fe8fb19SBen Gras return 1;
6572fe8fb19SBen Gras return 0;
6582fe8fb19SBen Gras }
6592fe8fb19SBen Gras
6602fe8fb19SBen Gras #ifndef SMALL
6612fe8fb19SBen Gras static int
cdbget(DB * capdbp,char ** bp,const char * name)6622fe8fb19SBen Gras cdbget(DB *capdbp, char **bp, const char *name)
6632fe8fb19SBen Gras {
6642fe8fb19SBen Gras DBT key;
6652fe8fb19SBen Gras DBT data;
6662fe8fb19SBen Gras
6672fe8fb19SBen Gras _DIAGASSERT(capdbp != NULL);
6682fe8fb19SBen Gras _DIAGASSERT(bp != NULL);
6692fe8fb19SBen Gras _DIAGASSERT(name != NULL);
6702fe8fb19SBen Gras
6712fe8fb19SBen Gras key.data = __UNCONST(name);
6722fe8fb19SBen Gras key.size = strlen(name);
6732fe8fb19SBen Gras
6742fe8fb19SBen Gras for (;;) {
6752fe8fb19SBen Gras /* Get the reference. */
6762fe8fb19SBen Gras switch(capdbp->get(capdbp, &key, &data, 0)) {
6772fe8fb19SBen Gras case -1:
6782fe8fb19SBen Gras return -2;
6792fe8fb19SBen Gras case 1:
6802fe8fb19SBen Gras return -1;
6812fe8fb19SBen Gras }
6822fe8fb19SBen Gras
6832fe8fb19SBen Gras /* If not an index to another record, leave. */
6842fe8fb19SBen Gras if (((char *)data.data)[0] != SHADOW)
6852fe8fb19SBen Gras break;
6862fe8fb19SBen Gras
6872fe8fb19SBen Gras key.data = (char *)data.data + 1;
6882fe8fb19SBen Gras key.size = data.size - 1;
6892fe8fb19SBen Gras }
6902fe8fb19SBen Gras
6912fe8fb19SBen Gras *bp = (char *)data.data + 1;
6922fe8fb19SBen Gras return ((char *)(data.data))[0] == TCERR ? 1 : 0;
6932fe8fb19SBen Gras }
6942fe8fb19SBen Gras #endif
6952fe8fb19SBen Gras
6962fe8fb19SBen Gras /*
6972fe8fb19SBen Gras * Cgetmatch will return 0 if name is one of the names of the capability
6982fe8fb19SBen Gras * record buf, -1 if not.
6992fe8fb19SBen Gras */
7002fe8fb19SBen Gras int
cgetmatch(const char * buf,const char * name)7012fe8fb19SBen Gras cgetmatch(const char *buf, const char *name)
7022fe8fb19SBen Gras {
7032fe8fb19SBen Gras const char *np, *bp;
7042fe8fb19SBen Gras
7052fe8fb19SBen Gras _DIAGASSERT(buf != NULL);
7062fe8fb19SBen Gras _DIAGASSERT(name != NULL);
7072fe8fb19SBen Gras
7082fe8fb19SBen Gras /*
7092fe8fb19SBen Gras * Start search at beginning of record.
7102fe8fb19SBen Gras */
7112fe8fb19SBen Gras bp = buf;
7122fe8fb19SBen Gras for (;;) {
7132fe8fb19SBen Gras /*
7142fe8fb19SBen Gras * Try to match a record name.
7152fe8fb19SBen Gras */
7162fe8fb19SBen Gras np = name;
7172fe8fb19SBen Gras for (;;)
7182fe8fb19SBen Gras if (*np == '\0') {
7192fe8fb19SBen Gras if (*bp == '|' || *bp == ':' || *bp == '\0')
7202fe8fb19SBen Gras return 0;
7212fe8fb19SBen Gras else
7222fe8fb19SBen Gras break;
7232fe8fb19SBen Gras } else if (*bp++ != *np++)
7242fe8fb19SBen Gras break;
7252fe8fb19SBen Gras
7262fe8fb19SBen Gras /*
7272fe8fb19SBen Gras * Match failed, skip to next name in record.
7282fe8fb19SBen Gras */
7292fe8fb19SBen Gras if (bp > buf)
7302fe8fb19SBen Gras bp--; /* a '|' or ':' may have stopped the match */
7312fe8fb19SBen Gras else
7322fe8fb19SBen Gras return -1;
7332fe8fb19SBen Gras for (;;)
7342fe8fb19SBen Gras if (*bp == '\0' || *bp == ':')
7352fe8fb19SBen Gras return -1; /* match failed totally */
7362fe8fb19SBen Gras else if (*bp++ == '|')
7372fe8fb19SBen Gras break; /* found next name */
7382fe8fb19SBen Gras }
7392fe8fb19SBen Gras }
7402fe8fb19SBen Gras
7412fe8fb19SBen Gras int
cgetfirst(char ** buf,const char * const * db_array)7422fe8fb19SBen Gras cgetfirst(char **buf, const char * const *db_array)
7432fe8fb19SBen Gras {
7442fe8fb19SBen Gras
7452fe8fb19SBen Gras _DIAGASSERT(buf != NULL);
7462fe8fb19SBen Gras _DIAGASSERT(db_array != NULL);
7472fe8fb19SBen Gras
7482fe8fb19SBen Gras (void)cgetclose();
7492fe8fb19SBen Gras return cgetnext(buf, db_array);
7502fe8fb19SBen Gras }
7512fe8fb19SBen Gras
7522fe8fb19SBen Gras static FILE *pfp;
7532fe8fb19SBen Gras static int slash;
7542fe8fb19SBen Gras static const char * const *dbp;
7552fe8fb19SBen Gras
7562fe8fb19SBen Gras int
cgetclose(void)7572fe8fb19SBen Gras cgetclose(void)
7582fe8fb19SBen Gras {
7592fe8fb19SBen Gras if (pfp != NULL) {
7602fe8fb19SBen Gras (void)fclose(pfp);
7612fe8fb19SBen Gras pfp = NULL;
7622fe8fb19SBen Gras }
7632fe8fb19SBen Gras dbp = NULL;
7642fe8fb19SBen Gras gottoprec = 0;
7652fe8fb19SBen Gras slash = 0;
7662fe8fb19SBen Gras return 0;
7672fe8fb19SBen Gras }
7682fe8fb19SBen Gras
7692fe8fb19SBen Gras /*
7702fe8fb19SBen Gras * Cgetnext() gets either the first or next entry in the logical database
7712fe8fb19SBen Gras * specified by db_array. It returns 0 upon completion of the database, 1
7722fe8fb19SBen Gras * upon returning an entry with more remaining, and -1 if an error occurs.
7732fe8fb19SBen Gras */
7742fe8fb19SBen Gras /* coverity[+alloc : arg-*0] */
7752fe8fb19SBen Gras int
cgetnext(char ** bp,const char * const * db_array)7762fe8fb19SBen Gras cgetnext(char **bp, const char * const *db_array)
7772fe8fb19SBen Gras {
7782fe8fb19SBen Gras size_t len = 0;
7792fe8fb19SBen Gras int status, done;
7802fe8fb19SBen Gras char *cp, *line, *rp, *np, buf[BSIZE], nbuf[BSIZE];
7812fe8fb19SBen Gras size_t dummy;
7822fe8fb19SBen Gras
7832fe8fb19SBen Gras _DIAGASSERT(bp != NULL);
7842fe8fb19SBen Gras _DIAGASSERT(db_array != NULL);
7852fe8fb19SBen Gras
7862fe8fb19SBen Gras if (dbp == NULL)
7872fe8fb19SBen Gras dbp = db_array;
7882fe8fb19SBen Gras
789f14fb602SLionel Sambuc if (pfp == NULL && (pfp = fopen(*dbp, "re")) == NULL) {
7902fe8fb19SBen Gras (void)cgetclose();
7912fe8fb19SBen Gras return -1;
7922fe8fb19SBen Gras }
7932fe8fb19SBen Gras for (;;) {
7942fe8fb19SBen Gras if (toprec != NULL && !gottoprec) {
7952fe8fb19SBen Gras gottoprec = 1;
7962fe8fb19SBen Gras line = toprec;
7972fe8fb19SBen Gras } else {
7982fe8fb19SBen Gras line = fgetln(pfp, &len);
7992fe8fb19SBen Gras if (line == NULL) {
8002fe8fb19SBen Gras if (pfp == NULL)
8012fe8fb19SBen Gras return -1;
8022fe8fb19SBen Gras if (ferror(pfp)) {
8032fe8fb19SBen Gras (void)cgetclose();
8042fe8fb19SBen Gras return -1;
8052fe8fb19SBen Gras } else {
8062fe8fb19SBen Gras (void)fclose(pfp);
8072fe8fb19SBen Gras pfp = NULL;
8082fe8fb19SBen Gras if (*++dbp == NULL) {
8092fe8fb19SBen Gras (void)cgetclose();
8102fe8fb19SBen Gras return 0;
8112fe8fb19SBen Gras } else if ((pfp =
812f14fb602SLionel Sambuc fopen(*dbp, "re")) == NULL) {
8132fe8fb19SBen Gras (void)cgetclose();
8142fe8fb19SBen Gras return -1;
8152fe8fb19SBen Gras } else
8162fe8fb19SBen Gras continue;
8172fe8fb19SBen Gras }
8182fe8fb19SBen Gras } else
8192fe8fb19SBen Gras line[len - 1] = '\0';
8202fe8fb19SBen Gras if (len == 1) {
8212fe8fb19SBen Gras slash = 0;
8222fe8fb19SBen Gras continue;
8232fe8fb19SBen Gras }
8242fe8fb19SBen Gras if (isspace((unsigned char)*line) ||
8252fe8fb19SBen Gras *line == ':' || *line == '#' || slash) {
8262fe8fb19SBen Gras if (line[len - 2] == '\\')
8272fe8fb19SBen Gras slash = 1;
8282fe8fb19SBen Gras else
8292fe8fb19SBen Gras slash = 0;
8302fe8fb19SBen Gras continue;
8312fe8fb19SBen Gras }
8322fe8fb19SBen Gras if (line[len - 2] == '\\')
8332fe8fb19SBen Gras slash = 1;
8342fe8fb19SBen Gras else
8352fe8fb19SBen Gras slash = 0;
8362fe8fb19SBen Gras }
8372fe8fb19SBen Gras
8382fe8fb19SBen Gras
8392fe8fb19SBen Gras /*
8402fe8fb19SBen Gras * Line points to a name line.
8412fe8fb19SBen Gras */
8422fe8fb19SBen Gras if (len > sizeof(nbuf))
8432fe8fb19SBen Gras return -1;
8442fe8fb19SBen Gras done = 0;
8452fe8fb19SBen Gras np = nbuf;
8462fe8fb19SBen Gras for (;;) {
8472fe8fb19SBen Gras for (cp = line; *cp != '\0'; cp++) {
8482fe8fb19SBen Gras if (*cp == ':') {
8492fe8fb19SBen Gras *np++ = ':';
8502fe8fb19SBen Gras done = 1;
8512fe8fb19SBen Gras break;
8522fe8fb19SBen Gras }
8532fe8fb19SBen Gras if (*cp == '\\')
8542fe8fb19SBen Gras break;
8552fe8fb19SBen Gras *np++ = *cp;
8562fe8fb19SBen Gras }
8572fe8fb19SBen Gras if (done) {
8582fe8fb19SBen Gras *np = '\0';
8592fe8fb19SBen Gras break;
8602fe8fb19SBen Gras } else { /* name field extends beyond the line */
8612fe8fb19SBen Gras line = fgetln(pfp, &len);
8622fe8fb19SBen Gras if (line == NULL && pfp) {
8632fe8fb19SBen Gras if (ferror(pfp)) {
8642fe8fb19SBen Gras (void)cgetclose();
8652fe8fb19SBen Gras return -1;
8662fe8fb19SBen Gras }
8672fe8fb19SBen Gras (void)fclose(pfp);
8682fe8fb19SBen Gras pfp = NULL;
8692fe8fb19SBen Gras *np = '\0';
8702fe8fb19SBen Gras break;
8712fe8fb19SBen Gras } else
8722fe8fb19SBen Gras line[len - 1] = '\0';
8732fe8fb19SBen Gras }
8742fe8fb19SBen Gras }
8752fe8fb19SBen Gras if (len > sizeof(buf))
8762fe8fb19SBen Gras return -1;
8772fe8fb19SBen Gras rp = buf;
8782fe8fb19SBen Gras for (cp = nbuf; *cp != '\0'; cp++)
8792fe8fb19SBen Gras if (*cp == '|' || *cp == ':')
8802fe8fb19SBen Gras break;
8812fe8fb19SBen Gras else
8822fe8fb19SBen Gras *rp++ = *cp;
8832fe8fb19SBen Gras
8842fe8fb19SBen Gras *rp = '\0';
8852fe8fb19SBen Gras /*
8862fe8fb19SBen Gras * XXX
8872fe8fb19SBen Gras * Last argument of getent here should be nbuf if we want true
8882fe8fb19SBen Gras * sequential access in the case of duplicates.
8892fe8fb19SBen Gras * With NULL, getent will return the first entry found
8902fe8fb19SBen Gras * rather than the duplicate entry record. This is a
8912fe8fb19SBen Gras * matter of semantics that should be resolved.
8922fe8fb19SBen Gras */
8932fe8fb19SBen Gras status = getent(bp, &dummy, db_array, -1, buf, 0, NULL);
8942fe8fb19SBen Gras if (status == -2 || status == -3)
8952fe8fb19SBen Gras (void)cgetclose();
8962fe8fb19SBen Gras
8972fe8fb19SBen Gras return status + 1;
8982fe8fb19SBen Gras }
8992fe8fb19SBen Gras /* NOTREACHED */
9002fe8fb19SBen Gras }
9012fe8fb19SBen Gras
9022fe8fb19SBen Gras /*
9032fe8fb19SBen Gras * Cgetstr retrieves the value of the string capability cap from the
9042fe8fb19SBen Gras * capability record pointed to by buf. A pointer to a decoded, NUL
9052fe8fb19SBen Gras * terminated, malloc'd copy of the string is returned in the char *
9062fe8fb19SBen Gras * pointed to by str. The length of the string not including the trailing
9072fe8fb19SBen Gras * NUL is returned on success, -1 if the requested string capability
9082fe8fb19SBen Gras * couldn't be found, -2 if a system error was encountered (storage
9092fe8fb19SBen Gras * allocation failure).
9102fe8fb19SBen Gras */
9112fe8fb19SBen Gras int
cgetstr(char * buf,const char * cap,char ** str)9122fe8fb19SBen Gras cgetstr(char *buf, const char *cap, char **str)
9132fe8fb19SBen Gras {
9142fe8fb19SBen Gras u_int m_room;
9152fe8fb19SBen Gras const char *bp;
9162fe8fb19SBen Gras char *mp;
917f14fb602SLionel Sambuc ptrdiff_t len;
9182fe8fb19SBen Gras char *mem, *newmem;
9192fe8fb19SBen Gras
9202fe8fb19SBen Gras _DIAGASSERT(buf != NULL);
9212fe8fb19SBen Gras _DIAGASSERT(cap != NULL);
9222fe8fb19SBen Gras _DIAGASSERT(str != NULL);
9232fe8fb19SBen Gras
9242fe8fb19SBen Gras /*
9252fe8fb19SBen Gras * Find string capability cap
9262fe8fb19SBen Gras */
9272fe8fb19SBen Gras bp = cgetcap(buf, cap, '=');
9282fe8fb19SBen Gras if (bp == NULL)
9292fe8fb19SBen Gras return -1;
9302fe8fb19SBen Gras
9312fe8fb19SBen Gras /*
9322fe8fb19SBen Gras * Conversion / storage allocation loop ... Allocate memory in
9332fe8fb19SBen Gras * chunks SFRAG in size.
9342fe8fb19SBen Gras */
9352fe8fb19SBen Gras if ((mem = malloc(SFRAG)) == NULL) {
9362fe8fb19SBen Gras errno = ENOMEM;
9372fe8fb19SBen Gras return -2; /* couldn't even allocate the first fragment */
9382fe8fb19SBen Gras }
9392fe8fb19SBen Gras m_room = SFRAG;
9402fe8fb19SBen Gras mp = mem;
9412fe8fb19SBen Gras
9422fe8fb19SBen Gras while (*bp != ':' && *bp != '\0') {
9432fe8fb19SBen Gras /*
9442fe8fb19SBen Gras * Loop invariants:
9452fe8fb19SBen Gras * There is always room for one more character in mem.
9462fe8fb19SBen Gras * Mp always points just past last character in mem.
9472fe8fb19SBen Gras * Bp always points at next character in buf.
9482fe8fb19SBen Gras */
9492fe8fb19SBen Gras if (*bp == '^') {
9502fe8fb19SBen Gras bp++;
9512fe8fb19SBen Gras if (*bp == ':' || *bp == '\0')
9522fe8fb19SBen Gras break; /* drop unfinished escape */
9532fe8fb19SBen Gras *mp++ = *bp++ & 037;
9542fe8fb19SBen Gras } else if (*bp == '\\') {
9552fe8fb19SBen Gras bp++;
9562fe8fb19SBen Gras if (*bp == ':' || *bp == '\0')
9572fe8fb19SBen Gras break; /* drop unfinished escape */
9582fe8fb19SBen Gras if ('0' <= *bp && *bp <= '7') {
9592fe8fb19SBen Gras int n, i;
9602fe8fb19SBen Gras
9612fe8fb19SBen Gras n = 0;
9622fe8fb19SBen Gras i = 3; /* maximum of three octal digits */
9632fe8fb19SBen Gras do {
9642fe8fb19SBen Gras n = n * 8 + (*bp++ - '0');
9652fe8fb19SBen Gras } while (--i && '0' <= *bp && *bp <= '7');
9662fe8fb19SBen Gras *mp++ = n;
9672fe8fb19SBen Gras }
9682fe8fb19SBen Gras else switch (*bp++) {
9692fe8fb19SBen Gras case 'b': case 'B':
9702fe8fb19SBen Gras *mp++ = '\b';
9712fe8fb19SBen Gras break;
9722fe8fb19SBen Gras case 't': case 'T':
9732fe8fb19SBen Gras *mp++ = '\t';
9742fe8fb19SBen Gras break;
9752fe8fb19SBen Gras case 'n': case 'N':
9762fe8fb19SBen Gras *mp++ = '\n';
9772fe8fb19SBen Gras break;
9782fe8fb19SBen Gras case 'f': case 'F':
9792fe8fb19SBen Gras *mp++ = '\f';
9802fe8fb19SBen Gras break;
9812fe8fb19SBen Gras case 'r': case 'R':
9822fe8fb19SBen Gras *mp++ = '\r';
9832fe8fb19SBen Gras break;
9842fe8fb19SBen Gras case 'e': case 'E':
9852fe8fb19SBen Gras *mp++ = ESC;
9862fe8fb19SBen Gras break;
9872fe8fb19SBen Gras case 'c': case 'C':
9882fe8fb19SBen Gras *mp++ = ':';
9892fe8fb19SBen Gras break;
9902fe8fb19SBen Gras default:
9912fe8fb19SBen Gras /*
9922fe8fb19SBen Gras * Catches '\', '^', and
9932fe8fb19SBen Gras * everything else.
9942fe8fb19SBen Gras */
9952fe8fb19SBen Gras *mp++ = *(bp-1);
9962fe8fb19SBen Gras break;
9972fe8fb19SBen Gras }
9982fe8fb19SBen Gras } else
9992fe8fb19SBen Gras *mp++ = *bp++;
10002fe8fb19SBen Gras m_room--;
10012fe8fb19SBen Gras
10022fe8fb19SBen Gras /*
10032fe8fb19SBen Gras * Enforce loop invariant: if no room left in current
10042fe8fb19SBen Gras * buffer, try to get some more.
10052fe8fb19SBen Gras */
10062fe8fb19SBen Gras if (m_room == 0) {
10072fe8fb19SBen Gras size_t size = mp - mem;
10082fe8fb19SBen Gras
10092fe8fb19SBen Gras if ((newmem = realloc(mem, size + SFRAG)) == NULL) {
10102fe8fb19SBen Gras free(mem);
10112fe8fb19SBen Gras return -2;
10122fe8fb19SBen Gras }
10132fe8fb19SBen Gras mem = newmem;
10142fe8fb19SBen Gras m_room = SFRAG;
10152fe8fb19SBen Gras mp = mem + size;
10162fe8fb19SBen Gras }
10172fe8fb19SBen Gras }
10182fe8fb19SBen Gras *mp++ = '\0'; /* loop invariant let's us do this */
10192fe8fb19SBen Gras m_room--;
10202fe8fb19SBen Gras len = mp - mem - 1;
10212fe8fb19SBen Gras
10222fe8fb19SBen Gras /*
10232fe8fb19SBen Gras * Give back any extra memory and return value and success.
10242fe8fb19SBen Gras */
10252fe8fb19SBen Gras if (m_room != 0) {
10262fe8fb19SBen Gras if ((newmem = realloc(mem, (size_t)(mp - mem))) == NULL) {
10272fe8fb19SBen Gras free(mem);
10282fe8fb19SBen Gras return -2;
10292fe8fb19SBen Gras }
10302fe8fb19SBen Gras mem = newmem;
10312fe8fb19SBen Gras }
10322fe8fb19SBen Gras *str = mem;
1033f14fb602SLionel Sambuc _DIAGASSERT(__type_fit(int, len));
1034f14fb602SLionel Sambuc return (int)len;
10352fe8fb19SBen Gras }
10362fe8fb19SBen Gras
10372fe8fb19SBen Gras /*
10382fe8fb19SBen Gras * Cgetustr retrieves the value of the string capability cap from the
10392fe8fb19SBen Gras * capability record pointed to by buf. The difference between cgetustr()
10402fe8fb19SBen Gras * and cgetstr() is that cgetustr does not decode escapes but rather treats
10412fe8fb19SBen Gras * all characters literally. A pointer to a NUL terminated malloc'd
10422fe8fb19SBen Gras * copy of the string is returned in the char pointed to by str. The
10432fe8fb19SBen Gras * length of the string not including the trailing NUL is returned on success,
10442fe8fb19SBen Gras * -1 if the requested string capability couldn't be found, -2 if a system
10452fe8fb19SBen Gras * error was encountered (storage allocation failure).
10462fe8fb19SBen Gras */
10472fe8fb19SBen Gras int
cgetustr(char * buf,const char * cap,char ** str)10482fe8fb19SBen Gras cgetustr(char *buf, const char *cap, char **str)
10492fe8fb19SBen Gras {
10502fe8fb19SBen Gras u_int m_room;
10512fe8fb19SBen Gras const char *bp;
10522fe8fb19SBen Gras char *mp;
1053f14fb602SLionel Sambuc size_t len;
10542fe8fb19SBen Gras char *mem, *newmem;
10552fe8fb19SBen Gras
10562fe8fb19SBen Gras _DIAGASSERT(buf != NULL);
10572fe8fb19SBen Gras _DIAGASSERT(cap != NULL);
10582fe8fb19SBen Gras _DIAGASSERT(str != NULL);
10592fe8fb19SBen Gras
10602fe8fb19SBen Gras /*
10612fe8fb19SBen Gras * Find string capability cap
10622fe8fb19SBen Gras */
10632fe8fb19SBen Gras if ((bp = cgetcap(buf, cap, '=')) == NULL)
10642fe8fb19SBen Gras return -1;
10652fe8fb19SBen Gras
10662fe8fb19SBen Gras /*
10672fe8fb19SBen Gras * Conversion / storage allocation loop ... Allocate memory in
10682fe8fb19SBen Gras * chunks SFRAG in size.
10692fe8fb19SBen Gras */
10702fe8fb19SBen Gras if ((mem = malloc(SFRAG)) == NULL) {
10712fe8fb19SBen Gras errno = ENOMEM;
10722fe8fb19SBen Gras return -2; /* couldn't even allocate the first fragment */
10732fe8fb19SBen Gras }
10742fe8fb19SBen Gras m_room = SFRAG;
10752fe8fb19SBen Gras mp = mem;
10762fe8fb19SBen Gras
10772fe8fb19SBen Gras while (*bp != ':' && *bp != '\0') {
10782fe8fb19SBen Gras /*
10792fe8fb19SBen Gras * Loop invariants:
10802fe8fb19SBen Gras * There is always room for one more character in mem.
10812fe8fb19SBen Gras * Mp always points just past last character in mem.
10822fe8fb19SBen Gras * Bp always points at next character in buf.
10832fe8fb19SBen Gras */
10842fe8fb19SBen Gras *mp++ = *bp++;
10852fe8fb19SBen Gras m_room--;
10862fe8fb19SBen Gras
10872fe8fb19SBen Gras /*
10882fe8fb19SBen Gras * Enforce loop invariant: if no room left in current
10892fe8fb19SBen Gras * buffer, try to get some more.
10902fe8fb19SBen Gras */
10912fe8fb19SBen Gras if (m_room == 0) {
10922fe8fb19SBen Gras size_t size = mp - mem;
10932fe8fb19SBen Gras
10942fe8fb19SBen Gras if ((newmem = realloc(mem, size + SFRAG)) == NULL) {
10952fe8fb19SBen Gras free(mem);
10962fe8fb19SBen Gras return -2;
10972fe8fb19SBen Gras }
10982fe8fb19SBen Gras mem = newmem;
10992fe8fb19SBen Gras m_room = SFRAG;
11002fe8fb19SBen Gras mp = mem + size;
11012fe8fb19SBen Gras }
11022fe8fb19SBen Gras }
11032fe8fb19SBen Gras *mp++ = '\0'; /* loop invariant let's us do this */
11042fe8fb19SBen Gras m_room--;
11052fe8fb19SBen Gras len = mp - mem - 1;
11062fe8fb19SBen Gras
11072fe8fb19SBen Gras /*
11082fe8fb19SBen Gras * Give back any extra memory and return value and success.
11092fe8fb19SBen Gras */
11102fe8fb19SBen Gras if (m_room != 0) {
11112fe8fb19SBen Gras if ((newmem = realloc(mem, (size_t)(mp - mem))) == NULL) {
11122fe8fb19SBen Gras free(mem);
11132fe8fb19SBen Gras return -2;
11142fe8fb19SBen Gras }
11152fe8fb19SBen Gras mem = newmem;
11162fe8fb19SBen Gras }
11172fe8fb19SBen Gras *str = mem;
1118f14fb602SLionel Sambuc _DIAGASSERT(__type_fit(int, len));
1119f14fb602SLionel Sambuc return (int)len;
11202fe8fb19SBen Gras }
11212fe8fb19SBen Gras
11222fe8fb19SBen Gras /*
11232fe8fb19SBen Gras * Cgetnum retrieves the value of the numeric capability cap from the
11242fe8fb19SBen Gras * capability record pointed to by buf. The numeric value is returned in
11252fe8fb19SBen Gras * the long pointed to by num. 0 is returned on success, -1 if the requested
11262fe8fb19SBen Gras * numeric capability couldn't be found.
11272fe8fb19SBen Gras */
11282fe8fb19SBen Gras int
cgetnum(char * buf,const char * cap,long * num)11292fe8fb19SBen Gras cgetnum(char *buf, const char *cap, long *num)
11302fe8fb19SBen Gras {
11312fe8fb19SBen Gras long n;
11322fe8fb19SBen Gras int base, digit;
11332fe8fb19SBen Gras const char *bp;
11342fe8fb19SBen Gras
11352fe8fb19SBen Gras _DIAGASSERT(buf != NULL);
11362fe8fb19SBen Gras _DIAGASSERT(cap != NULL);
11372fe8fb19SBen Gras _DIAGASSERT(num != NULL);
11382fe8fb19SBen Gras
11392fe8fb19SBen Gras /*
11402fe8fb19SBen Gras * Find numeric capability cap
11412fe8fb19SBen Gras */
11422fe8fb19SBen Gras bp = cgetcap(buf, cap, '#');
11432fe8fb19SBen Gras if (bp == NULL)
11442fe8fb19SBen Gras return -1;
11452fe8fb19SBen Gras
11462fe8fb19SBen Gras /*
11472fe8fb19SBen Gras * Look at value and determine numeric base:
11482fe8fb19SBen Gras * 0x... or 0X... hexadecimal,
11492fe8fb19SBen Gras * else 0... octal,
11502fe8fb19SBen Gras * else decimal.
11512fe8fb19SBen Gras */
11522fe8fb19SBen Gras if (*bp == '0') {
11532fe8fb19SBen Gras bp++;
11542fe8fb19SBen Gras if (*bp == 'x' || *bp == 'X') {
11552fe8fb19SBen Gras bp++;
11562fe8fb19SBen Gras base = 16;
11572fe8fb19SBen Gras } else
11582fe8fb19SBen Gras base = 8;
11592fe8fb19SBen Gras } else
11602fe8fb19SBen Gras base = 10;
11612fe8fb19SBen Gras
11622fe8fb19SBen Gras /*
11632fe8fb19SBen Gras * Conversion loop ...
11642fe8fb19SBen Gras */
11652fe8fb19SBen Gras n = 0;
11662fe8fb19SBen Gras for (;;) {
11672fe8fb19SBen Gras if ('0' <= *bp && *bp <= '9')
11682fe8fb19SBen Gras digit = *bp - '0';
11692fe8fb19SBen Gras else if ('a' <= *bp && *bp <= 'f')
11702fe8fb19SBen Gras digit = 10 + *bp - 'a';
11712fe8fb19SBen Gras else if ('A' <= *bp && *bp <= 'F')
11722fe8fb19SBen Gras digit = 10 + *bp - 'A';
11732fe8fb19SBen Gras else
11742fe8fb19SBen Gras break;
11752fe8fb19SBen Gras
11762fe8fb19SBen Gras if (digit >= base)
11772fe8fb19SBen Gras break;
11782fe8fb19SBen Gras
11792fe8fb19SBen Gras n = n * base + digit;
11802fe8fb19SBen Gras bp++;
11812fe8fb19SBen Gras }
11822fe8fb19SBen Gras
11832fe8fb19SBen Gras /*
11842fe8fb19SBen Gras * Return value and success.
11852fe8fb19SBen Gras */
11862fe8fb19SBen Gras *num = n;
11872fe8fb19SBen Gras return 0;
11882fe8fb19SBen Gras }
11892fe8fb19SBen Gras
11902fe8fb19SBen Gras
11912fe8fb19SBen Gras /*
11922fe8fb19SBen Gras * Compare name field of record.
11932fe8fb19SBen Gras */
11942fe8fb19SBen Gras static int
nfcmp(char * nf,char * rec)11952fe8fb19SBen Gras nfcmp(char *nf, char *rec)
11962fe8fb19SBen Gras {
11972fe8fb19SBen Gras char *cp, tmp;
11982fe8fb19SBen Gras int ret;
11992fe8fb19SBen Gras
12002fe8fb19SBen Gras _DIAGASSERT(nf != NULL);
12012fe8fb19SBen Gras _DIAGASSERT(rec != NULL);
12022fe8fb19SBen Gras
12032fe8fb19SBen Gras for (cp = rec; *cp != ':'; cp++)
12042fe8fb19SBen Gras continue;
12052fe8fb19SBen Gras
12062fe8fb19SBen Gras tmp = *(cp + 1);
12072fe8fb19SBen Gras *(cp + 1) = '\0';
12082fe8fb19SBen Gras ret = strcmp(nf, rec);
12092fe8fb19SBen Gras *(cp + 1) = tmp;
12102fe8fb19SBen Gras
12112fe8fb19SBen Gras return ret;
12122fe8fb19SBen Gras }
1213