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#ifdef HAVE_CONFIG_H 3655682Smarkm#include <config.h> 3755682Smarkm#endif 3855682Smarkm#include "roken.h" 39178825SdfrRCSID("$Id: getcap.c 22071 2007-11-14 20:04:50Z lha $"); 4055682Smarkm 4155682Smarkm#include <sys/types.h> 4255682Smarkm#include <ctype.h> 4355682Smarkm#if defined(HAVE_DB_185_H) 4455682Smarkm#include <db_185.h> 4555682Smarkm#elif defined(HAVE_DB_H) 4655682Smarkm#include <db.h> 4755682Smarkm#endif 4855682Smarkm#include <errno.h> 4955682Smarkm#include <fcntl.h> 5055682Smarkm#include <limits.h> 5155682Smarkm#include <stdio.h> 5255682Smarkm#include <stdlib.h> 5355682Smarkm#include <string.h> 5455682Smarkm#include <unistd.h> 5555682Smarkm 5655682Smarkm#define BFRAG 1024 5755682Smarkm#if 0 5855682Smarkm#define BSIZE 1024 5955682Smarkm#endif 6055682Smarkm#define ESC ('[' & 037) /* ASCII ESC */ 6155682Smarkm#define MAX_RECURSION 32 /* maximum getent recursion */ 6255682Smarkm#define SFRAG 100 /* cgetstr mallocs in SFRAG chunks */ 6355682Smarkm 6455682Smarkm#define RECOK (char)0 6555682Smarkm#define TCERR (char)1 6655682Smarkm#define SHADOW (char)2 6755682Smarkm 6855682Smarkmstatic size_t topreclen; /* toprec length */ 6955682Smarkmstatic char *toprec; /* Additional record specified by cgetset() */ 7055682Smarkmstatic int gottoprec; /* Flag indicating retrieval of toprecord */ 7155682Smarkm 72178825Sdfr#if 0 /* 73178825Sdfr * Don't use db support unless it's build into libc but we don't 74178825Sdfr * check for that now, so just disable the code. 75178825Sdfr */ 7655682Smarkm#if defined(HAVE_DBOPEN) && defined(HAVE_DB_H) 7755682Smarkm#define USE_DB 7855682Smarkm#endif 79178825Sdfr#endif 8055682Smarkm 8155682Smarkm#ifdef USE_DB 8255682Smarkmstatic int cdbget (DB *, char **, const char *); 8355682Smarkm#endif 8455682Smarkmstatic int getent (char **, size_t *, char **, int, const char *, int, char *); 8555682Smarkmstatic int nfcmp (char *, char *); 8655682Smarkm 8755682Smarkm 88178825Sdfrint ROKEN_LIB_FUNCTION cgetset(const char *ent); 89178825Sdfrchar *ROKEN_LIB_FUNCTION cgetcap(char *buf, const char *cap, int type); 90178825Sdfrint ROKEN_LIB_FUNCTION cgetent(char **buf, char **db_array, const char *name); 91178825Sdfrint ROKEN_LIB_FUNCTION cgetmatch(const char *buf, const char *name); 92178825Sdfrint ROKEN_LIB_FUNCTION cgetclose(void); 9355682Smarkm#if 0 9455682Smarkmint cgetfirst(char **buf, char **db_array); 9555682Smarkmint cgetnext(char **bp, char **db_array); 9655682Smarkm#endif 97178825Sdfrint ROKEN_LIB_FUNCTION cgetstr(char *buf, const char *cap, char **str); 98178825Sdfrint ROKEN_LIB_FUNCTION cgetustr(char *buf, const char *cap, char **str); 99178825Sdfrint ROKEN_LIB_FUNCTION cgetnum(char *buf, const char *cap, long *num); 10055682Smarkm/* 10155682Smarkm * Cgetset() allows the addition of a user specified buffer to be added 10255682Smarkm * to the database array, in effect "pushing" the buffer on top of the 10355682Smarkm * virtual database. 0 is returned on success, -1 on failure. 10455682Smarkm */ 105178825Sdfrint ROKEN_LIB_FUNCTION 10655682Smarkmcgetset(const char *ent) 10755682Smarkm{ 10855682Smarkm const char *source, *check; 10955682Smarkm char *dest; 11055682Smarkm 11155682Smarkm if (ent == NULL) { 11255682Smarkm if (toprec) 11355682Smarkm free(toprec); 11455682Smarkm toprec = NULL; 11555682Smarkm topreclen = 0; 11655682Smarkm return (0); 11755682Smarkm } 11855682Smarkm topreclen = strlen(ent); 11955682Smarkm if ((toprec = malloc (topreclen + 1)) == NULL) { 12055682Smarkm errno = ENOMEM; 12155682Smarkm return (-1); 12255682Smarkm } 12355682Smarkm gottoprec = 0; 12455682Smarkm 12555682Smarkm source=ent; 12655682Smarkm dest=toprec; 12755682Smarkm while (*source) { /* Strip whitespace */ 12855682Smarkm *dest++ = *source++; /* Do not check first field */ 12955682Smarkm while (*source == ':') { 13055682Smarkm check=source+1; 13155682Smarkm while (*check && (isspace((unsigned char)*check) || 13255682Smarkm (*check=='\\' && isspace((unsigned char)check[1])))) 13355682Smarkm ++check; 13455682Smarkm if( *check == ':' ) 13555682Smarkm source=check; 13655682Smarkm else 13755682Smarkm break; 13855682Smarkm 13955682Smarkm } 14055682Smarkm } 14155682Smarkm *dest=0; 14255682Smarkm 14355682Smarkm return (0); 14455682Smarkm} 14555682Smarkm 14655682Smarkm/* 14755682Smarkm * Cgetcap searches the capability record buf for the capability cap with 14855682Smarkm * type `type'. A pointer to the value of cap is returned on success, NULL 14955682Smarkm * if the requested capability couldn't be found. 15055682Smarkm * 15155682Smarkm * Specifying a type of ':' means that nothing should follow cap (:cap:). 15255682Smarkm * In this case a pointer to the terminating ':' or NUL will be returned if 15355682Smarkm * cap is found. 15455682Smarkm * 15555682Smarkm * If (cap, '@') or (cap, terminator, '@') is found before (cap, terminator) 15655682Smarkm * return NULL. 15755682Smarkm */ 158178825Sdfrchar * ROKEN_LIB_FUNCTION 15955682Smarkmcgetcap(char *buf, const char *cap, int type) 16055682Smarkm{ 16155682Smarkm char *bp; 16255682Smarkm const char *cp; 16355682Smarkm 16455682Smarkm bp = buf; 16555682Smarkm for (;;) { 16655682Smarkm /* 16755682Smarkm * Skip past the current capability field - it's either the 16855682Smarkm * name field if this is the first time through the loop, or 16955682Smarkm * the remainder of a field whose name failed to match cap. 17055682Smarkm */ 17155682Smarkm for (;;) 17255682Smarkm if (*bp == '\0') 17355682Smarkm return (NULL); 17455682Smarkm else 17555682Smarkm if (*bp++ == ':') 17655682Smarkm break; 17755682Smarkm 17855682Smarkm /* 17955682Smarkm * Try to match (cap, type) in buf. 18055682Smarkm */ 18155682Smarkm for (cp = cap; *cp == *bp && *bp != '\0'; cp++, bp++) 18255682Smarkm continue; 18355682Smarkm if (*cp != '\0') 18455682Smarkm continue; 18555682Smarkm if (*bp == '@') 18655682Smarkm return (NULL); 18755682Smarkm if (type == ':') { 18855682Smarkm if (*bp != '\0' && *bp != ':') 18955682Smarkm continue; 19055682Smarkm return(bp); 19155682Smarkm } 19255682Smarkm if (*bp != type) 19355682Smarkm continue; 19455682Smarkm bp++; 19555682Smarkm return (*bp == '@' ? NULL : bp); 19655682Smarkm } 19755682Smarkm /* NOTREACHED */ 19855682Smarkm} 19955682Smarkm 20055682Smarkm/* 20155682Smarkm * Cgetent extracts the capability record name from the NULL terminated file 20255682Smarkm * array db_array and returns a pointer to a malloc'd copy of it in buf. 20355682Smarkm * Buf must be retained through all subsequent calls to cgetcap, cgetnum, 20455682Smarkm * cgetflag, and cgetstr, but may then be free'd. 0 is returned on success, 20555682Smarkm * -1 if the requested record couldn't be found, -2 if a system error was 20655682Smarkm * encountered (couldn't open/read a file, etc.), and -3 if a potential 20755682Smarkm * reference loop is detected. 20855682Smarkm */ 209178825Sdfrint ROKEN_LIB_FUNCTION 21055682Smarkmcgetent(char **buf, char **db_array, const char *name) 21155682Smarkm{ 21255682Smarkm size_t dummy; 21355682Smarkm 21455682Smarkm return (getent(buf, &dummy, db_array, -1, name, 0, NULL)); 21555682Smarkm} 21655682Smarkm 21755682Smarkm/* 21855682Smarkm * Getent implements the functions of cgetent. If fd is non-negative, 21955682Smarkm * *db_array has already been opened and fd is the open file descriptor. We 22055682Smarkm * do this to save time and avoid using up file descriptors for tc= 22155682Smarkm * recursions. 22255682Smarkm * 22355682Smarkm * Getent returns the same success/failure codes as cgetent. On success, a 22455682Smarkm * pointer to a malloc'ed capability record with all tc= capabilities fully 22555682Smarkm * expanded and its length (not including trailing ASCII NUL) are left in 22655682Smarkm * *cap and *len. 22755682Smarkm * 22855682Smarkm * Basic algorithm: 22955682Smarkm * + Allocate memory incrementally as needed in chunks of size BFRAG 23055682Smarkm * for capability buffer. 23155682Smarkm * + Recurse for each tc=name and interpolate result. Stop when all 23255682Smarkm * names interpolated, a name can't be found, or depth exceeds 23355682Smarkm * MAX_RECURSION. 23455682Smarkm */ 23555682Smarkmstatic int 23655682Smarkmgetent(char **cap, size_t *len, char **db_array, int fd, 23755682Smarkm const char *name, int depth, char *nfield) 23855682Smarkm{ 23955682Smarkm char *r_end, *rp = NULL, **db_p; /* pacify gcc */ 24055682Smarkm int myfd = 0, eof, foundit; 24155682Smarkm char *record; 24255682Smarkm int tc_not_resolved; 24355682Smarkm 24455682Smarkm /* 24555682Smarkm * Return with ``loop detected'' error if we've recursed more than 24655682Smarkm * MAX_RECURSION times. 24755682Smarkm */ 24855682Smarkm if (depth > MAX_RECURSION) 24955682Smarkm return (-3); 25055682Smarkm 25155682Smarkm /* 25255682Smarkm * Check if we have a top record from cgetset(). 25355682Smarkm */ 25455682Smarkm if (depth == 0 && toprec != NULL && cgetmatch(toprec, name) == 0) { 255120945Snectar size_t len = topreclen + BFRAG; 256120945Snectar if ((record = malloc (len)) == NULL) { 25755682Smarkm errno = ENOMEM; 25855682Smarkm return (-2); 25955682Smarkm } 260120945Snectar (void)strlcpy(record, toprec, len); 26155682Smarkm db_p = db_array; 26255682Smarkm rp = record + topreclen + 1; 26355682Smarkm r_end = rp + BFRAG; 26455682Smarkm goto tc_exp; 26555682Smarkm } 26655682Smarkm /* 26755682Smarkm * Allocate first chunk of memory. 26855682Smarkm */ 26955682Smarkm if ((record = malloc(BFRAG)) == NULL) { 27055682Smarkm errno = ENOMEM; 27155682Smarkm return (-2); 27255682Smarkm } 27355682Smarkm r_end = record + BFRAG; 27455682Smarkm foundit = 0; 27555682Smarkm /* 27655682Smarkm * Loop through database array until finding the record. 27755682Smarkm */ 27855682Smarkm 27955682Smarkm for (db_p = db_array; *db_p != NULL; db_p++) { 28055682Smarkm eof = 0; 28155682Smarkm 28255682Smarkm /* 28355682Smarkm * Open database if not already open. 28455682Smarkm */ 28555682Smarkm 28655682Smarkm if (fd >= 0) { 28755682Smarkm (void)lseek(fd, (off_t)0, SEEK_SET); 28855682Smarkm } else { 28955682Smarkm#ifdef USE_DB 29055682Smarkm char pbuf[_POSIX_PATH_MAX]; 29155682Smarkm char *cbuf; 29255682Smarkm size_t clen; 29355682Smarkm int retval; 29455682Smarkm DB *capdbp; 29555682Smarkm 29655682Smarkm (void)snprintf(pbuf, sizeof(pbuf), "%s.db", *db_p); 29755682Smarkm if ((capdbp = dbopen(pbuf, O_RDONLY, 0, DB_HASH, 0)) 29855682Smarkm != NULL) { 29955682Smarkm free(record); 30055682Smarkm retval = cdbget(capdbp, &record, name); 30155682Smarkm if (retval < 0) { 30255682Smarkm /* no record available */ 30355682Smarkm (void)capdbp->close(capdbp); 30455682Smarkm return (retval); 30555682Smarkm } 30655682Smarkm /* save the data; close frees it */ 30755682Smarkm clen = strlen(record); 30855682Smarkm cbuf = malloc(clen + 1); 309178825Sdfr if (cbuf == NULL) 310178825Sdfr return (-2); 31155682Smarkm memmove(cbuf, record, clen + 1); 31255682Smarkm if (capdbp->close(capdbp) < 0) { 31355682Smarkm free(cbuf); 31455682Smarkm return (-2); 31555682Smarkm } 31655682Smarkm *len = clen; 31755682Smarkm *cap = cbuf; 31855682Smarkm return (retval); 31955682Smarkm } else 32055682Smarkm#endif 32155682Smarkm { 32255682Smarkm fd = open(*db_p, O_RDONLY, 0); 32355682Smarkm if (fd < 0) { 32455682Smarkm /* No error on unfound file. */ 32555682Smarkm continue; 32655682Smarkm } 32755682Smarkm myfd = 1; 32855682Smarkm } 32955682Smarkm } 33055682Smarkm /* 33155682Smarkm * Find the requested capability record ... 33255682Smarkm */ 33355682Smarkm { 33455682Smarkm char buf[BUFSIZ]; 33555682Smarkm char *b_end, *bp, *cp; 33655682Smarkm int c, slash; 33755682Smarkm 33855682Smarkm /* 33955682Smarkm * Loop invariants: 34055682Smarkm * There is always room for one more character in record. 34155682Smarkm * R_end always points just past end of record. 34255682Smarkm * Rp always points just past last character in record. 34355682Smarkm * B_end always points just past last character in buf. 34455682Smarkm * Bp always points at next character in buf. 34555682Smarkm * Cp remembers where the last colon was. 34655682Smarkm */ 34755682Smarkm b_end = buf; 34855682Smarkm bp = buf; 34955682Smarkm cp = 0; 35055682Smarkm slash = 0; 35155682Smarkm for (;;) { 35255682Smarkm 35355682Smarkm /* 35455682Smarkm * Read in a line implementing (\, newline) 35555682Smarkm * line continuation. 35655682Smarkm */ 35755682Smarkm rp = record; 35855682Smarkm for (;;) { 35955682Smarkm if (bp >= b_end) { 36055682Smarkm int n; 36155682Smarkm 36255682Smarkm n = read(fd, buf, sizeof(buf)); 36355682Smarkm if (n <= 0) { 36455682Smarkm if (myfd) 36555682Smarkm (void)close(fd); 36655682Smarkm if (n < 0) { 36755682Smarkm free(record); 36855682Smarkm return (-2); 36955682Smarkm } else { 37055682Smarkm fd = -1; 37155682Smarkm eof = 1; 37255682Smarkm break; 37355682Smarkm } 37455682Smarkm } 37555682Smarkm b_end = buf+n; 37655682Smarkm bp = buf; 37755682Smarkm } 37855682Smarkm 37955682Smarkm c = *bp++; 38055682Smarkm if (c == '\n') { 38155682Smarkm if (slash) { 38255682Smarkm slash = 0; 38355682Smarkm rp--; 38455682Smarkm continue; 38555682Smarkm } else 38655682Smarkm break; 38755682Smarkm } 38855682Smarkm if (slash) { 38955682Smarkm slash = 0; 39055682Smarkm cp = 0; 39155682Smarkm } 39255682Smarkm if (c == ':') { 39355682Smarkm /* 39455682Smarkm * If the field was `empty' (i.e. 39555682Smarkm * contained only white space), back up 39655682Smarkm * to the colon (eliminating the 39755682Smarkm * field). 39855682Smarkm */ 39955682Smarkm if (cp) 40055682Smarkm rp = cp; 40155682Smarkm else 40255682Smarkm cp = rp; 40355682Smarkm } else if (c == '\\') { 40455682Smarkm slash = 1; 40555682Smarkm } else if (c != ' ' && c != '\t') { 40655682Smarkm /* 40755682Smarkm * Forget where the colon was, as this 40855682Smarkm * is not an empty field. 40955682Smarkm */ 41055682Smarkm cp = 0; 41155682Smarkm } 41255682Smarkm *rp++ = c; 41355682Smarkm 41455682Smarkm /* 41555682Smarkm * Enforce loop invariant: if no room 41655682Smarkm * left in record buffer, try to get 41755682Smarkm * some more. 41855682Smarkm */ 41955682Smarkm if (rp >= r_end) { 42055682Smarkm u_int pos; 42155682Smarkm size_t newsize; 42255682Smarkm 42355682Smarkm pos = rp - record; 42455682Smarkm newsize = r_end - record + BFRAG; 42555682Smarkm record = realloc(record, newsize); 42655682Smarkm if (record == NULL) { 42755682Smarkm errno = ENOMEM; 42855682Smarkm if (myfd) 42955682Smarkm (void)close(fd); 43055682Smarkm return (-2); 43155682Smarkm } 43255682Smarkm r_end = record + newsize; 43355682Smarkm rp = record + pos; 43455682Smarkm } 43555682Smarkm } 43655682Smarkm /* Eliminate any white space after the last colon. */ 43755682Smarkm if (cp) 43855682Smarkm rp = cp + 1; 43955682Smarkm /* Loop invariant lets us do this. */ 44055682Smarkm *rp++ = '\0'; 44155682Smarkm 44255682Smarkm /* 44355682Smarkm * If encountered eof check next file. 44455682Smarkm */ 44555682Smarkm if (eof) 44655682Smarkm break; 44755682Smarkm 44855682Smarkm /* 44955682Smarkm * Toss blank lines and comments. 45055682Smarkm */ 45155682Smarkm if (*record == '\0' || *record == '#') 45255682Smarkm continue; 45355682Smarkm 45455682Smarkm /* 45555682Smarkm * See if this is the record we want ... 45655682Smarkm */ 45755682Smarkm if (cgetmatch(record, name) == 0) { 45855682Smarkm if (nfield == NULL || !nfcmp(nfield, record)) { 45955682Smarkm foundit = 1; 46055682Smarkm break; /* found it! */ 46155682Smarkm } 46255682Smarkm } 46355682Smarkm } 46455682Smarkm } 46555682Smarkm if (foundit) 46655682Smarkm break; 46755682Smarkm } 46855682Smarkm 46955682Smarkm if (!foundit) 47055682Smarkm return (-1); 47155682Smarkm 47255682Smarkm /* 47355682Smarkm * Got the capability record, but now we have to expand all tc=name 47455682Smarkm * references in it ... 47555682Smarkm */ 47655682Smarkm tc_exp: { 47755682Smarkm char *newicap, *s; 47855682Smarkm size_t ilen, newilen; 47955682Smarkm int diff, iret, tclen; 48055682Smarkm char *icap, *scan, *tc, *tcstart, *tcend; 48155682Smarkm 48255682Smarkm /* 48355682Smarkm * Loop invariants: 48455682Smarkm * There is room for one more character in record. 48555682Smarkm * R_end points just past end of record. 48655682Smarkm * Rp points just past last character in record. 48755682Smarkm * Scan points at remainder of record that needs to be 48855682Smarkm * scanned for tc=name constructs. 48955682Smarkm */ 49055682Smarkm scan = record; 49155682Smarkm tc_not_resolved = 0; 49255682Smarkm for (;;) { 49355682Smarkm if ((tc = cgetcap(scan, "tc", '=')) == NULL) 49455682Smarkm break; 49555682Smarkm 49655682Smarkm /* 49755682Smarkm * Find end of tc=name and stomp on the trailing `:' 49855682Smarkm * (if present) so we can use it to call ourselves. 49955682Smarkm */ 50055682Smarkm s = tc; 50155682Smarkm for (;;) 50255682Smarkm if (*s == '\0') 50355682Smarkm break; 50455682Smarkm else 50555682Smarkm if (*s++ == ':') { 50655682Smarkm *(s - 1) = '\0'; 50755682Smarkm break; 50855682Smarkm } 50955682Smarkm tcstart = tc - 3; 51055682Smarkm tclen = s - tcstart; 51155682Smarkm tcend = s; 51255682Smarkm 51355682Smarkm iret = getent(&icap, &ilen, db_p, fd, tc, depth+1, 51455682Smarkm NULL); 51555682Smarkm newicap = icap; /* Put into a register. */ 51655682Smarkm newilen = ilen; 51755682Smarkm if (iret != 0) { 51855682Smarkm /* an error */ 51955682Smarkm if (iret < -1) { 52055682Smarkm if (myfd) 52155682Smarkm (void)close(fd); 52255682Smarkm free(record); 52355682Smarkm return (iret); 52455682Smarkm } 52555682Smarkm if (iret == 1) 52655682Smarkm tc_not_resolved = 1; 52755682Smarkm /* couldn't resolve tc */ 52855682Smarkm if (iret == -1) { 52955682Smarkm *(s - 1) = ':'; 53055682Smarkm scan = s - 1; 53155682Smarkm tc_not_resolved = 1; 53255682Smarkm continue; 53355682Smarkm 53455682Smarkm } 53555682Smarkm } 53655682Smarkm /* not interested in name field of tc'ed record */ 53755682Smarkm s = newicap; 53855682Smarkm for (;;) 53955682Smarkm if (*s == '\0') 54055682Smarkm break; 54155682Smarkm else 54255682Smarkm if (*s++ == ':') 54355682Smarkm break; 54455682Smarkm newilen -= s - newicap; 54555682Smarkm newicap = s; 54655682Smarkm 54755682Smarkm /* make sure interpolated record is `:'-terminated */ 54855682Smarkm s += newilen; 54955682Smarkm if (*(s-1) != ':') { 55055682Smarkm *s = ':'; /* overwrite NUL with : */ 55155682Smarkm newilen++; 55255682Smarkm } 55355682Smarkm 55455682Smarkm /* 55555682Smarkm * Make sure there's enough room to insert the 55655682Smarkm * new record. 55755682Smarkm */ 55855682Smarkm diff = newilen - tclen; 55955682Smarkm if (diff >= r_end - rp) { 56055682Smarkm u_int pos, tcpos, tcposend; 56155682Smarkm size_t newsize; 56255682Smarkm 56355682Smarkm pos = rp - record; 56455682Smarkm newsize = r_end - record + diff + BFRAG; 56555682Smarkm tcpos = tcstart - record; 56655682Smarkm tcposend = tcend - record; 56755682Smarkm record = realloc(record, newsize); 56855682Smarkm if (record == NULL) { 56955682Smarkm errno = ENOMEM; 57055682Smarkm if (myfd) 57155682Smarkm (void)close(fd); 57255682Smarkm free(icap); 57355682Smarkm return (-2); 57455682Smarkm } 57555682Smarkm r_end = record + newsize; 57655682Smarkm rp = record + pos; 57755682Smarkm tcstart = record + tcpos; 57855682Smarkm tcend = record + tcposend; 57955682Smarkm } 58055682Smarkm 58155682Smarkm /* 58255682Smarkm * Insert tc'ed record into our record. 58355682Smarkm */ 58455682Smarkm s = tcstart + newilen; 58555682Smarkm memmove(s, tcend, (size_t)(rp - tcend)); 58655682Smarkm memmove(tcstart, newicap, newilen); 58755682Smarkm rp += diff; 58855682Smarkm free(icap); 58955682Smarkm 59055682Smarkm /* 59155682Smarkm * Start scan on `:' so next cgetcap works properly 59255682Smarkm * (cgetcap always skips first field). 59355682Smarkm */ 59455682Smarkm scan = s-1; 59555682Smarkm } 59655682Smarkm 59755682Smarkm } 59855682Smarkm /* 59955682Smarkm * Close file (if we opened it), give back any extra memory, and 60055682Smarkm * return capability, length and success. 60155682Smarkm */ 60255682Smarkm if (myfd) 60355682Smarkm (void)close(fd); 60455682Smarkm *len = rp - record - 1; /* don't count NUL */ 60555682Smarkm if (r_end > rp) 60655682Smarkm if ((record = 60755682Smarkm realloc(record, (size_t)(rp - record))) == NULL) { 60855682Smarkm errno = ENOMEM; 60955682Smarkm return (-2); 61055682Smarkm } 61155682Smarkm 61255682Smarkm *cap = record; 61355682Smarkm if (tc_not_resolved) 61455682Smarkm return (1); 61555682Smarkm return (0); 61655682Smarkm} 61755682Smarkm 61855682Smarkm#ifdef USE_DB 61955682Smarkmstatic int 62055682Smarkmcdbget(DB *capdbp, char **bp, const char *name) 62155682Smarkm{ 62255682Smarkm DBT key; 62355682Smarkm DBT data; 62455682Smarkm 62555682Smarkm /* LINTED key is not modified */ 62655682Smarkm key.data = (char *)name; 62755682Smarkm key.size = strlen(name); 62855682Smarkm 62955682Smarkm for (;;) { 63055682Smarkm /* Get the reference. */ 63155682Smarkm switch(capdbp->get(capdbp, &key, &data, 0)) { 63255682Smarkm case -1: 63355682Smarkm return (-2); 63455682Smarkm case 1: 63555682Smarkm return (-1); 63655682Smarkm } 63755682Smarkm 63855682Smarkm /* If not an index to another record, leave. */ 63955682Smarkm if (((char *)data.data)[0] != SHADOW) 64055682Smarkm break; 64155682Smarkm 64255682Smarkm key.data = (char *)data.data + 1; 64355682Smarkm key.size = data.size - 1; 64455682Smarkm } 64555682Smarkm 64655682Smarkm *bp = (char *)data.data + 1; 64755682Smarkm return (((char *)(data.data))[0] == TCERR ? 1 : 0); 64855682Smarkm} 64955682Smarkm#endif /* USE_DB */ 65055682Smarkm 65155682Smarkm/* 65255682Smarkm * Cgetmatch will return 0 if name is one of the names of the capability 65355682Smarkm * record buf, -1 if not. 65455682Smarkm */ 65555682Smarkmint 65655682Smarkmcgetmatch(const char *buf, const char *name) 65755682Smarkm{ 65855682Smarkm const char *np, *bp; 65955682Smarkm 66055682Smarkm /* 66155682Smarkm * Start search at beginning of record. 66255682Smarkm */ 66355682Smarkm bp = buf; 66455682Smarkm for (;;) { 66555682Smarkm /* 66655682Smarkm * Try to match a record name. 66755682Smarkm */ 66855682Smarkm np = name; 66955682Smarkm for (;;) 67055682Smarkm if (*np == '\0') { 67155682Smarkm if (*bp == '|' || *bp == ':' || *bp == '\0') 67255682Smarkm return (0); 67355682Smarkm else 67455682Smarkm break; 67555682Smarkm } else 67655682Smarkm if (*bp++ != *np++) 67755682Smarkm break; 67855682Smarkm 67955682Smarkm /* 68055682Smarkm * Match failed, skip to next name in record. 68155682Smarkm */ 68255682Smarkm bp--; /* a '|' or ':' may have stopped the match */ 68355682Smarkm for (;;) 68455682Smarkm if (*bp == '\0' || *bp == ':') 68555682Smarkm return (-1); /* match failed totally */ 68655682Smarkm else 68755682Smarkm if (*bp++ == '|') 68855682Smarkm break; /* found next name */ 68955682Smarkm } 69055682Smarkm} 69155682Smarkm 69255682Smarkm#if 0 69355682Smarkmint 69455682Smarkmcgetfirst(char **buf, char **db_array) 69555682Smarkm{ 69655682Smarkm (void)cgetclose(); 69755682Smarkm return (cgetnext(buf, db_array)); 69855682Smarkm} 69955682Smarkm#endif 70055682Smarkm 70155682Smarkmstatic FILE *pfp; 70255682Smarkmstatic int slash; 70355682Smarkmstatic char **dbp; 70455682Smarkm 705178825Sdfrint ROKEN_LIB_FUNCTION 70655682Smarkmcgetclose(void) 70755682Smarkm{ 70855682Smarkm if (pfp != NULL) { 70955682Smarkm (void)fclose(pfp); 71055682Smarkm pfp = NULL; 71155682Smarkm } 71255682Smarkm dbp = NULL; 71355682Smarkm gottoprec = 0; 71455682Smarkm slash = 0; 71555682Smarkm return(0); 71655682Smarkm} 71755682Smarkm 71855682Smarkm#if 0 71955682Smarkm/* 72055682Smarkm * Cgetnext() gets either the first or next entry in the logical database 72155682Smarkm * specified by db_array. It returns 0 upon completion of the database, 1 72255682Smarkm * upon returning an entry with more remaining, and -1 if an error occurs. 72355682Smarkm */ 72455682Smarkmint 72555682Smarkmcgetnext(char **bp, char **db_array) 72655682Smarkm{ 72755682Smarkm size_t len; 72855682Smarkm int status, done; 72955682Smarkm char *cp, *line, *rp, *np, buf[BSIZE], nbuf[BSIZE]; 73055682Smarkm size_t dummy; 73155682Smarkm 73255682Smarkm if (dbp == NULL) 73355682Smarkm dbp = db_array; 73455682Smarkm 73555682Smarkm if (pfp == NULL && (pfp = fopen(*dbp, "r")) == NULL) { 73655682Smarkm (void)cgetclose(); 73755682Smarkm return (-1); 73855682Smarkm } 73955682Smarkm for(;;) { 74055682Smarkm if (toprec && !gottoprec) { 74155682Smarkm gottoprec = 1; 74255682Smarkm line = toprec; 74355682Smarkm } else { 74455682Smarkm line = fgetln(pfp, &len); 74555682Smarkm if (line == NULL && pfp) { 74655682Smarkm if (ferror(pfp)) { 74755682Smarkm (void)cgetclose(); 74855682Smarkm return (-1); 74955682Smarkm } else { 75055682Smarkm (void)fclose(pfp); 75155682Smarkm pfp = NULL; 75255682Smarkm if (*++dbp == NULL) { 75355682Smarkm (void)cgetclose(); 75455682Smarkm return (0); 75555682Smarkm } else if ((pfp = 75655682Smarkm fopen(*dbp, "r")) == NULL) { 75755682Smarkm (void)cgetclose(); 75855682Smarkm return (-1); 75955682Smarkm } else 76055682Smarkm continue; 76155682Smarkm } 76255682Smarkm } else 76355682Smarkm line[len - 1] = '\0'; 76455682Smarkm if (len == 1) { 76555682Smarkm slash = 0; 76655682Smarkm continue; 76755682Smarkm } 76855682Smarkm if (isspace((unsigned char)*line) || 76955682Smarkm *line == ':' || *line == '#' || slash) { 77055682Smarkm if (line[len - 2] == '\\') 77155682Smarkm slash = 1; 77255682Smarkm else 77355682Smarkm slash = 0; 77455682Smarkm continue; 77555682Smarkm } 77655682Smarkm if (line[len - 2] == '\\') 77755682Smarkm slash = 1; 77855682Smarkm else 77955682Smarkm slash = 0; 78055682Smarkm } 78155682Smarkm 78255682Smarkm 78355682Smarkm /* 78455682Smarkm * Line points to a name line. 78555682Smarkm */ 78655682Smarkm done = 0; 78755682Smarkm np = nbuf; 78855682Smarkm for (;;) { 78955682Smarkm for (cp = line; *cp != '\0'; cp++) { 79055682Smarkm if (*cp == ':') { 79155682Smarkm *np++ = ':'; 79255682Smarkm done = 1; 79355682Smarkm break; 79455682Smarkm } 79555682Smarkm if (*cp == '\\') 79655682Smarkm break; 79755682Smarkm *np++ = *cp; 79855682Smarkm } 79955682Smarkm if (done) { 80055682Smarkm *np = '\0'; 80155682Smarkm break; 80255682Smarkm } else { /* name field extends beyond the line */ 80355682Smarkm line = fgetln(pfp, &len); 80455682Smarkm if (line == NULL && pfp) { 80555682Smarkm if (ferror(pfp)) { 80655682Smarkm (void)cgetclose(); 80755682Smarkm return (-1); 80855682Smarkm } 80955682Smarkm (void)fclose(pfp); 81055682Smarkm pfp = NULL; 81155682Smarkm *np = '\0'; 81255682Smarkm break; 81355682Smarkm } else 81455682Smarkm line[len - 1] = '\0'; 81555682Smarkm } 81655682Smarkm } 81755682Smarkm rp = buf; 81855682Smarkm for(cp = nbuf; *cp != '\0'; cp++) 81955682Smarkm if (*cp == '|' || *cp == ':') 82055682Smarkm break; 82155682Smarkm else 82255682Smarkm *rp++ = *cp; 82355682Smarkm 82455682Smarkm *rp = '\0'; 82555682Smarkm /* 82655682Smarkm * XXX 82755682Smarkm * Last argument of getent here should be nbuf if we want true 82855682Smarkm * sequential access in the case of duplicates. 82955682Smarkm * With NULL, getent will return the first entry found 83055682Smarkm * rather than the duplicate entry record. This is a 83155682Smarkm * matter of semantics that should be resolved. 83255682Smarkm */ 83355682Smarkm status = getent(bp, &dummy, db_array, -1, buf, 0, NULL); 83455682Smarkm if (status == -2 || status == -3) 83555682Smarkm (void)cgetclose(); 83655682Smarkm 83755682Smarkm return (status + 1); 83855682Smarkm } 83955682Smarkm /* NOTREACHED */ 84055682Smarkm} 84155682Smarkm#endif 84255682Smarkm 84355682Smarkm/* 84455682Smarkm * Cgetstr retrieves the value of the string capability cap from the 84555682Smarkm * capability record pointed to by buf. A pointer to a decoded, NUL 84655682Smarkm * terminated, malloc'd copy of the string is returned in the char * 84755682Smarkm * pointed to by str. The length of the string not including the trailing 84855682Smarkm * NUL is returned on success, -1 if the requested string capability 84955682Smarkm * couldn't be found, -2 if a system error was encountered (storage 85055682Smarkm * allocation failure). 85155682Smarkm */ 852178825Sdfrint ROKEN_LIB_FUNCTION 85355682Smarkmcgetstr(char *buf, const char *cap, char **str) 85455682Smarkm{ 85555682Smarkm u_int m_room; 85655682Smarkm const char *bp; 85755682Smarkm char *mp; 85855682Smarkm int len; 85955682Smarkm char *mem; 86055682Smarkm 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 94655682Smarkm if ((mem = realloc(mem, size + SFRAG)) == NULL) 94755682Smarkm return (-2); 94855682Smarkm m_room = SFRAG; 94955682Smarkm mp = mem + size; 95055682Smarkm } 95155682Smarkm } 95255682Smarkm *mp++ = '\0'; /* loop invariant let's us do this */ 95355682Smarkm m_room--; 95455682Smarkm len = mp - mem - 1; 95555682Smarkm 95655682Smarkm /* 95755682Smarkm * Give back any extra memory and return value and success. 95855682Smarkm */ 95955682Smarkm if (m_room != 0) 96055682Smarkm if ((mem = realloc(mem, (size_t)(mp - mem))) == NULL) 96155682Smarkm return (-2); 96255682Smarkm *str = mem; 96355682Smarkm return (len); 96455682Smarkm} 96555682Smarkm 96655682Smarkm/* 96755682Smarkm * Cgetustr retrieves the value of the string capability cap from the 96855682Smarkm * capability record pointed to by buf. The difference between cgetustr() 96955682Smarkm * and cgetstr() is that cgetustr does not decode escapes but rather treats 97055682Smarkm * all characters literally. A pointer to a NUL terminated malloc'd 97155682Smarkm * copy of the string is returned in the char pointed to by str. The 97255682Smarkm * length of the string not including the trailing NUL is returned on success, 97355682Smarkm * -1 if the requested string capability couldn't be found, -2 if a system 97455682Smarkm * error was encountered (storage allocation failure). 97555682Smarkm */ 976178825Sdfrint ROKEN_LIB_FUNCTION 97755682Smarkmcgetustr(char *buf, const char *cap, char **str) 97855682Smarkm{ 97955682Smarkm u_int m_room; 98055682Smarkm const char *bp; 98155682Smarkm char *mp; 98255682Smarkm int len; 98355682Smarkm char *mem; 98455682Smarkm 98555682Smarkm /* 98655682Smarkm * Find string capability cap 98755682Smarkm */ 98855682Smarkm if ((bp = cgetcap(buf, cap, '=')) == NULL) 98955682Smarkm return (-1); 99055682Smarkm 99155682Smarkm /* 99255682Smarkm * Conversion / storage allocation loop ... Allocate memory in 99355682Smarkm * chunks SFRAG in size. 99455682Smarkm */ 99555682Smarkm if ((mem = malloc(SFRAG)) == NULL) { 99655682Smarkm errno = ENOMEM; 99755682Smarkm return (-2); /* couldn't even allocate the first fragment */ 99855682Smarkm } 99955682Smarkm m_room = SFRAG; 100055682Smarkm mp = mem; 100155682Smarkm 100255682Smarkm while (*bp != ':' && *bp != '\0') { 100355682Smarkm /* 100455682Smarkm * Loop invariants: 100555682Smarkm * There is always room for one more character in mem. 100655682Smarkm * Mp always points just past last character in mem. 100755682Smarkm * Bp always points at next character in buf. 100855682Smarkm */ 100955682Smarkm *mp++ = *bp++; 101055682Smarkm m_room--; 101155682Smarkm 101255682Smarkm /* 101355682Smarkm * Enforce loop invariant: if no room left in current 101455682Smarkm * buffer, try to get some more. 101555682Smarkm */ 101655682Smarkm if (m_room == 0) { 101755682Smarkm size_t size = mp - mem; 101855682Smarkm 101955682Smarkm if ((mem = realloc(mem, size + SFRAG)) == NULL) 102055682Smarkm return (-2); 102155682Smarkm m_room = SFRAG; 102255682Smarkm mp = mem + size; 102355682Smarkm } 102455682Smarkm } 102555682Smarkm *mp++ = '\0'; /* loop invariant let's us do this */ 102655682Smarkm m_room--; 102755682Smarkm len = mp - mem - 1; 102855682Smarkm 102955682Smarkm /* 103055682Smarkm * Give back any extra memory and return value and success. 103155682Smarkm */ 103255682Smarkm if (m_room != 0) 103355682Smarkm if ((mem = realloc(mem, (size_t)(mp - mem))) == NULL) 103455682Smarkm return (-2); 103555682Smarkm *str = mem; 103655682Smarkm return (len); 103755682Smarkm} 103855682Smarkm 103955682Smarkm/* 104055682Smarkm * Cgetnum retrieves the value of the numeric capability cap from the 104155682Smarkm * capability record pointed to by buf. The numeric value is returned in 104255682Smarkm * the long pointed to by num. 0 is returned on success, -1 if the requested 104355682Smarkm * numeric capability couldn't be found. 104455682Smarkm */ 1045178825Sdfrint ROKEN_LIB_FUNCTION 104655682Smarkmcgetnum(char *buf, const char *cap, long *num) 104755682Smarkm{ 104855682Smarkm long n; 104955682Smarkm int base, digit; 105055682Smarkm const char *bp; 105155682Smarkm 105255682Smarkm /* 105355682Smarkm * Find numeric capability cap 105455682Smarkm */ 105555682Smarkm bp = cgetcap(buf, cap, '#'); 105655682Smarkm if (bp == NULL) 105755682Smarkm return (-1); 105855682Smarkm 105955682Smarkm /* 106055682Smarkm * Look at value and determine numeric base: 106155682Smarkm * 0x... or 0X... hexadecimal, 106255682Smarkm * else 0... octal, 106355682Smarkm * else decimal. 106455682Smarkm */ 106555682Smarkm if (*bp == '0') { 106655682Smarkm bp++; 106755682Smarkm if (*bp == 'x' || *bp == 'X') { 106855682Smarkm bp++; 106955682Smarkm base = 16; 107055682Smarkm } else 107155682Smarkm base = 8; 107255682Smarkm } else 107355682Smarkm base = 10; 107455682Smarkm 107555682Smarkm /* 107655682Smarkm * Conversion loop ... 107755682Smarkm */ 107855682Smarkm n = 0; 107955682Smarkm for (;;) { 108055682Smarkm if ('0' <= *bp && *bp <= '9') 108155682Smarkm digit = *bp - '0'; 108255682Smarkm else if ('a' <= *bp && *bp <= 'f') 108355682Smarkm digit = 10 + *bp - 'a'; 108455682Smarkm else if ('A' <= *bp && *bp <= 'F') 108555682Smarkm digit = 10 + *bp - 'A'; 108655682Smarkm else 108755682Smarkm break; 108855682Smarkm 108955682Smarkm if (digit >= base) 109055682Smarkm break; 109155682Smarkm 109255682Smarkm n = n * base + digit; 109355682Smarkm bp++; 109455682Smarkm } 109555682Smarkm 109655682Smarkm /* 109755682Smarkm * Return value and success. 109855682Smarkm */ 109955682Smarkm *num = n; 110055682Smarkm return (0); 110155682Smarkm} 110255682Smarkm 110355682Smarkm 110455682Smarkm/* 110555682Smarkm * Compare name field of record. 110655682Smarkm */ 110755682Smarkmstatic int 110855682Smarkmnfcmp(char *nf, char *rec) 110955682Smarkm{ 111055682Smarkm char *cp, tmp; 111155682Smarkm int ret; 111255682Smarkm 111355682Smarkm for (cp = rec; *cp != ':'; cp++) 111455682Smarkm ; 111555682Smarkm 111655682Smarkm tmp = *(cp + 1); 111755682Smarkm *(cp + 1) = '\0'; 111855682Smarkm ret = strcmp(nf, rec); 111955682Smarkm *(cp + 1) = tmp; 112055682Smarkm 112155682Smarkm return (ret); 112255682Smarkm} 1123