/crypto/heimdal/lib/roken/getcap.c

https://bitbucket.org/freebsd/freebsd-head/ · C · 1129 lines · 729 code · 96 blank · 304 comment · 282 complexity · 1e55a2b9f9cf348d5c92e8afc9a4c55b MD5 · raw file

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