|
|
1.1 ! cgd 1: /*-
! 2: * Copyright (c) 1992 The Regents of the University of California.
! 3: * All rights reserved.
! 4: *
! 5: * This code is derived from software contributed to Berkeley by
! 6: * Casey Leedom of Lawrence Livermore National Laboratory.
! 7: *
! 8: * Redistribution and use in source and binary forms, with or without
! 9: * modification, are permitted provided that the following conditions
! 10: * are met:
! 11: * 1. Redistributions of source code must retain the above copyright
! 12: * notice, this list of conditions and the following disclaimer.
! 13: * 2. Redistributions in binary form must reproduce the above copyright
! 14: * notice, this list of conditions and the following disclaimer in the
! 15: * documentation and/or other materials provided with the distribution.
! 16: * 3. All advertising materials mentioning features or use of this software
! 17: * must display the following acknowledgement:
! 18: * This product includes software developed by the University of
! 19: * California, Berkeley and its contributors.
! 20: * 4. Neither the name of the University nor the names of its contributors
! 21: * may be used to endorse or promote products derived from this software
! 22: * without specific prior written permission.
! 23: *
! 24: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
! 25: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
! 26: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
! 27: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
! 28: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
! 29: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
! 30: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
! 31: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
! 32: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
! 33: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
! 34: * SUCH DAMAGE.
! 35: */
! 36:
! 37: #if defined(LIBC_SCCS) && !defined(lint)
! 38: static char sccsid[] = "@(#)getcap.c 5.15 (Berkeley) 3/19/93";
! 39: #endif /* LIBC_SCCS and not lint */
! 40:
! 41: #include <sys/types.h>
! 42:
! 43: #include <ctype.h>
! 44: #include <db.h>
! 45: #include <errno.h>
! 46: #include <fcntl.h>
! 47: #include <limits.h>
! 48: #include <stdio.h>
! 49: #include <stdlib.h>
! 50: #include <string.h>
! 51: #include <unistd.h>
! 52:
! 53: #define BFRAG 1024
! 54: #define BSIZE 1024
! 55: #define ESC ('[' & 037) /* ASCII ESC */
! 56: #define MAX_RECURSION 32 /* maximum getent recursion */
! 57: #define SFRAG 100 /* cgetstr mallocs in SFRAG chunks */
! 58:
! 59: #define RECOK (char)0
! 60: #define TCERR (char)1
! 61: #define SHADOW (char)2
! 62:
! 63: static size_t topreclen; /* toprec length */
! 64: static char *toprec; /* Additional record specified by cgetset() */
! 65: static int gottoprec; /* Flag indicating retrieval of toprecord */
! 66:
! 67: static int cdbget __P((DB *, char **, char *));
! 68: static int getent __P((char **, u_int *, char **, int, char *, int, char *));
! 69: static int nfcmp __P((char *, char *));
! 70:
! 71: /*
! 72: * Cgetset() allows the addition of a user specified buffer to be added
! 73: * to the database array, in effect "pushing" the buffer on top of the
! 74: * virtual database. 0 is returned on success, -1 on failure.
! 75: */
! 76: int
! 77: cgetset(ent)
! 78: char *ent;
! 79: {
! 80: if (ent == NULL) {
! 81: if (toprec)
! 82: free(toprec);
! 83: toprec = NULL;
! 84: topreclen = 0;
! 85: return (0);
! 86: }
! 87: topreclen = strlen(ent);
! 88: if ((toprec = malloc (topreclen + 1)) == NULL) {
! 89: errno = ENOMEM;
! 90: return (-1);
! 91: }
! 92: gottoprec = 0;
! 93: (void)strcpy(toprec, ent);
! 94: return (0);
! 95: }
! 96:
! 97: /*
! 98: * Cgetcap searches the capability record buf for the capability cap with
! 99: * type `type'. A pointer to the value of cap is returned on success, NULL
! 100: * if the requested capability couldn't be found.
! 101: *
! 102: * Specifying a type of ':' means that nothing should follow cap (:cap:).
! 103: * In this case a pointer to the terminating ':' or NUL will be returned if
! 104: * cap is found.
! 105: *
! 106: * If (cap, '@') or (cap, terminator, '@') is found before (cap, terminator)
! 107: * return NULL.
! 108: */
! 109: char *
! 110: cgetcap(buf, cap, type)
! 111: char *buf, *cap;
! 112: int type;
! 113: {
! 114: register char *bp, *cp;
! 115:
! 116: bp = buf;
! 117: for (;;) {
! 118: /*
! 119: * Skip past the current capability field - it's either the
! 120: * name field if this is the first time through the loop, or
! 121: * the remainder of a field whose name failed to match cap.
! 122: */
! 123: for (;;)
! 124: if (*bp == '\0')
! 125: return (NULL);
! 126: else
! 127: if (*bp++ == ':')
! 128: break;
! 129:
! 130: /*
! 131: * Try to match (cap, type) in buf.
! 132: */
! 133: for (cp = cap; *cp == *bp && *bp != '\0'; cp++, bp++)
! 134: continue;
! 135: if (*cp != '\0')
! 136: continue;
! 137: if (*bp == '@')
! 138: return (NULL);
! 139: if (type == ':') {
! 140: if (*bp != '\0' && *bp != ':')
! 141: continue;
! 142: return(bp);
! 143: }
! 144: if (*bp != type)
! 145: continue;
! 146: bp++;
! 147: return (*bp == '@' ? NULL : bp);
! 148: }
! 149: /* NOTREACHED */
! 150: }
! 151:
! 152: /*
! 153: * Cgetent extracts the capability record name from the NULL terminated file
! 154: * array db_array and returns a pointer to a malloc'd copy of it in buf.
! 155: * Buf must be retained through all subsequent calls to cgetcap, cgetnum,
! 156: * cgetflag, and cgetstr, but may then be free'd. 0 is returned on success,
! 157: * -1 if the requested record couldn't be found, -2 if a system error was
! 158: * encountered (couldn't open/read a file, etc.), and -3 if a potential
! 159: * reference loop is detected.
! 160: */
! 161: int
! 162: cgetent(buf, db_array, name)
! 163: char **buf, **db_array, *name;
! 164: {
! 165: u_int dummy;
! 166:
! 167: return (getent(buf, &dummy, db_array, -1, name, 0, NULL));
! 168: }
! 169:
! 170: /*
! 171: * Getent implements the functions of cgetent. If fd is non-negative,
! 172: * *db_array has already been opened and fd is the open file descriptor. We
! 173: * do this to save time and avoid using up file descriptors for tc=
! 174: * recursions.
! 175: *
! 176: * Getent returns the same success/failure codes as cgetent. On success, a
! 177: * pointer to a malloc'ed capability record with all tc= capabilities fully
! 178: * expanded and its length (not including trailing ASCII NUL) are left in
! 179: * *cap and *len.
! 180: *
! 181: * Basic algorithm:
! 182: * + Allocate memory incrementally as needed in chunks of size BFRAG
! 183: * for capability buffer.
! 184: * + Recurse for each tc=name and interpolate result. Stop when all
! 185: * names interpolated, a name can't be found, or depth exceeds
! 186: * MAX_RECURSION.
! 187: */
! 188: static int
! 189: getent(cap, len, db_array, fd, name, depth, nfield)
! 190: char **cap, **db_array, *name, *nfield;
! 191: u_int *len;
! 192: int fd, depth;
! 193: {
! 194: DB *capdbp;
! 195: DBT key, data;
! 196: register char *r_end, *rp, **db_p;
! 197: int myfd, eof, foundit, retval;
! 198: char *record;
! 199: int tc_not_resolved;
! 200: char pbuf[_POSIX_PATH_MAX];
! 201:
! 202: /*
! 203: * Return with ``loop detected'' error if we've recursed more than
! 204: * MAX_RECURSION times.
! 205: */
! 206: if (depth > MAX_RECURSION)
! 207: return (-3);
! 208:
! 209: /*
! 210: * Check if we have a top record from cgetset().
! 211: */
! 212: if (depth == 0 && toprec != NULL && cgetmatch(toprec, name) == 0) {
! 213: if ((record = malloc (topreclen + BFRAG)) == NULL) {
! 214: errno = ENOMEM;
! 215: return (-2);
! 216: }
! 217: (void)strcpy(record, toprec);
! 218: myfd = 0;
! 219: db_p = db_array;
! 220: rp = record + topreclen + 1;
! 221: r_end = rp + BFRAG;
! 222: goto tc_exp;
! 223: }
! 224: /*
! 225: * Allocate first chunk of memory.
! 226: */
! 227: if ((record = malloc(BFRAG)) == NULL) {
! 228: errno = ENOMEM;
! 229: return (-2);
! 230: }
! 231: r_end = record + BFRAG;
! 232: foundit = 0;
! 233: /*
! 234: * Loop through database array until finding the record.
! 235: */
! 236:
! 237: for (db_p = db_array; *db_p != NULL; db_p++) {
! 238: eof = 0;
! 239:
! 240: /*
! 241: * Open database if not already open.
! 242: */
! 243:
! 244: if (fd >= 0) {
! 245: (void)lseek(fd, (off_t)0, L_SET);
! 246: myfd = 0;
! 247: } else {
! 248: (void)snprintf(pbuf, sizeof(pbuf), "%s.db", *db_p);
! 249: if ((capdbp = dbopen(pbuf, O_RDONLY, 0, DB_HASH, 0))
! 250: != NULL) {
! 251: free(record);
! 252: retval = cdbget(capdbp, &record, name);
! 253: if (capdbp->close(capdbp) < 0)
! 254: return (-2);
! 255: *len = strlen(record);
! 256: *cap = malloc(*len + 1);
! 257: memmove(*cap, record, *len + 1);
! 258: return (retval);
! 259: } else {
! 260: fd = open(*db_p, O_RDONLY, 0);
! 261: if (fd < 0) {
! 262: /* No error on unfound file. */
! 263: if (errno == ENOENT)
! 264: continue;
! 265: free(record);
! 266: return (-2);
! 267: }
! 268: myfd = 1;
! 269: }
! 270: }
! 271: /*
! 272: * Find the requested capability record ...
! 273: */
! 274: {
! 275: char buf[BUFSIZ];
! 276: register char *b_end, *bp;
! 277: register int c;
! 278:
! 279: /*
! 280: * Loop invariants:
! 281: * There is always room for one more character in record.
! 282: * R_end always points just past end of record.
! 283: * Rp always points just past last character in record.
! 284: * B_end always points just past last character in buf.
! 285: * Bp always points at next character in buf.
! 286: */
! 287: b_end = buf;
! 288: bp = buf;
! 289: for (;;) {
! 290:
! 291: /*
! 292: * Read in a line implementing (\, newline)
! 293: * line continuation.
! 294: */
! 295: rp = record;
! 296: for (;;) {
! 297: if (bp >= b_end) {
! 298: int n;
! 299:
! 300: n = read(fd, buf, sizeof(buf));
! 301: if (n <= 0) {
! 302: if (myfd)
! 303: (void)close(fd);
! 304: if (n < 0) {
! 305: free(record);
! 306: return (-2);
! 307: } else {
! 308: fd = -1;
! 309: eof = 1;
! 310: break;
! 311: }
! 312: }
! 313: b_end = buf+n;
! 314: bp = buf;
! 315: }
! 316:
! 317: c = *bp++;
! 318: if (c == '\n') {
! 319: if (rp > record && *(rp-1) == '\\') {
! 320: rp--;
! 321: continue;
! 322: } else
! 323: break;
! 324: }
! 325: *rp++ = c;
! 326:
! 327: /*
! 328: * Enforce loop invariant: if no room
! 329: * left in record buffer, try to get
! 330: * some more.
! 331: */
! 332: if (rp >= r_end) {
! 333: u_int pos;
! 334: size_t newsize;
! 335:
! 336: pos = rp - record;
! 337: newsize = r_end - record + BFRAG;
! 338: record = realloc(record, newsize);
! 339: if (record == NULL) {
! 340: errno = ENOMEM;
! 341: if (myfd)
! 342: (void)close(fd);
! 343: return (-2);
! 344: }
! 345: r_end = record + newsize;
! 346: rp = record + pos;
! 347: }
! 348: }
! 349: /* loop invariant let's us do this */
! 350: *rp++ = '\0';
! 351:
! 352: /*
! 353: * If encountered eof check next file.
! 354: */
! 355: if (eof)
! 356: break;
! 357:
! 358: /*
! 359: * Toss blank lines and comments.
! 360: */
! 361: if (*record == '\0' || *record == '#')
! 362: continue;
! 363:
! 364: /*
! 365: * See if this is the record we want ...
! 366: */
! 367: if (cgetmatch(record, name) == 0) {
! 368: if (nfield == NULL || !nfcmp(nfield, record)) {
! 369: foundit = 1;
! 370: break; /* found it! */
! 371: }
! 372: }
! 373: }
! 374: }
! 375: if (foundit)
! 376: break;
! 377: }
! 378:
! 379: if (!foundit)
! 380: return (-1);
! 381:
! 382: /*
! 383: * Got the capability record, but now we have to expand all tc=name
! 384: * references in it ...
! 385: */
! 386: tc_exp: {
! 387: register char *newicap, *s;
! 388: register int newilen;
! 389: u_int ilen;
! 390: int diff, iret, tclen;
! 391: char *icap, *scan, *tc, *tcstart, *tcend;
! 392:
! 393: /*
! 394: * Loop invariants:
! 395: * There is room for one more character in record.
! 396: * R_end points just past end of record.
! 397: * Rp points just past last character in record.
! 398: * Scan points at remainder of record that needs to be
! 399: * scanned for tc=name constructs.
! 400: */
! 401: scan = record;
! 402: tc_not_resolved = 0;
! 403: for (;;) {
! 404: if ((tc = cgetcap(scan, "tc", '=')) == NULL)
! 405: break;
! 406:
! 407: /*
! 408: * Find end of tc=name and stomp on the trailing `:'
! 409: * (if present) so we can use it to call ourselves.
! 410: */
! 411: s = tc;
! 412: for (;;)
! 413: if (*s == '\0')
! 414: break;
! 415: else
! 416: if (*s++ == ':') {
! 417: *(s - 1) = '\0';
! 418: break;
! 419: }
! 420: tcstart = tc - 3;
! 421: tclen = s - tcstart;
! 422: tcend = s;
! 423:
! 424: iret = getent(&icap, &ilen, db_p, fd, tc, depth+1,
! 425: NULL);
! 426: newicap = icap; /* Put into a register. */
! 427: newilen = ilen;
! 428: if (iret != 0) {
! 429: /* an error */
! 430: if (iret < -1) {
! 431: if (myfd)
! 432: (void)close(fd);
! 433: free(record);
! 434: return (iret);
! 435: }
! 436: if (iret == 1)
! 437: tc_not_resolved = 1;
! 438: /* couldn't resolve tc */
! 439: if (iret == -1) {
! 440: *(s - 1) = ':';
! 441: scan = s - 1;
! 442: tc_not_resolved = 1;
! 443: continue;
! 444:
! 445: }
! 446: }
! 447: /* not interested in name field of tc'ed record */
! 448: s = newicap;
! 449: for (;;)
! 450: if (*s == '\0')
! 451: break;
! 452: else
! 453: if (*s++ == ':')
! 454: break;
! 455: newilen -= s - newicap;
! 456: newicap = s;
! 457:
! 458: /* make sure interpolated record is `:'-terminated */
! 459: s += newilen;
! 460: if (*(s-1) != ':') {
! 461: *s = ':'; /* overwrite NUL with : */
! 462: newilen++;
! 463: }
! 464:
! 465: /*
! 466: * Make sure there's enough room to insert the
! 467: * new record.
! 468: */
! 469: diff = newilen - tclen;
! 470: if (diff >= r_end - rp) {
! 471: u_int pos, tcpos, tcposend;
! 472: size_t newsize;
! 473:
! 474: pos = rp - record;
! 475: newsize = r_end - record + diff + BFRAG;
! 476: tcpos = tcstart - record;
! 477: tcposend = tcend - record;
! 478: record = realloc(record, newsize);
! 479: if (record == NULL) {
! 480: errno = ENOMEM;
! 481: if (myfd)
! 482: (void)close(fd);
! 483: free(icap);
! 484: return (-2);
! 485: }
! 486: r_end = record + newsize;
! 487: rp = record + pos;
! 488: tcstart = record + tcpos;
! 489: tcend = record + tcposend;
! 490: }
! 491:
! 492: /*
! 493: * Insert tc'ed record into our record.
! 494: */
! 495: s = tcstart + newilen;
! 496: bcopy(tcend, s, rp - tcend);
! 497: bcopy(newicap, tcstart, newilen);
! 498: rp += diff;
! 499: free(icap);
! 500:
! 501: /*
! 502: * Start scan on `:' so next cgetcap works properly
! 503: * (cgetcap always skips first field).
! 504: */
! 505: scan = s-1;
! 506: }
! 507:
! 508: }
! 509: /*
! 510: * Close file (if we opened it), give back any extra memory, and
! 511: * return capability, length and success.
! 512: */
! 513: if (myfd)
! 514: (void)close(fd);
! 515: *len = rp - record - 1; /* don't count NUL */
! 516: if (r_end > rp)
! 517: if ((record =
! 518: realloc(record, (size_t)(rp - record))) == NULL) {
! 519: errno = ENOMEM;
! 520: return (-2);
! 521: }
! 522:
! 523: *cap = record;
! 524: if (tc_not_resolved)
! 525: return (1);
! 526: return (0);
! 527: }
! 528:
! 529: static int
! 530: cdbget(capdbp, bp, name)
! 531: DB *capdbp;
! 532: char **bp, *name;
! 533: {
! 534: DBT key, data;
! 535: char *buf;
! 536: int st;
! 537:
! 538: key.data = name;
! 539: key.size = strlen(name);
! 540:
! 541: for (;;) {
! 542: /* Get the reference. */
! 543: switch(capdbp->get(capdbp, &key, &data, 0)) {
! 544: case -1:
! 545: return (-2);
! 546: case 1:
! 547: return (-1);
! 548: }
! 549:
! 550: /* If not an index to another record, leave. */
! 551: if (((char *)data.data)[0] != SHADOW)
! 552: break;
! 553:
! 554: key.data = (char *)data.data + 1;
! 555: key.size = data.size - 1;
! 556: }
! 557:
! 558: *bp = (char *)data.data + 1;
! 559: return (((char *)(data.data))[0] == TCERR ? 1 : 0);
! 560: }
! 561:
! 562: /*
! 563: * Cgetmatch will return 0 if name is one of the names of the capability
! 564: * record buf, -1 if not.
! 565: */
! 566: int
! 567: cgetmatch(buf, name)
! 568: char *buf, *name;
! 569: {
! 570: register char *np, *bp;
! 571:
! 572: /*
! 573: * Start search at beginning of record.
! 574: */
! 575: bp = buf;
! 576: for (;;) {
! 577: /*
! 578: * Try to match a record name.
! 579: */
! 580: np = name;
! 581: for (;;)
! 582: if (*np == '\0')
! 583: if (*bp == '|' || *bp == ':' || *bp == '\0')
! 584: return (0);
! 585: else
! 586: break;
! 587: else
! 588: if (*bp++ != *np++)
! 589: break;
! 590:
! 591: /*
! 592: * Match failed, skip to next name in record.
! 593: */
! 594: bp--; /* a '|' or ':' may have stopped the match */
! 595: for (;;)
! 596: if (*bp == '\0' || *bp == ':')
! 597: return (-1); /* match failed totally */
! 598: else
! 599: if (*bp++ == '|')
! 600: break; /* found next name */
! 601: }
! 602: }
! 603:
! 604:
! 605:
! 606:
! 607:
! 608: int
! 609: cgetfirst(buf, db_array)
! 610: char **buf, **db_array;
! 611: {
! 612: (void)cgetclose();
! 613: return (cgetnext(buf, db_array));
! 614: }
! 615:
! 616: static FILE *pfp;
! 617: static int slash;
! 618: static char **dbp;
! 619:
! 620: int
! 621: cgetclose()
! 622: {
! 623: if (pfp != NULL) {
! 624: (void)fclose(pfp);
! 625: pfp = NULL;
! 626: }
! 627: dbp = NULL;
! 628: gottoprec = 0;
! 629: slash = 0;
! 630: return(0);
! 631: }
! 632:
! 633: /*
! 634: * Cgetnext() gets either the first or next entry in the logical database
! 635: * specified by db_array. It returns 0 upon completion of the database, 1
! 636: * upon returning an entry with more remaining, and -1 if an error occurs.
! 637: */
! 638: int
! 639: cgetnext(bp, db_array)
! 640: register char **bp;
! 641: char **db_array;
! 642: {
! 643: size_t len;
! 644: int status, i, done;
! 645: char *cp, *line, *rp, *np, buf[BSIZE], nbuf[BSIZE];
! 646: u_int dummy;
! 647:
! 648: if (dbp == NULL)
! 649: dbp = db_array;
! 650:
! 651: if (pfp == NULL && (pfp = fopen(*dbp, "r")) == NULL) {
! 652: (void)cgetclose();
! 653: return (-1);
! 654: }
! 655: for(;;) {
! 656: if (toprec && !gottoprec) {
! 657: gottoprec = 1;
! 658: line = toprec;
! 659: } else {
! 660: line = fgetline(pfp, &len);
! 661: if (line == NULL && pfp) {
! 662: (void)fclose(pfp);
! 663: if (ferror(pfp)) {
! 664: (void)cgetclose();
! 665: return (-1);
! 666: } else {
! 667: if (*++dbp == NULL) {
! 668: (void)cgetclose();
! 669: return (0);
! 670: } else if ((pfp =
! 671: fopen(*dbp, "r")) == NULL) {
! 672: (void)cgetclose();
! 673: return (-1);
! 674: } else
! 675: continue;
! 676: }
! 677: } else
! 678: line[len - 1] = '\0';
! 679: if (len == 1) {
! 680: slash = 0;
! 681: continue;
! 682: }
! 683: if (isspace(*line) ||
! 684: *line == ':' || *line == '#' || slash) {
! 685: if (line[len - 2] == '\\')
! 686: slash = 1;
! 687: else
! 688: slash = 0;
! 689: continue;
! 690: }
! 691: if (line[len - 2] == '\\')
! 692: slash = 1;
! 693: else
! 694: slash = 0;
! 695: }
! 696:
! 697:
! 698: /*
! 699: * Line points to a name line.
! 700: */
! 701: i = 0;
! 702: done = 0;
! 703: np = nbuf;
! 704: for (;;) {
! 705: for (cp = line; *cp != '\0'; cp++) {
! 706: if (*cp == ':') {
! 707: *np++ = ':';
! 708: done = 1;
! 709: break;
! 710: }
! 711: if (*cp == '\\')
! 712: break;
! 713: *np++ = *cp;
! 714: }
! 715: if (done) {
! 716: *np = '\0';
! 717: break;
! 718: } else { /* name field extends beyond the line */
! 719: line = fgetline(pfp, &len);
! 720: if (line == NULL && pfp) {
! 721: (void)fclose(pfp);
! 722: if (ferror(pfp)) {
! 723: (void)cgetclose();
! 724: return (-1);
! 725: }
! 726: } else
! 727: line[len - 1] = '\0';
! 728: }
! 729: }
! 730: rp = buf;
! 731: for(cp = nbuf; *cp != NULL; cp++)
! 732: if (*cp == '|' || *cp == ':')
! 733: break;
! 734: else
! 735: *rp++ = *cp;
! 736:
! 737: *rp = '\0';
! 738: /*
! 739: * XXX
! 740: * Last argument of getent here should be nbuf if we want true
! 741: * sequential access in the case of duplicates.
! 742: * With NULL, getent will return the first entry found
! 743: * rather than the duplicate entry record. This is a
! 744: * matter of semantics that should be resolved.
! 745: */
! 746: status = getent(bp, &dummy, db_array, -1, buf, 0, NULL);
! 747: if (status == -2 || status == -3)
! 748: (void)cgetclose();
! 749:
! 750: return (status + 1);
! 751: }
! 752: /* NOTREACHED */
! 753: }
! 754:
! 755: /*
! 756: * Cgetstr retrieves the value of the string capability cap from the
! 757: * capability record pointed to by buf. A pointer to a decoded, NUL
! 758: * terminated, malloc'd copy of the string is returned in the char *
! 759: * pointed to by str. The length of the string not including the trailing
! 760: * NUL is returned on success, -1 if the requested string capability
! 761: * couldn't be found, -2 if a system error was encountered (storage
! 762: * allocation failure).
! 763: */
! 764: int
! 765: cgetstr(buf, cap, str)
! 766: char *buf, *cap;
! 767: char **str;
! 768: {
! 769: register u_int m_room;
! 770: register char *bp, *mp;
! 771: int len;
! 772: char *mem;
! 773:
! 774: /*
! 775: * Find string capability cap
! 776: */
! 777: bp = cgetcap(buf, cap, '=');
! 778: if (bp == NULL)
! 779: return (-1);
! 780:
! 781: /*
! 782: * Conversion / storage allocation loop ... Allocate memory in
! 783: * chunks SFRAG in size.
! 784: */
! 785: if ((mem = malloc(SFRAG)) == NULL) {
! 786: errno = ENOMEM;
! 787: return (-2); /* couldn't even allocate the first fragment */
! 788: }
! 789: m_room = SFRAG;
! 790: mp = mem;
! 791:
! 792: while (*bp != ':' && *bp != '\0') {
! 793: /*
! 794: * Loop invariants:
! 795: * There is always room for one more character in mem.
! 796: * Mp always points just past last character in mem.
! 797: * Bp always points at next character in buf.
! 798: */
! 799: if (*bp == '^') {
! 800: bp++;
! 801: if (*bp == ':' || *bp == '\0')
! 802: break; /* drop unfinished escape */
! 803: *mp++ = *bp++ & 037;
! 804: } else if (*bp == '\\') {
! 805: bp++;
! 806: if (*bp == ':' || *bp == '\0')
! 807: break; /* drop unfinished escape */
! 808: if ('0' <= *bp && *bp <= '7') {
! 809: register int n, i;
! 810:
! 811: n = 0;
! 812: i = 3; /* maximum of three octal digits */
! 813: do {
! 814: n = n * 8 + (*bp++ - '0');
! 815: } while (--i && '0' <= *bp && *bp <= '7');
! 816: *mp++ = n;
! 817: }
! 818: else switch (*bp++) {
! 819: case 'b': case 'B':
! 820: *mp++ = '\b';
! 821: break;
! 822: case 't': case 'T':
! 823: *mp++ = '\t';
! 824: break;
! 825: case 'n': case 'N':
! 826: *mp++ = '\n';
! 827: break;
! 828: case 'f': case 'F':
! 829: *mp++ = '\f';
! 830: break;
! 831: case 'r': case 'R':
! 832: *mp++ = '\r';
! 833: break;
! 834: case 'e': case 'E':
! 835: *mp++ = ESC;
! 836: break;
! 837: case 'c': case 'C':
! 838: *mp++ = ':';
! 839: break;
! 840: default:
! 841: /*
! 842: * Catches '\', '^', and
! 843: * everything else.
! 844: */
! 845: *mp++ = *(bp-1);
! 846: break;
! 847: }
! 848: } else
! 849: *mp++ = *bp++;
! 850: m_room--;
! 851:
! 852: /*
! 853: * Enforce loop invariant: if no room left in current
! 854: * buffer, try to get some more.
! 855: */
! 856: if (m_room == 0) {
! 857: size_t size = mp - mem;
! 858:
! 859: if ((mem = realloc(mem, size + SFRAG)) == NULL)
! 860: return (-2);
! 861: m_room = SFRAG;
! 862: mp = mem + size;
! 863: }
! 864: }
! 865: *mp++ = '\0'; /* loop invariant let's us do this */
! 866: m_room--;
! 867: len = mp - mem - 1;
! 868:
! 869: /*
! 870: * Give back any extra memory and return value and success.
! 871: */
! 872: if (m_room != 0)
! 873: if ((mem = realloc(mem, (size_t)(mp - mem))) == NULL)
! 874: return (-2);
! 875: *str = mem;
! 876: return (len);
! 877: }
! 878:
! 879: /*
! 880: * Cgetustr retrieves the value of the string capability cap from the
! 881: * capability record pointed to by buf. The difference between cgetustr()
! 882: * and cgetstr() is that cgetustr does not decode escapes but rather treats
! 883: * all characters literally. A pointer to a NUL terminated malloc'd
! 884: * copy of the string is returned in the char pointed to by str. The
! 885: * length of the string not including the trailing NUL is returned on success,
! 886: * -1 if the requested string capability couldn't be found, -2 if a system
! 887: * error was encountered (storage allocation failure).
! 888: */
! 889: int
! 890: cgetustr(buf, cap, str)
! 891: char *buf, *cap, **str;
! 892: {
! 893: register u_int m_room;
! 894: register char *bp, *mp;
! 895: int len;
! 896: char *mem;
! 897:
! 898: /*
! 899: * Find string capability cap
! 900: */
! 901: if ((bp = cgetcap(buf, cap, '=')) == NULL)
! 902: return (-1);
! 903:
! 904: /*
! 905: * Conversion / storage allocation loop ... Allocate memory in
! 906: * chunks SFRAG in size.
! 907: */
! 908: if ((mem = malloc(SFRAG)) == NULL) {
! 909: errno = ENOMEM;
! 910: return (-2); /* couldn't even allocate the first fragment */
! 911: }
! 912: m_room = SFRAG;
! 913: mp = mem;
! 914:
! 915: while (*bp != ':' && *bp != '\0') {
! 916: /*
! 917: * Loop invariants:
! 918: * There is always room for one more character in mem.
! 919: * Mp always points just past last character in mem.
! 920: * Bp always points at next character in buf.
! 921: */
! 922: *mp++ = *bp++;
! 923: m_room--;
! 924:
! 925: /*
! 926: * Enforce loop invariant: if no room left in current
! 927: * buffer, try to get some more.
! 928: */
! 929: if (m_room == 0) {
! 930: size_t size = mp - mem;
! 931:
! 932: if ((mem = realloc(mem, size + SFRAG)) == NULL)
! 933: return (-2);
! 934: m_room = SFRAG;
! 935: mp = mem + size;
! 936: }
! 937: }
! 938: *mp++ = '\0'; /* loop invariant let's us do this */
! 939: m_room--;
! 940: len = mp - mem - 1;
! 941:
! 942: /*
! 943: * Give back any extra memory and return value and success.
! 944: */
! 945: if (m_room != 0)
! 946: if ((mem = realloc(mem, (size_t)(mp - mem))) == NULL)
! 947: return (-2);
! 948: *str = mem;
! 949: return (len);
! 950: }
! 951:
! 952: /*
! 953: * Cgetnum retrieves the value of the numeric capability cap from the
! 954: * capability record pointed to by buf. The numeric value is returned in
! 955: * the long pointed to by num. 0 is returned on success, -1 if the requested
! 956: * numeric capability couldn't be found.
! 957: */
! 958: int
! 959: cgetnum(buf, cap, num)
! 960: char *buf, *cap;
! 961: long *num;
! 962: {
! 963: register long n;
! 964: register int base, digit;
! 965: register char *bp;
! 966:
! 967: /*
! 968: * Find numeric capability cap
! 969: */
! 970: bp = cgetcap(buf, cap, '#');
! 971: if (bp == NULL)
! 972: return (-1);
! 973:
! 974: /*
! 975: * Look at value and determine numeric base:
! 976: * 0x... or 0X... hexadecimal,
! 977: * else 0... octal,
! 978: * else decimal.
! 979: */
! 980: if (*bp == '0') {
! 981: bp++;
! 982: if (*bp == 'x' || *bp == 'X') {
! 983: bp++;
! 984: base = 16;
! 985: } else
! 986: base = 8;
! 987: } else
! 988: base = 10;
! 989:
! 990: /*
! 991: * Conversion loop ...
! 992: */
! 993: n = 0;
! 994: for (;;) {
! 995: if ('0' <= *bp && *bp <= '9')
! 996: digit = *bp - '0';
! 997: else if ('a' <= *bp && *bp <= 'f')
! 998: digit = 10 + *bp - 'a';
! 999: else if ('A' <= *bp && *bp <= 'F')
! 1000: digit = 10 + *bp - 'A';
! 1001: else
! 1002: break;
! 1003:
! 1004: if (digit >= base)
! 1005: break;
! 1006:
! 1007: n = n * base + digit;
! 1008: bp++;
! 1009: }
! 1010:
! 1011: /*
! 1012: * Return value and success.
! 1013: */
! 1014: *num = n;
! 1015: return (0);
! 1016: }
! 1017:
! 1018:
! 1019: /*
! 1020: * Compare name field of record.
! 1021: */
! 1022: static int
! 1023: nfcmp(nf, rec)
! 1024: char *nf, *rec;
! 1025: {
! 1026: char *cp, tmp;
! 1027: int ret;
! 1028:
! 1029: for (cp = rec; *cp != ':'; cp++)
! 1030: ;
! 1031:
! 1032: tmp = *(cp + 1);
! 1033: *(cp + 1) = '\0';
! 1034: ret = strcmp(nf, rec);
! 1035: *(cp + 1) = tmp;
! 1036:
! 1037: return (ret);
! 1038: }