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