155682Smarkm/* $NetBSD: getcap.c,v 1.29 1999/03/29 09:27:29 abs Exp $ */ 255682Smarkm 355682Smarkm/*- 455682Smarkm * Copyright (c) 1992, 1993 555682Smarkm * The Regents of the University of California. All rights reserved. 655682Smarkm * 755682Smarkm * This code is derived from software contributed to Berkeley by 855682Smarkm * Casey Leedom of Lawrence Livermore National Laboratory. 955682Smarkm * 1055682Smarkm * Redistribution and use in source and binary forms, with or without 1155682Smarkm * modification, are permitted provided that the following conditions 1255682Smarkm * are met: 1355682Smarkm * 1. Redistributions of source code must retain the above copyright 1455682Smarkm * notice, this list of conditions and the following disclaimer. 1555682Smarkm * 2. Redistributions in binary form must reproduce the above copyright 1655682Smarkm * notice, this list of conditions and the following disclaimer in the 1755682Smarkm * documentation and/or other materials provided with the distribution. 18178825Sdfr * 3. Neither the name of the University nor the names of its contributors 1955682Smarkm * may be used to endorse or promote products derived from this software 2055682Smarkm * without specific prior written permission. 2155682Smarkm * 2255682Smarkm * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 2355682Smarkm * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2455682Smarkm * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2555682Smarkm * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 2655682Smarkm * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2755682Smarkm * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2855682Smarkm * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2955682Smarkm * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 3055682Smarkm * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 3155682Smarkm * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 3255682Smarkm * SUCH DAMAGE. 3355682Smarkm */ 3455682Smarkm 3555682Smarkm#include <config.h> 36233294Sstas 3755682Smarkm#include "roken.h" 3855682Smarkm 3955682Smarkm#include <sys/types.h> 4055682Smarkm#include <ctype.h> 4155682Smarkm#if defined(HAVE_DB_185_H) 4255682Smarkm#include <db_185.h> 4355682Smarkm#elif defined(HAVE_DB_H) 4455682Smarkm#include <db.h> 4555682Smarkm#endif 46233294Sstas#include <errno.h> 4755682Smarkm#include <fcntl.h> 4855682Smarkm#include <limits.h> 4955682Smarkm#include <stdio.h> 5055682Smarkm#include <stdlib.h> 5155682Smarkm#include <string.h> 5255682Smarkm#include <unistd.h> 5355682Smarkm 5455682Smarkm#define BFRAG 1024 5555682Smarkm#if 0 5655682Smarkm#define BSIZE 1024 5755682Smarkm#endif 5855682Smarkm#define ESC ('[' & 037) /* ASCII ESC */ 5955682Smarkm#define MAX_RECURSION 32 /* maximum getent recursion */ 6055682Smarkm#define SFRAG 100 /* cgetstr mallocs in SFRAG chunks */ 6155682Smarkm 6255682Smarkm#define RECOK (char)0 6355682Smarkm#define TCERR (char)1 6455682Smarkm#define SHADOW (char)2 6555682Smarkm 6655682Smarkmstatic size_t topreclen; /* toprec length */ 6755682Smarkmstatic char *toprec; /* Additional record specified by cgetset() */ 6855682Smarkmstatic int gottoprec; /* Flag indicating retrieval of toprecord */ 6955682Smarkm 70178825Sdfr#if 0 /* 71178825Sdfr * Don't use db support unless it's build into libc but we don't 72178825Sdfr * check for that now, so just disable the code. 73178825Sdfr */ 7455682Smarkm#if defined(HAVE_DBOPEN) && defined(HAVE_DB_H) 7555682Smarkm#define USE_DB 7655682Smarkm#endif 77178825Sdfr#endif 7855682Smarkm 7955682Smarkm#ifdef USE_DB 8055682Smarkmstatic int cdbget (DB *, char **, const char *); 8155682Smarkm#endif 8255682Smarkmstatic int getent (char **, size_t *, char **, int, const char *, int, char *); 8355682Smarkmstatic int nfcmp (char *, char *); 8455682Smarkm 8555682Smarkm 86233294SstasROKEN_LIB_FUNCTION int ROKEN_LIB_CALL cgetset(const char *ent); 87233294SstasROKEN_LIB_FUNCTION char * ROKEN_LIB_CALL cgetcap(char *buf, const char *cap, int type); 88233294SstasROKEN_LIB_FUNCTION int ROKEN_LIB_CALL cgetent(char **buf, char **db_array, const char *name); 89233294SstasROKEN_LIB_FUNCTION int ROKEN_LIB_CALL cgetmatch(const char *buf, const char *name); 90233294SstasROKEN_LIB_FUNCTION int ROKEN_LIB_CALL cgetclose(void); 9155682Smarkm#if 0 9255682Smarkmint cgetfirst(char **buf, char **db_array); 9355682Smarkmint cgetnext(char **bp, char **db_array); 9455682Smarkm#endif 95233294SstasROKEN_LIB_FUNCTION int ROKEN_LIB_CALL cgetstr(char *buf, const char *cap, char **str); 96233294SstasROKEN_LIB_FUNCTION int ROKEN_LIB_CALL cgetustr(char *buf, const char *cap, char **str); 97233294SstasROKEN_LIB_FUNCTION int ROKEN_LIB_CALL cgetnum(char *buf, const char *cap, long *num); 9855682Smarkm/* 9955682Smarkm * Cgetset() allows the addition of a user specified buffer to be added 10055682Smarkm * to the database array, in effect "pushing" the buffer on top of the 10155682Smarkm * virtual database. 0 is returned on success, -1 on failure. 10255682Smarkm */ 103233294SstasROKEN_LIB_FUNCTION int ROKEN_LIB_CALL 10455682Smarkmcgetset(const char *ent) 10555682Smarkm{ 10655682Smarkm const char *source, *check; 10755682Smarkm char *dest; 10855682Smarkm 10955682Smarkm if (ent == NULL) { 11055682Smarkm if (toprec) 11155682Smarkm free(toprec); 11255682Smarkm toprec = NULL; 11355682Smarkm topreclen = 0; 11455682Smarkm return (0); 11555682Smarkm } 11655682Smarkm topreclen = strlen(ent); 11755682Smarkm if ((toprec = malloc (topreclen + 1)) == NULL) { 11855682Smarkm errno = ENOMEM; 11955682Smarkm return (-1); 12055682Smarkm } 12155682Smarkm gottoprec = 0; 12255682Smarkm 12355682Smarkm source=ent; 12455682Smarkm dest=toprec; 12555682Smarkm while (*source) { /* Strip whitespace */ 12655682Smarkm *dest++ = *source++; /* Do not check first field */ 12755682Smarkm while (*source == ':') { 12855682Smarkm check=source+1; 12955682Smarkm while (*check && (isspace((unsigned char)*check) || 13055682Smarkm (*check=='\\' && isspace((unsigned char)check[1])))) 13155682Smarkm ++check; 13255682Smarkm if( *check == ':' ) 13355682Smarkm source=check; 13455682Smarkm else 13555682Smarkm break; 13655682Smarkm 13755682Smarkm } 13855682Smarkm } 13955682Smarkm *dest=0; 14055682Smarkm 14155682Smarkm return (0); 14255682Smarkm} 14355682Smarkm 14455682Smarkm/* 14555682Smarkm * Cgetcap searches the capability record buf for the capability cap with 14655682Smarkm * type `type'. A pointer to the value of cap is returned on success, NULL 14755682Smarkm * if the requested capability couldn't be found. 14855682Smarkm * 14955682Smarkm * Specifying a type of ':' means that nothing should follow cap (:cap:). 15055682Smarkm * In this case a pointer to the terminating ':' or NUL will be returned if 15155682Smarkm * cap is found. 15255682Smarkm * 15355682Smarkm * If (cap, '@') or (cap, terminator, '@') is found before (cap, terminator) 15455682Smarkm * return NULL. 15555682Smarkm */ 156233294SstasROKEN_LIB_FUNCTION char * ROKEN_LIB_CALL 15755682Smarkmcgetcap(char *buf, const char *cap, int type) 15855682Smarkm{ 15955682Smarkm char *bp; 16055682Smarkm const char *cp; 16155682Smarkm 16255682Smarkm bp = buf; 16355682Smarkm for (;;) { 16455682Smarkm /* 16555682Smarkm * Skip past the current capability field - it's either the 16655682Smarkm * name field if this is the first time through the loop, or 16755682Smarkm * the remainder of a field whose name failed to match cap. 16855682Smarkm */ 16955682Smarkm for (;;) 17055682Smarkm if (*bp == '\0') 17155682Smarkm return (NULL); 17255682Smarkm else 17355682Smarkm if (*bp++ == ':') 17455682Smarkm break; 17555682Smarkm 17655682Smarkm /* 17755682Smarkm * Try to match (cap, type) in buf. 17855682Smarkm */ 17955682Smarkm for (cp = cap; *cp == *bp && *bp != '\0'; cp++, bp++) 18055682Smarkm continue; 18155682Smarkm if (*cp != '\0') 18255682Smarkm continue; 18355682Smarkm if (*bp == '@') 18455682Smarkm return (NULL); 18555682Smarkm if (type == ':') { 18655682Smarkm if (*bp != '\0' && *bp != ':') 18755682Smarkm continue; 18855682Smarkm return(bp); 18955682Smarkm } 19055682Smarkm if (*bp != type) 19155682Smarkm continue; 19255682Smarkm bp++; 19355682Smarkm return (*bp == '@' ? NULL : bp); 19455682Smarkm } 19555682Smarkm /* NOTREACHED */ 19655682Smarkm} 19755682Smarkm 19855682Smarkm/* 19955682Smarkm * Cgetent extracts the capability record name from the NULL terminated file 20055682Smarkm * array db_array and returns a pointer to a malloc'd copy of it in buf. 20155682Smarkm * Buf must be retained through all subsequent calls to cgetcap, cgetnum, 20255682Smarkm * cgetflag, and cgetstr, but may then be free'd. 0 is returned on success, 20355682Smarkm * -1 if the requested record couldn't be found, -2 if a system error was 20455682Smarkm * encountered (couldn't open/read a file, etc.), and -3 if a potential 20555682Smarkm * reference loop is detected. 20655682Smarkm */ 207233294SstasROKEN_LIB_FUNCTION int ROKEN_LIB_CALL 20855682Smarkmcgetent(char **buf, char **db_array, const char *name) 20955682Smarkm{ 21055682Smarkm size_t dummy; 21155682Smarkm 21255682Smarkm return (getent(buf, &dummy, db_array, -1, name, 0, NULL)); 21355682Smarkm} 21455682Smarkm 21555682Smarkm/* 21655682Smarkm * Getent implements the functions of cgetent. If fd is non-negative, 21755682Smarkm * *db_array has already been opened and fd is the open file descriptor. We 21855682Smarkm * do this to save time and avoid using up file descriptors for tc= 21955682Smarkm * recursions. 22055682Smarkm * 22155682Smarkm * Getent returns the same success/failure codes as cgetent. On success, a 22255682Smarkm * pointer to a malloc'ed capability record with all tc= capabilities fully 22355682Smarkm * expanded and its length (not including trailing ASCII NUL) are left in 22455682Smarkm * *cap and *len. 22555682Smarkm * 22655682Smarkm * Basic algorithm: 22755682Smarkm * + Allocate memory incrementally as needed in chunks of size BFRAG 22855682Smarkm * for capability buffer. 22955682Smarkm * + Recurse for each tc=name and interpolate result. Stop when all 23055682Smarkm * names interpolated, a name can't be found, or depth exceeds 23155682Smarkm * MAX_RECURSION. 23255682Smarkm */ 23355682Smarkmstatic int 234233294Sstasgetent(char **cap, size_t *len, char **db_array, int fd, 23555682Smarkm const char *name, int depth, char *nfield) 23655682Smarkm{ 23755682Smarkm char *r_end, *rp = NULL, **db_p; /* pacify gcc */ 23855682Smarkm int myfd = 0, eof, foundit; 23955682Smarkm char *record; 24055682Smarkm int tc_not_resolved; 241233294Sstas 24255682Smarkm /* 24355682Smarkm * Return with ``loop detected'' error if we've recursed more than 24455682Smarkm * MAX_RECURSION times. 24555682Smarkm */ 24655682Smarkm if (depth > MAX_RECURSION) 24755682Smarkm return (-3); 24855682Smarkm 24955682Smarkm /* 25055682Smarkm * Check if we have a top record from cgetset(). 25155682Smarkm */ 25255682Smarkm if (depth == 0 && toprec != NULL && cgetmatch(toprec, name) == 0) { 253120945Snectar size_t len = topreclen + BFRAG; 254120945Snectar if ((record = malloc (len)) == NULL) { 25555682Smarkm errno = ENOMEM; 25655682Smarkm return (-2); 25755682Smarkm } 258120945Snectar (void)strlcpy(record, toprec, len); 25955682Smarkm db_p = db_array; 26055682Smarkm rp = record + topreclen + 1; 26155682Smarkm r_end = rp + BFRAG; 26255682Smarkm goto tc_exp; 26355682Smarkm } 26455682Smarkm /* 26555682Smarkm * Allocate first chunk of memory. 26655682Smarkm */ 26755682Smarkm if ((record = malloc(BFRAG)) == NULL) { 26855682Smarkm errno = ENOMEM; 26955682Smarkm return (-2); 27055682Smarkm } 27155682Smarkm r_end = record + BFRAG; 27255682Smarkm foundit = 0; 27355682Smarkm /* 27455682Smarkm * Loop through database array until finding the record. 27555682Smarkm */ 27655682Smarkm 27755682Smarkm for (db_p = db_array; *db_p != NULL; db_p++) { 27855682Smarkm eof = 0; 27955682Smarkm 28055682Smarkm /* 28155682Smarkm * Open database if not already open. 28255682Smarkm */ 28355682Smarkm 28455682Smarkm if (fd >= 0) { 28555682Smarkm (void)lseek(fd, (off_t)0, SEEK_SET); 28655682Smarkm } else { 28755682Smarkm#ifdef USE_DB 28855682Smarkm char pbuf[_POSIX_PATH_MAX]; 28955682Smarkm char *cbuf; 29055682Smarkm size_t clen; 29155682Smarkm int retval; 29255682Smarkm DB *capdbp; 29355682Smarkm 29455682Smarkm (void)snprintf(pbuf, sizeof(pbuf), "%s.db", *db_p); 29555682Smarkm if ((capdbp = dbopen(pbuf, O_RDONLY, 0, DB_HASH, 0)) 29655682Smarkm != NULL) { 29755682Smarkm free(record); 29855682Smarkm retval = cdbget(capdbp, &record, name); 29955682Smarkm if (retval < 0) { 30055682Smarkm /* no record available */ 30155682Smarkm (void)capdbp->close(capdbp); 30255682Smarkm return (retval); 30355682Smarkm } 30455682Smarkm /* save the data; close frees it */ 30555682Smarkm clen = strlen(record); 30655682Smarkm cbuf = malloc(clen + 1); 307178825Sdfr if (cbuf == NULL) 308178825Sdfr return (-2); 30955682Smarkm memmove(cbuf, record, clen + 1); 31055682Smarkm if (capdbp->close(capdbp) < 0) { 31155682Smarkm free(cbuf); 31255682Smarkm return (-2); 31355682Smarkm } 31455682Smarkm *len = clen; 31555682Smarkm *cap = cbuf; 31655682Smarkm return (retval); 31755682Smarkm } else 31855682Smarkm#endif 31955682Smarkm { 32055682Smarkm fd = open(*db_p, O_RDONLY, 0); 32155682Smarkm if (fd < 0) { 32255682Smarkm /* No error on unfound file. */ 32355682Smarkm continue; 32455682Smarkm } 32555682Smarkm myfd = 1; 32655682Smarkm } 32755682Smarkm } 32855682Smarkm /* 32955682Smarkm * Find the requested capability record ... 33055682Smarkm */ 33155682Smarkm { 33255682Smarkm char buf[BUFSIZ]; 33355682Smarkm char *b_end, *bp, *cp; 33455682Smarkm int c, slash; 33555682Smarkm 33655682Smarkm /* 33755682Smarkm * Loop invariants: 33855682Smarkm * There is always room for one more character in record. 33955682Smarkm * R_end always points just past end of record. 34055682Smarkm * Rp always points just past last character in record. 34155682Smarkm * B_end always points just past last character in buf. 34255682Smarkm * Bp always points at next character in buf. 34355682Smarkm * Cp remembers where the last colon was. 34455682Smarkm */ 34555682Smarkm b_end = buf; 34655682Smarkm bp = buf; 34755682Smarkm cp = 0; 34855682Smarkm slash = 0; 34955682Smarkm for (;;) { 35055682Smarkm 35155682Smarkm /* 35255682Smarkm * Read in a line implementing (\, newline) 35355682Smarkm * line continuation. 35455682Smarkm */ 35555682Smarkm rp = record; 35655682Smarkm for (;;) { 35755682Smarkm if (bp >= b_end) { 35855682Smarkm int n; 359233294Sstas 36055682Smarkm n = read(fd, buf, sizeof(buf)); 36155682Smarkm if (n <= 0) { 36255682Smarkm if (myfd) 36355682Smarkm (void)close(fd); 36455682Smarkm if (n < 0) { 36555682Smarkm free(record); 36655682Smarkm return (-2); 36755682Smarkm } else { 36855682Smarkm fd = -1; 36955682Smarkm eof = 1; 37055682Smarkm break; 37155682Smarkm } 37255682Smarkm } 37355682Smarkm b_end = buf+n; 37455682Smarkm bp = buf; 37555682Smarkm } 376233294Sstas 37755682Smarkm c = *bp++; 37855682Smarkm if (c == '\n') { 37955682Smarkm if (slash) { 38055682Smarkm slash = 0; 38155682Smarkm rp--; 38255682Smarkm continue; 38355682Smarkm } else 38455682Smarkm break; 38555682Smarkm } 38655682Smarkm if (slash) { 38755682Smarkm slash = 0; 38855682Smarkm cp = 0; 38955682Smarkm } 39055682Smarkm if (c == ':') { 39155682Smarkm /* 39255682Smarkm * If the field was `empty' (i.e. 39355682Smarkm * contained only white space), back up 39455682Smarkm * to the colon (eliminating the 39555682Smarkm * field). 39655682Smarkm */ 39755682Smarkm if (cp) 39855682Smarkm rp = cp; 39955682Smarkm else 40055682Smarkm cp = rp; 40155682Smarkm } else if (c == '\\') { 40255682Smarkm slash = 1; 40355682Smarkm } else if (c != ' ' && c != '\t') { 40455682Smarkm /* 40555682Smarkm * Forget where the colon was, as this 40655682Smarkm * is not an empty field. 40755682Smarkm */ 40855682Smarkm cp = 0; 40955682Smarkm } 41055682Smarkm *rp++ = c; 41155682Smarkm 41255682Smarkm /* 413233294Sstas * Enforce loop invariant: if no room 41455682Smarkm * left in record buffer, try to get 41555682Smarkm * some more. 41655682Smarkm */ 41755682Smarkm if (rp >= r_end) { 41855682Smarkm u_int pos; 41955682Smarkm size_t newsize; 42055682Smarkm 42155682Smarkm pos = rp - record; 42255682Smarkm newsize = r_end - record + BFRAG; 42355682Smarkm record = realloc(record, newsize); 42455682Smarkm if (record == NULL) { 42555682Smarkm errno = ENOMEM; 42655682Smarkm if (myfd) 42755682Smarkm (void)close(fd); 42855682Smarkm return (-2); 42955682Smarkm } 43055682Smarkm r_end = record + newsize; 43155682Smarkm rp = record + pos; 43255682Smarkm } 43355682Smarkm } 43455682Smarkm /* Eliminate any white space after the last colon. */ 43555682Smarkm if (cp) 43655682Smarkm rp = cp + 1; 43755682Smarkm /* Loop invariant lets us do this. */ 43855682Smarkm *rp++ = '\0'; 43955682Smarkm 44055682Smarkm /* 44155682Smarkm * If encountered eof check next file. 44255682Smarkm */ 44355682Smarkm if (eof) 44455682Smarkm break; 445233294Sstas 44655682Smarkm /* 44755682Smarkm * Toss blank lines and comments. 44855682Smarkm */ 44955682Smarkm if (*record == '\0' || *record == '#') 45055682Smarkm continue; 451233294Sstas 45255682Smarkm /* 45355682Smarkm * See if this is the record we want ... 45455682Smarkm */ 45555682Smarkm if (cgetmatch(record, name) == 0) { 45655682Smarkm if (nfield == NULL || !nfcmp(nfield, record)) { 45755682Smarkm foundit = 1; 45855682Smarkm break; /* found it! */ 45955682Smarkm } 46055682Smarkm } 46155682Smarkm } 46255682Smarkm } 46355682Smarkm if (foundit) 46455682Smarkm break; 46555682Smarkm } 46655682Smarkm 46755682Smarkm if (!foundit) 46855682Smarkm return (-1); 46955682Smarkm 47055682Smarkm /* 47155682Smarkm * Got the capability record, but now we have to expand all tc=name 47255682Smarkm * references in it ... 47355682Smarkm */ 47455682Smarkm tc_exp: { 47555682Smarkm char *newicap, *s; 47655682Smarkm size_t ilen, newilen; 47755682Smarkm int diff, iret, tclen; 47855682Smarkm char *icap, *scan, *tc, *tcstart, *tcend; 47955682Smarkm 48055682Smarkm /* 48155682Smarkm * Loop invariants: 48255682Smarkm * There is room for one more character in record. 48355682Smarkm * R_end points just past end of record. 48455682Smarkm * Rp points just past last character in record. 48555682Smarkm * Scan points at remainder of record that needs to be 48655682Smarkm * scanned for tc=name constructs. 48755682Smarkm */ 48855682Smarkm scan = record; 48955682Smarkm tc_not_resolved = 0; 49055682Smarkm for (;;) { 49155682Smarkm if ((tc = cgetcap(scan, "tc", '=')) == NULL) 49255682Smarkm break; 49355682Smarkm 49455682Smarkm /* 49555682Smarkm * Find end of tc=name and stomp on the trailing `:' 49655682Smarkm * (if present) so we can use it to call ourselves. 49755682Smarkm */ 49855682Smarkm s = tc; 49955682Smarkm for (;;) 50055682Smarkm if (*s == '\0') 50155682Smarkm break; 50255682Smarkm else 50355682Smarkm if (*s++ == ':') { 50455682Smarkm *(s - 1) = '\0'; 50555682Smarkm break; 50655682Smarkm } 50755682Smarkm tcstart = tc - 3; 50855682Smarkm tclen = s - tcstart; 50955682Smarkm tcend = s; 51055682Smarkm 511233294Sstas iret = getent(&icap, &ilen, db_p, fd, tc, depth+1, 51255682Smarkm NULL); 51355682Smarkm newicap = icap; /* Put into a register. */ 51455682Smarkm newilen = ilen; 51555682Smarkm if (iret != 0) { 51655682Smarkm /* an error */ 51755682Smarkm if (iret < -1) { 51855682Smarkm if (myfd) 51955682Smarkm (void)close(fd); 52055682Smarkm free(record); 52155682Smarkm return (iret); 52255682Smarkm } 52355682Smarkm if (iret == 1) 52455682Smarkm tc_not_resolved = 1; 52555682Smarkm /* couldn't resolve tc */ 52655682Smarkm if (iret == -1) { 527233294Sstas *(s - 1) = ':'; 52855682Smarkm scan = s - 1; 52955682Smarkm tc_not_resolved = 1; 53055682Smarkm continue; 531233294Sstas 53255682Smarkm } 53355682Smarkm } 53455682Smarkm /* not interested in name field of tc'ed record */ 53555682Smarkm s = newicap; 53655682Smarkm for (;;) 53755682Smarkm if (*s == '\0') 53855682Smarkm break; 53955682Smarkm else 54055682Smarkm if (*s++ == ':') 54155682Smarkm break; 54255682Smarkm newilen -= s - newicap; 54355682Smarkm newicap = s; 54455682Smarkm 54555682Smarkm /* make sure interpolated record is `:'-terminated */ 54655682Smarkm s += newilen; 54755682Smarkm if (*(s-1) != ':') { 54855682Smarkm *s = ':'; /* overwrite NUL with : */ 54955682Smarkm newilen++; 55055682Smarkm } 55155682Smarkm 55255682Smarkm /* 55355682Smarkm * Make sure there's enough room to insert the 55455682Smarkm * new record. 55555682Smarkm */ 55655682Smarkm diff = newilen - tclen; 55755682Smarkm if (diff >= r_end - rp) { 55855682Smarkm u_int pos, tcpos, tcposend; 55955682Smarkm size_t newsize; 56055682Smarkm 56155682Smarkm pos = rp - record; 56255682Smarkm newsize = r_end - record + diff + BFRAG; 56355682Smarkm tcpos = tcstart - record; 56455682Smarkm tcposend = tcend - record; 56555682Smarkm record = realloc(record, newsize); 56655682Smarkm if (record == NULL) { 56755682Smarkm errno = ENOMEM; 56855682Smarkm if (myfd) 56955682Smarkm (void)close(fd); 57055682Smarkm free(icap); 57155682Smarkm return (-2); 57255682Smarkm } 57355682Smarkm r_end = record + newsize; 57455682Smarkm rp = record + pos; 57555682Smarkm tcstart = record + tcpos; 57655682Smarkm tcend = record + tcposend; 57755682Smarkm } 57855682Smarkm 57955682Smarkm /* 58055682Smarkm * Insert tc'ed record into our record. 58155682Smarkm */ 58255682Smarkm s = tcstart + newilen; 58355682Smarkm memmove(s, tcend, (size_t)(rp - tcend)); 58455682Smarkm memmove(tcstart, newicap, newilen); 58555682Smarkm rp += diff; 58655682Smarkm free(icap); 58755682Smarkm 58855682Smarkm /* 58955682Smarkm * Start scan on `:' so next cgetcap works properly 59055682Smarkm * (cgetcap always skips first field). 59155682Smarkm */ 59255682Smarkm scan = s-1; 59355682Smarkm } 594233294Sstas 59555682Smarkm } 59655682Smarkm /* 59755682Smarkm * Close file (if we opened it), give back any extra memory, and 59855682Smarkm * return capability, length and success. 59955682Smarkm */ 60055682Smarkm if (myfd) 60155682Smarkm (void)close(fd); 60255682Smarkm *len = rp - record - 1; /* don't count NUL */ 60355682Smarkm if (r_end > rp) 604233294Sstas if ((record = 60555682Smarkm realloc(record, (size_t)(rp - record))) == NULL) { 60655682Smarkm errno = ENOMEM; 60755682Smarkm return (-2); 60855682Smarkm } 609233294Sstas 61055682Smarkm *cap = record; 61155682Smarkm if (tc_not_resolved) 61255682Smarkm return (1); 61355682Smarkm return (0); 614233294Sstas} 61555682Smarkm 61655682Smarkm#ifdef USE_DB 61755682Smarkmstatic int 61855682Smarkmcdbget(DB *capdbp, char **bp, const char *name) 61955682Smarkm{ 62055682Smarkm DBT key; 62155682Smarkm DBT data; 62255682Smarkm 62355682Smarkm /* LINTED key is not modified */ 62455682Smarkm key.data = (char *)name; 62555682Smarkm key.size = strlen(name); 62655682Smarkm 62755682Smarkm for (;;) { 62855682Smarkm /* Get the reference. */ 62955682Smarkm switch(capdbp->get(capdbp, &key, &data, 0)) { 63055682Smarkm case -1: 63155682Smarkm return (-2); 63255682Smarkm case 1: 63355682Smarkm return (-1); 63455682Smarkm } 63555682Smarkm 63655682Smarkm /* If not an index to another record, leave. */ 63755682Smarkm if (((char *)data.data)[0] != SHADOW) 63855682Smarkm break; 63955682Smarkm 64055682Smarkm key.data = (char *)data.data + 1; 64155682Smarkm key.size = data.size - 1; 64255682Smarkm } 643233294Sstas 64455682Smarkm *bp = (char *)data.data + 1; 64555682Smarkm return (((char *)(data.data))[0] == TCERR ? 1 : 0); 64655682Smarkm} 64755682Smarkm#endif /* USE_DB */ 64855682Smarkm 64955682Smarkm/* 65055682Smarkm * Cgetmatch will return 0 if name is one of the names of the capability 65155682Smarkm * record buf, -1 if not. 65255682Smarkm */ 65355682Smarkmint 65455682Smarkmcgetmatch(const char *buf, const char *name) 65555682Smarkm{ 65655682Smarkm const char *np, *bp; 65755682Smarkm 65855682Smarkm /* 65955682Smarkm * Start search at beginning of record. 66055682Smarkm */ 66155682Smarkm bp = buf; 66255682Smarkm for (;;) { 66355682Smarkm /* 66455682Smarkm * Try to match a record name. 66555682Smarkm */ 66655682Smarkm np = name; 66755682Smarkm for (;;) 66855682Smarkm if (*np == '\0') { 66955682Smarkm if (*bp == '|' || *bp == ':' || *bp == '\0') 67055682Smarkm return (0); 67155682Smarkm else 67255682Smarkm break; 67355682Smarkm } else 67455682Smarkm if (*bp++ != *np++) 67555682Smarkm break; 67655682Smarkm 67755682Smarkm /* 67855682Smarkm * Match failed, skip to next name in record. 67955682Smarkm */ 68055682Smarkm bp--; /* a '|' or ':' may have stopped the match */ 68155682Smarkm for (;;) 68255682Smarkm if (*bp == '\0' || *bp == ':') 68355682Smarkm return (-1); /* match failed totally */ 68455682Smarkm else 68555682Smarkm if (*bp++ == '|') 68655682Smarkm break; /* found next name */ 68755682Smarkm } 68855682Smarkm} 68955682Smarkm 69055682Smarkm#if 0 69155682Smarkmint 69255682Smarkmcgetfirst(char **buf, char **db_array) 69355682Smarkm{ 69455682Smarkm (void)cgetclose(); 69555682Smarkm return (cgetnext(buf, db_array)); 69655682Smarkm} 69755682Smarkm#endif 69855682Smarkm 69955682Smarkmstatic FILE *pfp; 70055682Smarkmstatic int slash; 70155682Smarkmstatic char **dbp; 70255682Smarkm 703233294SstasROKEN_LIB_FUNCTION int ROKEN_LIB_CALL 70455682Smarkmcgetclose(void) 70555682Smarkm{ 70655682Smarkm if (pfp != NULL) { 70755682Smarkm (void)fclose(pfp); 70855682Smarkm pfp = NULL; 70955682Smarkm } 71055682Smarkm dbp = NULL; 71155682Smarkm gottoprec = 0; 71255682Smarkm slash = 0; 71355682Smarkm return(0); 71455682Smarkm} 71555682Smarkm 71655682Smarkm#if 0 71755682Smarkm/* 718233294Sstas * Cgetnext() gets either the first or next entry in the logical database 71955682Smarkm * specified by db_array. It returns 0 upon completion of the database, 1 72055682Smarkm * upon returning an entry with more remaining, and -1 if an error occurs. 72155682Smarkm */ 72255682Smarkmint 72355682Smarkmcgetnext(char **bp, char **db_array) 72455682Smarkm{ 72555682Smarkm size_t len; 72655682Smarkm int status, done; 72755682Smarkm char *cp, *line, *rp, *np, buf[BSIZE], nbuf[BSIZE]; 72855682Smarkm size_t dummy; 72955682Smarkm 73055682Smarkm if (dbp == NULL) 73155682Smarkm dbp = db_array; 73255682Smarkm 73355682Smarkm if (pfp == NULL && (pfp = fopen(*dbp, "r")) == NULL) { 73455682Smarkm (void)cgetclose(); 73555682Smarkm return (-1); 73655682Smarkm } 73755682Smarkm for(;;) { 73855682Smarkm if (toprec && !gottoprec) { 73955682Smarkm gottoprec = 1; 74055682Smarkm line = toprec; 74155682Smarkm } else { 74255682Smarkm line = fgetln(pfp, &len); 74355682Smarkm if (line == NULL && pfp) { 74455682Smarkm if (ferror(pfp)) { 74555682Smarkm (void)cgetclose(); 74655682Smarkm return (-1); 74755682Smarkm } else { 74855682Smarkm (void)fclose(pfp); 74955682Smarkm pfp = NULL; 75055682Smarkm if (*++dbp == NULL) { 75155682Smarkm (void)cgetclose(); 75255682Smarkm return (0); 75355682Smarkm } else if ((pfp = 75455682Smarkm fopen(*dbp, "r")) == NULL) { 75555682Smarkm (void)cgetclose(); 75655682Smarkm return (-1); 75755682Smarkm } else 75855682Smarkm continue; 75955682Smarkm } 76055682Smarkm } else 76155682Smarkm line[len - 1] = '\0'; 76255682Smarkm if (len == 1) { 76355682Smarkm slash = 0; 76455682Smarkm continue; 76555682Smarkm } 76655682Smarkm if (isspace((unsigned char)*line) || 76755682Smarkm *line == ':' || *line == '#' || slash) { 76855682Smarkm if (line[len - 2] == '\\') 76955682Smarkm slash = 1; 77055682Smarkm else 77155682Smarkm slash = 0; 77255682Smarkm continue; 77355682Smarkm } 77455682Smarkm if (line[len - 2] == '\\') 77555682Smarkm slash = 1; 77655682Smarkm else 77755682Smarkm slash = 0; 778233294Sstas } 77955682Smarkm 78055682Smarkm 781233294Sstas /* 78255682Smarkm * Line points to a name line. 78355682Smarkm */ 78455682Smarkm done = 0; 78555682Smarkm np = nbuf; 78655682Smarkm for (;;) { 78755682Smarkm for (cp = line; *cp != '\0'; cp++) { 78855682Smarkm if (*cp == ':') { 78955682Smarkm *np++ = ':'; 79055682Smarkm done = 1; 79155682Smarkm break; 79255682Smarkm } 79355682Smarkm if (*cp == '\\') 79455682Smarkm break; 79555682Smarkm *np++ = *cp; 79655682Smarkm } 79755682Smarkm if (done) { 79855682Smarkm *np = '\0'; 79955682Smarkm break; 80055682Smarkm } else { /* name field extends beyond the line */ 80155682Smarkm line = fgetln(pfp, &len); 80255682Smarkm if (line == NULL && pfp) { 80355682Smarkm if (ferror(pfp)) { 80455682Smarkm (void)cgetclose(); 80555682Smarkm return (-1); 80655682Smarkm } 80755682Smarkm (void)fclose(pfp); 80855682Smarkm pfp = NULL; 80955682Smarkm *np = '\0'; 81055682Smarkm break; 81155682Smarkm } else 81255682Smarkm line[len - 1] = '\0'; 81355682Smarkm } 81455682Smarkm } 81555682Smarkm rp = buf; 81655682Smarkm for(cp = nbuf; *cp != '\0'; cp++) 81755682Smarkm if (*cp == '|' || *cp == ':') 81855682Smarkm break; 81955682Smarkm else 82055682Smarkm *rp++ = *cp; 82155682Smarkm 82255682Smarkm *rp = '\0'; 823233294Sstas /* 824233294Sstas * XXX 82555682Smarkm * Last argument of getent here should be nbuf if we want true 826233294Sstas * sequential access in the case of duplicates. 82755682Smarkm * With NULL, getent will return the first entry found 828233294Sstas * rather than the duplicate entry record. This is a 82955682Smarkm * matter of semantics that should be resolved. 83055682Smarkm */ 83155682Smarkm status = getent(bp, &dummy, db_array, -1, buf, 0, NULL); 83255682Smarkm if (status == -2 || status == -3) 83355682Smarkm (void)cgetclose(); 83455682Smarkm 83555682Smarkm return (status + 1); 83655682Smarkm } 83755682Smarkm /* NOTREACHED */ 83855682Smarkm} 83955682Smarkm#endif 84055682Smarkm 84155682Smarkm/* 84255682Smarkm * Cgetstr retrieves the value of the string capability cap from the 84355682Smarkm * capability record pointed to by buf. A pointer to a decoded, NUL 84455682Smarkm * terminated, malloc'd copy of the string is returned in the char * 84555682Smarkm * pointed to by str. The length of the string not including the trailing 84655682Smarkm * NUL is returned on success, -1 if the requested string capability 84755682Smarkm * couldn't be found, -2 if a system error was encountered (storage 84855682Smarkm * allocation failure). 84955682Smarkm */ 850233294SstasROKEN_LIB_FUNCTION int ROKEN_LIB_CALL 85155682Smarkmcgetstr(char *buf, const char *cap, char **str) 85255682Smarkm{ 85355682Smarkm u_int m_room; 85455682Smarkm const char *bp; 85555682Smarkm char *mp; 85655682Smarkm int len; 857233294Sstas char *mem, *nmem; 85855682Smarkm 859233294Sstas *str = NULL; 860233294Sstas 86155682Smarkm /* 86255682Smarkm * Find string capability cap 86355682Smarkm */ 86455682Smarkm bp = cgetcap(buf, cap, '='); 86555682Smarkm if (bp == NULL) 86655682Smarkm return (-1); 86755682Smarkm 86855682Smarkm /* 86955682Smarkm * Conversion / storage allocation loop ... Allocate memory in 87055682Smarkm * chunks SFRAG in size. 87155682Smarkm */ 87255682Smarkm if ((mem = malloc(SFRAG)) == NULL) { 87355682Smarkm errno = ENOMEM; 87455682Smarkm return (-2); /* couldn't even allocate the first fragment */ 87555682Smarkm } 87655682Smarkm m_room = SFRAG; 87755682Smarkm mp = mem; 87855682Smarkm 87955682Smarkm while (*bp != ':' && *bp != '\0') { 88055682Smarkm /* 88155682Smarkm * Loop invariants: 88255682Smarkm * There is always room for one more character in mem. 88355682Smarkm * Mp always points just past last character in mem. 88455682Smarkm * Bp always points at next character in buf. 88555682Smarkm */ 88655682Smarkm if (*bp == '^') { 88755682Smarkm bp++; 88855682Smarkm if (*bp == ':' || *bp == '\0') 88955682Smarkm break; /* drop unfinished escape */ 89055682Smarkm *mp++ = *bp++ & 037; 89155682Smarkm } else if (*bp == '\\') { 89255682Smarkm bp++; 89355682Smarkm if (*bp == ':' || *bp == '\0') 89455682Smarkm break; /* drop unfinished escape */ 89555682Smarkm if ('0' <= *bp && *bp <= '7') { 89655682Smarkm int n, i; 89755682Smarkm 89855682Smarkm n = 0; 89955682Smarkm i = 3; /* maximum of three octal digits */ 90055682Smarkm do { 90155682Smarkm n = n * 8 + (*bp++ - '0'); 90255682Smarkm } while (--i && '0' <= *bp && *bp <= '7'); 90355682Smarkm *mp++ = n; 90455682Smarkm } 90555682Smarkm else switch (*bp++) { 90655682Smarkm case 'b': case 'B': 90755682Smarkm *mp++ = '\b'; 90855682Smarkm break; 90955682Smarkm case 't': case 'T': 91055682Smarkm *mp++ = '\t'; 91155682Smarkm break; 91255682Smarkm case 'n': case 'N': 91355682Smarkm *mp++ = '\n'; 91455682Smarkm break; 91555682Smarkm case 'f': case 'F': 91655682Smarkm *mp++ = '\f'; 91755682Smarkm break; 91855682Smarkm case 'r': case 'R': 91955682Smarkm *mp++ = '\r'; 92055682Smarkm break; 92155682Smarkm case 'e': case 'E': 92255682Smarkm *mp++ = ESC; 92355682Smarkm break; 92455682Smarkm case 'c': case 'C': 92555682Smarkm *mp++ = ':'; 92655682Smarkm break; 92755682Smarkm default: 92855682Smarkm /* 92955682Smarkm * Catches '\', '^', and 93055682Smarkm * everything else. 93155682Smarkm */ 93255682Smarkm *mp++ = *(bp-1); 93355682Smarkm break; 93455682Smarkm } 93555682Smarkm } else 93655682Smarkm *mp++ = *bp++; 93755682Smarkm m_room--; 93855682Smarkm 93955682Smarkm /* 94055682Smarkm * Enforce loop invariant: if no room left in current 94155682Smarkm * buffer, try to get some more. 94255682Smarkm */ 94355682Smarkm if (m_room == 0) { 94455682Smarkm size_t size = mp - mem; 94555682Smarkm 946233294Sstas if ((nmem = realloc(mem, size + SFRAG)) == NULL) { 947233294Sstas free(mem); 94855682Smarkm return (-2); 949233294Sstas } 950233294Sstas mem = nmem; 95155682Smarkm m_room = SFRAG; 95255682Smarkm mp = mem + size; 95355682Smarkm } 95455682Smarkm } 95555682Smarkm *mp++ = '\0'; /* loop invariant let's us do this */ 95655682Smarkm m_room--; 95755682Smarkm len = mp - mem - 1; 95855682Smarkm 95955682Smarkm /* 96055682Smarkm * Give back any extra memory and return value and success. 96155682Smarkm */ 962233294Sstas if (m_room != 0) { 963233294Sstas if ((nmem = realloc(mem, (size_t)(mp - mem))) == NULL) { 964233294Sstas free(mem); 96555682Smarkm return (-2); 966233294Sstas } 967233294Sstas mem = nmem; 968233294Sstas } 96955682Smarkm *str = mem; 97055682Smarkm return (len); 97155682Smarkm} 97255682Smarkm 97355682Smarkm/* 97455682Smarkm * Cgetustr retrieves the value of the string capability cap from the 97555682Smarkm * capability record pointed to by buf. The difference between cgetustr() 97655682Smarkm * and cgetstr() is that cgetustr does not decode escapes but rather treats 977233294Sstas * all characters literally. A pointer to a NUL terminated malloc'd 978233294Sstas * copy of the string is returned in the char pointed to by str. The 97955682Smarkm * length of the string not including the trailing NUL is returned on success, 980233294Sstas * -1 if the requested string capability couldn't be found, -2 if a system 98155682Smarkm * error was encountered (storage allocation failure). 98255682Smarkm */ 983233294SstasROKEN_LIB_FUNCTION int ROKEN_LIB_CALL 98455682Smarkmcgetustr(char *buf, const char *cap, char **str) 98555682Smarkm{ 98655682Smarkm u_int m_room; 98755682Smarkm const char *bp; 98855682Smarkm char *mp; 98955682Smarkm int len; 99055682Smarkm char *mem; 99155682Smarkm 99255682Smarkm /* 99355682Smarkm * Find string capability cap 99455682Smarkm */ 99555682Smarkm if ((bp = cgetcap(buf, cap, '=')) == NULL) 99655682Smarkm return (-1); 99755682Smarkm 99855682Smarkm /* 99955682Smarkm * Conversion / storage allocation loop ... Allocate memory in 100055682Smarkm * chunks SFRAG in size. 100155682Smarkm */ 100255682Smarkm if ((mem = malloc(SFRAG)) == NULL) { 100355682Smarkm errno = ENOMEM; 100455682Smarkm return (-2); /* couldn't even allocate the first fragment */ 100555682Smarkm } 100655682Smarkm m_room = SFRAG; 100755682Smarkm mp = mem; 100855682Smarkm 100955682Smarkm while (*bp != ':' && *bp != '\0') { 101055682Smarkm /* 101155682Smarkm * Loop invariants: 101255682Smarkm * There is always room for one more character in mem. 101355682Smarkm * Mp always points just past last character in mem. 101455682Smarkm * Bp always points at next character in buf. 101555682Smarkm */ 101655682Smarkm *mp++ = *bp++; 101755682Smarkm m_room--; 101855682Smarkm 101955682Smarkm /* 102055682Smarkm * Enforce loop invariant: if no room left in current 102155682Smarkm * buffer, try to get some more. 102255682Smarkm */ 102355682Smarkm if (m_room == 0) { 102455682Smarkm size_t size = mp - mem; 102555682Smarkm 102655682Smarkm if ((mem = realloc(mem, size + SFRAG)) == NULL) 102755682Smarkm return (-2); 102855682Smarkm m_room = SFRAG; 102955682Smarkm mp = mem + size; 103055682Smarkm } 103155682Smarkm } 103255682Smarkm *mp++ = '\0'; /* loop invariant let's us do this */ 103355682Smarkm m_room--; 103455682Smarkm len = mp - mem - 1; 103555682Smarkm 103655682Smarkm /* 103755682Smarkm * Give back any extra memory and return value and success. 103855682Smarkm */ 103955682Smarkm if (m_room != 0) 104055682Smarkm if ((mem = realloc(mem, (size_t)(mp - mem))) == NULL) 104155682Smarkm return (-2); 104255682Smarkm *str = mem; 104355682Smarkm return (len); 104455682Smarkm} 104555682Smarkm 104655682Smarkm/* 104755682Smarkm * Cgetnum retrieves the value of the numeric capability cap from the 104855682Smarkm * capability record pointed to by buf. The numeric value is returned in 104955682Smarkm * the long pointed to by num. 0 is returned on success, -1 if the requested 105055682Smarkm * numeric capability couldn't be found. 105155682Smarkm */ 1052233294SstasROKEN_LIB_FUNCTION int ROKEN_LIB_CALL 105355682Smarkmcgetnum(char *buf, const char *cap, long *num) 105455682Smarkm{ 105555682Smarkm long n; 105655682Smarkm int base, digit; 105755682Smarkm const char *bp; 105855682Smarkm 105955682Smarkm /* 106055682Smarkm * Find numeric capability cap 106155682Smarkm */ 106255682Smarkm bp = cgetcap(buf, cap, '#'); 106355682Smarkm if (bp == NULL) 106455682Smarkm return (-1); 106555682Smarkm 106655682Smarkm /* 106755682Smarkm * Look at value and determine numeric base: 106855682Smarkm * 0x... or 0X... hexadecimal, 106955682Smarkm * else 0... octal, 107055682Smarkm * else decimal. 107155682Smarkm */ 107255682Smarkm if (*bp == '0') { 107355682Smarkm bp++; 107455682Smarkm if (*bp == 'x' || *bp == 'X') { 107555682Smarkm bp++; 107655682Smarkm base = 16; 107755682Smarkm } else 107855682Smarkm base = 8; 107955682Smarkm } else 108055682Smarkm base = 10; 108155682Smarkm 108255682Smarkm /* 108355682Smarkm * Conversion loop ... 108455682Smarkm */ 108555682Smarkm n = 0; 108655682Smarkm for (;;) { 108755682Smarkm if ('0' <= *bp && *bp <= '9') 108855682Smarkm digit = *bp - '0'; 108955682Smarkm else if ('a' <= *bp && *bp <= 'f') 109055682Smarkm digit = 10 + *bp - 'a'; 109155682Smarkm else if ('A' <= *bp && *bp <= 'F') 109255682Smarkm digit = 10 + *bp - 'A'; 109355682Smarkm else 109455682Smarkm break; 109555682Smarkm 109655682Smarkm if (digit >= base) 109755682Smarkm break; 109855682Smarkm 109955682Smarkm n = n * base + digit; 110055682Smarkm bp++; 110155682Smarkm } 110255682Smarkm 110355682Smarkm /* 110455682Smarkm * Return value and success. 110555682Smarkm */ 110655682Smarkm *num = n; 110755682Smarkm return (0); 110855682Smarkm} 110955682Smarkm 111055682Smarkm 111155682Smarkm/* 111255682Smarkm * Compare name field of record. 111355682Smarkm */ 111455682Smarkmstatic int 111555682Smarkmnfcmp(char *nf, char *rec) 111655682Smarkm{ 111755682Smarkm char *cp, tmp; 111855682Smarkm int ret; 1119233294Sstas 112055682Smarkm for (cp = rec; *cp != ':'; cp++) 112155682Smarkm ; 1122233294Sstas 112355682Smarkm tmp = *(cp + 1); 112455682Smarkm *(cp + 1) = '\0'; 112555682Smarkm ret = strcmp(nf, rec); 112655682Smarkm *(cp + 1) = tmp; 112755682Smarkm 112855682Smarkm return (ret); 112955682Smarkm} 1130