]>
git.saurik.com Git - apple/libc.git/blob - gen/FreeBSD/getcap.c
   2  * Copyright (c) 1992, 1993 
   3  *      The Regents of the University of California.  All rights reserved. 
   5  * This code is derived from software contributed to Berkeley by 
   6  * Casey Leedom of Lawrence Livermore National Laboratory. 
   8  * Redistribution and use in source and binary forms, with or without 
   9  * modification, are permitted provided that the following conditions 
  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  * 4. Neither the name of the University nor the names of its contributors 
  17  *    may be used to endorse or promote products derived from this software 
  18  *    without specific prior written permission. 
  20  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 
  21  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 
  22  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 
  23  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 
  24  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 
  25  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 
  26  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 
  27  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 
  28  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 
  29  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 
  33 #if defined(LIBC_SCCS) && !defined(lint) 
  34 static char sccsid
[] = "@(#)getcap.c    8.3 (Berkeley) 3/25/94"; 
  35 #endif /* LIBC_SCCS and not lint */ 
  36 #include <sys/cdefs.h> 
  37 __FBSDID("$FreeBSD: src/lib/libc/gen/getcap.c,v 1.23 2009/11/25 04:45:45 wollman Exp $"); 
  39 #include "xlocale_private.h" 
  41 #include "namespace.h" 
  42 #include <sys/types.h> 
  52 #include "un-namespace.h" 
  58 #define ESC             ('[' & 037)     /* ASCII ESC */ 
  59 #define MAX_RECURSION   32              /* maximum getent recursion */ 
  60 #define SFRAG           100             /* cgetstr mallocs in SFRAG chunks */ 
  64 #define SHADOW  (char)2 
  66 static size_t    topreclen
;     /* toprec length */ 
  67 static char     *toprec
;        /* Additional record specified by cgetset() */ 
  68 static int       gottoprec
;     /* Flag indicating retrieval of toprecord */ 
  70 static int      cdbget(DB 
*, char **, const char *); 
  71 static int      getent(char **, u_int 
*, char **, int, const char *, int, char *, locale_t
); 
  72 static int      nfcmp(char *, char *); 
  75  * Cgetset() allows the addition of a user specified buffer to be added 
  76  * to the database array, in effect "pushing" the buffer on top of the 
  77  * virtual database. 0 is returned on success, -1 on failure. 
  80 cgetset(const char *ent
) 
  89         topreclen 
= strlen(ent
); 
  90         if ((toprec 
= malloc (topreclen 
+ 1)) == NULL
) { 
  95         (void)strcpy(toprec
, ent
); 
 100  * Cgetcap searches the capability record buf for the capability cap with 
 101  * type `type'.  A pointer to the value of cap is returned on success, NULL 
 102  * if the requested capability couldn't be found. 
 104  * Specifying a type of ':' means that nothing should follow cap (:cap:). 
 105  * In this case a pointer to the terminating ':' or NUL will be returned if 
 108  * If (cap, '@') or (cap, terminator, '@') is found before (cap, terminator) 
 112 cgetcap(char *buf
, const char *cap
, int type
) 
 120                  * Skip past the current capability field - it's either the 
 121                  * name field if this is the first time through the loop, or 
 122                  * the remainder of a field whose name failed to match cap. 
 132                  * Try to match (cap, type) in buf. 
 134                 for (cp 
= cap
; *cp 
== *bp 
&& *bp 
!= '\0'; cp
++, bp
++) 
 141                         if (*bp 
!= '\0' && *bp 
!= ':') 
 148                 return (*bp 
== '@' ? NULL 
: bp
); 
 154  * Cgetent extracts the capability record name from the NULL terminated file 
 155  * array db_array and returns a pointer to a malloc'd copy of it in buf. 
 156  * Buf must be retained through all subsequent calls to cgetcap, cgetnum, 
 157  * cgetflag, and cgetstr, but may then be free'd.  0 is returned on success, 
 158  * -1 if the requested record couldn't be found, -2 if a system error was 
 159  * encountered (couldn't open/read a file, etc.), and -3 if a potential 
 160  * reference loop is detected. 
 163 cgetent(char **buf
, char **db_array
, const char *name
) 
 167         return (getent(buf
, &dummy
, db_array
, -1, name
, 0, NULL
, __current_locale())); 
 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= 
 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 
 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 
 189 getent(char **cap
, u_int 
*len
, char **db_array
, int fd
, const char *name
, 
 190     int depth
, char *nfield
, locale_t loc
) 
 193         char *r_end
, *rp
, **db_p
; 
 194         int myfd
, eof
, foundit
, retval
; 
 197         char pbuf
[_POSIX_PATH_MAX
]; 
 200          * Return with ``loop detected'' error if we've recursed more than 
 201          * MAX_RECURSION times. 
 203         if (depth 
> MAX_RECURSION
) 
 207          * Check if we have a top record from cgetset(). 
 209         if (depth 
== 0 && toprec 
!= NULL 
&& cgetmatch(toprec
, name
) == 0) { 
 210                 if ((record 
= malloc (topreclen 
+ BFRAG
)) == NULL
) { 
 214                 (void)strcpy(record
, toprec
); 
 217                 rp 
= record 
+ topreclen 
+ 1; 
 222          * Allocate first chunk of memory. 
 224         if ((record 
= malloc(BFRAG
)) == NULL
) { 
 228         r_end 
= record 
+ BFRAG
; 
 231          * Loop through database array until finding the record. 
 234         for (db_p 
= db_array
; *db_p 
!= NULL
; db_p
++) { 
 238                  * Open database if not already open. 
 242                         (void)lseek(fd
, (off_t
)0, SEEK_SET
); 
 245                         (void)snprintf(pbuf
, sizeof(pbuf
), "%s.db", *db_p
); 
 246                         if ((capdbp 
= dbopen(pbuf
, O_RDONLY
, 0, DB_HASH
, 0)) 
 249                                 retval 
= cdbget(capdbp
, &record
, name
); 
 251                                         /* no record available */ 
 252                                         (void)capdbp
->close(capdbp
); 
 255                                 /* save the data; close frees it */ 
 256                                 cbuf 
= strdup(record
); 
 257                                 if (capdbp
->close(capdbp
) < 0) { 
 269                                 fd 
= _open(*db_p
, O_RDONLY
, 0); 
 276                  * Find the requested capability record ... 
 285                  *      There is always room for one more character in record. 
 286                  *      R_end always points just past end of record. 
 287                  *      Rp always points just past last character in record. 
 288                  *      B_end always points just past last character in buf. 
 289                  *      Bp always points at next character in buf. 
 296                          * Read in a line implementing (\, newline) 
 304                                         n 
= _read(fd
, buf
, sizeof(buf
)); 
 323                                         if (rp 
> record 
&& *(rp
-1) == '\\') { 
 332                                  * Enforce loop invariant: if no room 
 333                                  * left in record buffer, try to get 
 341                                         newsize 
= r_end 
- record 
+ BFRAG
; 
 342                                         record 
= reallocf(record
, newsize
); 
 343                                         if (record 
== NULL
) { 
 349                                         r_end 
= record 
+ newsize
; 
 353                                 /* loop invariant let's us do this */ 
 357                          * If encountered eof check next file. 
 363                          * Toss blank lines and comments. 
 365                         if (*record 
== '\0' || *record 
== '#') 
 369                          * See if this is the record we want ... 
 371                         if (cgetmatch(record
, name
) == 0) { 
 372                                 if (nfield 
== NULL 
|| !nfcmp(nfield
, record
)) { 
 374                                         break;  /* found it! */ 
 389          * Got the capability record, but now we have to expand all tc=name 
 390          * references in it ... 
 396                 int diff
, iret
, tclen
; 
 397                 char *icap
, *scan
, *tc
, *tcstart
, *tcend
; 
 401                  *      There is room for one more character in record. 
 402                  *      R_end points just past end of record. 
 403                  *      Rp points just past last character in record. 
 404                  *      Scan points at remainder of record that needs to be 
 405                  *      scanned for tc=name constructs. 
 410                         if ((tc 
= cgetcap(scan
, "tc", '=')) == NULL
) 
 414                          * Find end of tc=name and stomp on the trailing `:' 
 415                          * (if present) so we can use it to call ourselves. 
 430                         iret 
= getent(&icap
, &ilen
, db_p
, fd
, tc
, depth
+1, 
 432                         newicap 
= icap
;         /* Put into a register. */ 
 444                                 /* couldn't resolve tc */ 
 453                         /* not interested in name field of tc'ed record */ 
 461                         newilen 
-= s 
- newicap
; 
 464                         /* make sure interpolated record is `:'-terminated */ 
 467                                 *s 
= ':';       /* overwrite NUL with : */ 
 472                          * Make sure there's enough room to insert the 
 475                         diff 
= newilen 
- tclen
; 
 476                         if (diff 
>= r_end 
- rp
) { 
 477                                 u_int pos
, tcpos
, tcposend
; 
 481                                 newsize 
= r_end 
- record 
+ diff 
+ BFRAG
; 
 482                                 tcpos 
= tcstart 
- record
; 
 483                                 tcposend 
= tcend 
- record
; 
 484                                 record 
= reallocf(record
, newsize
); 
 485                                 if (record 
== NULL
) { 
 492                                 r_end 
= record 
+ newsize
; 
 494                                 tcstart 
= record 
+ tcpos
; 
 495                                 tcend 
= record 
+ tcposend
; 
 499                          * Insert tc'ed record into our record. 
 501                         s 
= tcstart 
+ newilen
; 
 502                         bcopy(tcend
, s
, rp 
- tcend
); 
 503                         bcopy(newicap
, tcstart
, newilen
); 
 508                          * Start scan on `:' so next cgetcap works properly 
 509                          * (cgetcap always skips first field). 
 516          * Close file (if we opened it), give back any extra memory, and 
 517          * return capability, length and success. 
 521         *len 
= rp 
- record 
- 1; /* don't count NUL */ 
 524                      reallocf(record
, (size_t)(rp 
- record
))) == NULL
) { 
 536 cdbget(DB 
*capdbp
, char **bp
, const char *name
) 
 541         namebuf 
= strdup(name
); 
 545         key
.size 
= strlen(namebuf
); 
 548                 /* Get the reference. */ 
 549                 switch(capdbp
->get(capdbp
, &key
, &data
, 0)) { 
 558                 /* If not an index to another record, leave. */ 
 559                 if (((char *)data
.data
)[0] != SHADOW
) 
 562                 key
.data 
= (char *)data
.data 
+ 1; 
 563                 key
.size 
= data
.size 
- 1; 
 566         *bp 
= (char *)data
.data 
+ 1; 
 568         return (((char *)(data
.data
))[0] == TCERR 
? 1 : 0); 
 572  * Cgetmatch will return 0 if name is one of the names of the capability 
 573  * record buf, -1 if not. 
 576 cgetmatch(const char *buf
, const char *name
) 
 580         if (name 
== NULL 
|| *name 
== '\0') 
 584          * Start search at beginning of record. 
 589                  * Try to match a record name. 
 594                                 if (*bp 
== '|' || *bp 
== ':' || *bp 
== '\0') 
 603                  * Match failed, skip to next name in record. 
 605                 bp
--;   /* a '|' or ':' may have stopped the match */ 
 607                         if (*bp 
== '\0' || *bp 
== ':') 
 608                                 return (-1);    /* match failed totally */ 
 611                                         break;  /* found next name */ 
 620 cgetfirst(char **buf
, char **db_array
) 
 623         return (cgetnext(buf
, db_array
)); 
 644  * Cgetnext() gets either the first or next entry in the logical database 
 645  * specified by db_array.  It returns 0 upon completion of the database, 1 
 646  * upon returning an entry with more remaining, and -1 if an error occurs. 
 649 cgetnext(char **bp
, char **db_array
) 
 652         int done
, hadreaderr
, savederrno
, status
; 
 653         char *cp
, *line
, *rp
, *np
, buf
[BSIZE
], nbuf
[BSIZE
]; 
 655         locale_t loc 
= __current_locale(); 
 660         if (pfp 
== NULL 
&& (pfp 
= fopen(*dbp
, "r")) == NULL
) { 
 665                 if (toprec 
&& !gottoprec
) { 
 669                         line 
= fgetln(pfp
, &len
); 
 670                         if (line 
== NULL 
&& pfp
) { 
 671                                 hadreaderr 
= ferror(pfp
); 
 681                                         if (*++dbp 
== NULL
) { 
 685                                             fopen(*dbp
, "r")) == NULL
) { 
 692                                 line
[len 
- 1] = '\0'; 
 697                         if (isspace_l((unsigned char)*line
, loc
) || 
 698                             *line 
== ':' || *line 
== '#' || slash
) { 
 699                                 if (line
[len 
- 2] == '\\') 
 705                         if (line
[len 
- 2] == '\\') 
 713                  * Line points to a name line. 
 718                         for (cp 
= line
; *cp 
!= '\0'; cp
++) { 
 731                         } else { /* name field extends beyond the line */ 
 732                                 line 
= fgetln(pfp
, &len
); 
 733                                 if (line 
== NULL 
&& pfp
) { 
 734                                         /* Name extends beyond the EOF! */ 
 735                                         hadreaderr 
= ferror(pfp
); 
 749                                         line
[len 
- 1] = '\0'; 
 753                 for(cp 
= nbuf
; *cp 
!= '\0'; cp
++) 
 754                         if (*cp 
== '|' || *cp 
== ':') 
 762                  * Last argument of getent here should be nbuf if we want true 
 763                  * sequential access in the case of duplicates. 
 764                  * With NULL, getent will return the first entry found 
 765                  * rather than the duplicate entry record.  This is a 
 766                  * matter of semantics that should be resolved. 
 768                 status 
= getent(bp
, &dummy
, db_array
, -1, buf
, 0, NULL
, loc
); 
 769                 if (status 
== -2 || status 
== -3) 
 778  * Cgetstr retrieves the value of the string capability cap from the 
 779  * capability record pointed to by buf.  A pointer to a decoded, NUL 
 780  * terminated, malloc'd copy of the string is returned in the char * 
 781  * pointed to by str.  The length of the string not including the trailing 
 782  * NUL is returned on success, -1 if the requested string capability 
 783  * couldn't be found, -2 if a system error was encountered (storage 
 784  * allocation failure). 
 787 cgetstr(char *buf
, const char *cap
, char **str
) 
 795          * Find string capability cap 
 797         bp 
= cgetcap(buf
, cap
, '='); 
 802          * Conversion / storage allocation loop ...  Allocate memory in 
 803          * chunks SFRAG in size. 
 805         if ((mem 
= malloc(SFRAG
)) == NULL
) { 
 807                 return (-2);    /* couldn't even allocate the first fragment */ 
 812         while (*bp 
!= ':' && *bp 
!= '\0') { 
 815                  *      There is always room for one more character in mem. 
 816                  *      Mp always points just past last character in mem. 
 817                  *      Bp always points at next character in buf. 
 821                         if (*bp 
== ':' || *bp 
== '\0') 
 822                                 break;  /* drop unfinished escape */ 
 828                 } else if (*bp 
== '\\') { 
 830                         if (*bp 
== ':' || *bp 
== '\0') 
 831                                 break;  /* drop unfinished escape */ 
 832                         if ('0' <= *bp 
&& *bp 
<= '7') { 
 836                                 i 
= 3;  /* maximum of three octal digits */ 
 838                                         n 
= n 
* 8 + (*bp
++ - '0'); 
 839                                 } while (--i 
&& '0' <= *bp 
&& *bp 
<= '7'); 
 842                         else switch (*bp
++) { 
 866                                          * Catches '\', '^', and 
 877                  * Enforce loop invariant: if no room left in current 
 878                  * buffer, try to get some more. 
 881                         size_t size 
= mp 
- mem
; 
 883                         if ((mem 
= reallocf(mem
, size 
+ SFRAG
)) == NULL
) 
 889         *mp
++ = '\0';   /* loop invariant let's us do this */ 
 894          * Give back any extra memory and return value and success. 
 897                 if ((mem 
= reallocf(mem
, (size_t)(mp 
- mem
))) == NULL
) 
 904  * Cgetustr retrieves the value of the string capability cap from the 
 905  * capability record pointed to by buf.  The difference between cgetustr() 
 906  * and cgetstr() is that cgetustr does not decode escapes but rather treats 
 907  * all characters literally.  A pointer to a  NUL terminated malloc'd 
 908  * copy of the string is returned in the char pointed to by str.  The 
 909  * length of the string not including the trailing NUL is returned on success, 
 910  * -1 if the requested string capability couldn't be found, -2 if a system 
 911  * error was encountered (storage allocation failure). 
 914 cgetustr(char *buf
, const char *cap
, char **str
) 
 922          * Find string capability cap 
 924         if ((bp 
= cgetcap(buf
, cap
, '=')) == NULL
) 
 928          * Conversion / storage allocation loop ...  Allocate memory in 
 929          * chunks SFRAG in size. 
 931         if ((mem 
= malloc(SFRAG
)) == NULL
) { 
 933                 return (-2);    /* couldn't even allocate the first fragment */ 
 938         while (*bp 
!= ':' && *bp 
!= '\0') { 
 941                  *      There is always room for one more character in mem. 
 942                  *      Mp always points just past last character in mem. 
 943                  *      Bp always points at next character in buf. 
 949                  * Enforce loop invariant: if no room left in current 
 950                  * buffer, try to get some more. 
 953                         size_t size 
= mp 
- mem
; 
 955                         if ((mem 
= reallocf(mem
, size 
+ SFRAG
)) == NULL
) 
 961         *mp
++ = '\0';   /* loop invariant let's us do this */ 
 966          * Give back any extra memory and return value and success. 
 969                 if ((mem 
= reallocf(mem
, (size_t)(mp 
- mem
))) == NULL
) 
 976  * Cgetnum retrieves the value of the numeric capability cap from the 
 977  * capability record pointed to by buf.  The numeric value is returned in 
 978  * the long pointed to by num.  0 is returned on success, -1 if the requested 
 979  * numeric capability couldn't be found. 
 982 cgetnum(char *buf
, const char *cap
, long *num
) 
 989          * Find numeric capability cap 
 991         bp 
= cgetcap(buf
, cap
, '#'); 
 996          * Look at value and determine numeric base: 
 997          *      0x... or 0X...  hexadecimal, 
1003                 if (*bp 
== 'x' || *bp 
== 'X') { 
1012          * Conversion loop ... 
1016                 if ('0' <= *bp 
&& *bp 
<= '9') 
1018                 else if ('a' <= *bp 
&& *bp 
<= 'f') 
1019                         digit 
= 10 + *bp 
- 'a'; 
1020                 else if ('A' <= *bp 
&& *bp 
<= 'F') 
1021                         digit 
= 10 + *bp 
- 'A'; 
1028                 n 
= n 
* base 
+ digit
; 
1033          * Return value and success. 
1041  * Compare name field of record. 
1044 nfcmp(char *nf
, char *rec
) 
1049         for (cp 
= rec
; *cp 
!= ':'; cp
++) 
1054         ret 
= strcmp(nf
, rec
);