1*55868Sbostic /*- 2*55868Sbostic * Copyright (c) 1992 The Regents of the University of California. 3*55868Sbostic * All rights reserved. 4*55868Sbostic * 5*55868Sbostic * This code is derived from software contributed to Berkeley by 6*55868Sbostic * Casey Leedom of Lawrence Livermore National Laboratory. 7*55868Sbostic * 8*55868Sbostic * %sccs.include.redist.c% 9*55868Sbostic */ 10*55868Sbostic 11*55868Sbostic #if defined(LIBC_SCCS) && !defined(lint) 12*55868Sbostic static char sccsid[] = "@(#)getcap.c 5.1 (Berkeley) 08/06/92"; 13*55868Sbostic #endif /* LIBC_SCCS and not lint */ 14*55868Sbostic 15*55868Sbostic #include <sys/types.h> 16*55868Sbostic 17*55868Sbostic #include <ctype.h> 18*55868Sbostic #include <errno.h> 19*55868Sbostic #include <errno.h> 20*55868Sbostic #include <fcntl.h> 21*55868Sbostic #include <stdio.h> 22*55868Sbostic #include <stdlib.h> 23*55868Sbostic #include <string.h> 24*55868Sbostic #include <unistd.h> 25*55868Sbostic 26*55868Sbostic #define BFRAG 1024 27*55868Sbostic #define BSIZE 80 28*55868Sbostic #define ESC ('[' & 037) /* ASCII ESC */ 29*55868Sbostic #define MAX_RECURSION 32 /* maximum getent recursion */ 30*55868Sbostic #define SFRAG 100 /* cgetstr mallocs in SFRAG chunks */ 31*55868Sbostic 32*55868Sbostic static size_t topreclen; /* toprec length */ 33*55868Sbostic static char *toprec; /* Additional record specified by cgetset() */ 34*55868Sbostic 35*55868Sbostic static int getent __P((char **, u_int *, char **, int, char *, int)); 36*55868Sbostic 37*55868Sbostic /* 38*55868Sbostic * Cgetset() allows the addition of a user specified buffer to be added 39*55868Sbostic * to the database array, in effect "pushing" the buffer on top of the 40*55868Sbostic * virtual database. 0 is returned on success, -1 on failure. 41*55868Sbostic */ 42*55868Sbostic int 43*55868Sbostic cgetset(ent) 44*55868Sbostic char *ent; 45*55868Sbostic { 46*55868Sbostic if (ent == NULL) { 47*55868Sbostic if (toprec) 48*55868Sbostic free(toprec); 49*55868Sbostic toprec = NULL; 50*55868Sbostic topreclen = 0; 51*55868Sbostic return (0); 52*55868Sbostic } 53*55868Sbostic topreclen = strlen(ent); 54*55868Sbostic if ((toprec = malloc (topreclen + 1)) == NULL) { 55*55868Sbostic errno = ENOMEM; 56*55868Sbostic return (-1); 57*55868Sbostic } 58*55868Sbostic (void)strcpy(toprec, ent); 59*55868Sbostic return (0); 60*55868Sbostic } 61*55868Sbostic 62*55868Sbostic /* 63*55868Sbostic * Cgetcap searches the capability record buf for the capability cap with 64*55868Sbostic * type `type'. A pointer to the value of cap is returned on success, NULL 65*55868Sbostic * if the requested capability couldn't be found. 66*55868Sbostic * 67*55868Sbostic * Specifying a type of ':' means that nothing should follow cap (:cap:). 68*55868Sbostic * In this case a pointer to the terminating ':' or NUL will be returned if 69*55868Sbostic * cap is found. 70*55868Sbostic * 71*55868Sbostic * If (cap, '@') or (cap, terminator, '@') is found before (cap, terminator) 72*55868Sbostic * return NULL. 73*55868Sbostic */ 74*55868Sbostic char * 75*55868Sbostic cgetcap(buf, cap, type) 76*55868Sbostic char *buf, *cap; 77*55868Sbostic int type; 78*55868Sbostic { 79*55868Sbostic register char *bp, *cp; 80*55868Sbostic 81*55868Sbostic bp = buf; 82*55868Sbostic for (;;) { 83*55868Sbostic /* 84*55868Sbostic * Skip past the current capability field - it's either the 85*55868Sbostic * name field if this is the first time through the loop, or 86*55868Sbostic * the remainder of a field whose name failed to match cap. 87*55868Sbostic */ 88*55868Sbostic for (;;) 89*55868Sbostic if (*bp == '\0') 90*55868Sbostic return (NULL); 91*55868Sbostic else 92*55868Sbostic if (*bp++ == ':') 93*55868Sbostic break; 94*55868Sbostic 95*55868Sbostic /* 96*55868Sbostic * Try to match (cap, type) in buf. 97*55868Sbostic */ 98*55868Sbostic for (cp = cap; *cp == *bp && *bp != '\0'; cp++, bp++) 99*55868Sbostic continue; 100*55868Sbostic if (*cp != '\0') 101*55868Sbostic continue; 102*55868Sbostic if (*bp == '@') 103*55868Sbostic return (NULL); 104*55868Sbostic if (type == ':') { 105*55868Sbostic if (*bp != '\0' && *bp != ':') 106*55868Sbostic continue; 107*55868Sbostic return(bp); 108*55868Sbostic } 109*55868Sbostic if (*bp != type) 110*55868Sbostic continue; 111*55868Sbostic bp++; 112*55868Sbostic return (*bp == '@' ? NULL : bp); 113*55868Sbostic } 114*55868Sbostic /* NOTREACHED */ 115*55868Sbostic } 116*55868Sbostic 117*55868Sbostic /* 118*55868Sbostic * Cgetent extracts the capability record name from the NULL terminated file 119*55868Sbostic * array db_array and returns a pointer to a malloc'd copy of it in buf. 120*55868Sbostic * Buf must be retained through all subsequent calls to cgetcap, cgetnum, 121*55868Sbostic * cgetflag, and cgetstr, but may then be free'd. 0 is returned on success, 122*55868Sbostic * -1 if the requested record couldn't be found, -2 if a system error was 123*55868Sbostic * encountered (couldn't open/read a file, etc.), and -3 if a potential 124*55868Sbostic * reference loop is detected. 125*55868Sbostic */ 126*55868Sbostic int 127*55868Sbostic cgetent(buf, db_array, name) 128*55868Sbostic char **buf, **db_array, *name; 129*55868Sbostic { 130*55868Sbostic u_int dummy; 131*55868Sbostic 132*55868Sbostic return (getent(buf, &dummy, db_array, -1, name, 0)); 133*55868Sbostic } 134*55868Sbostic 135*55868Sbostic /* 136*55868Sbostic * Getent implements the functions of cgetent. If fd is non-negative, 137*55868Sbostic * *db_array has already been opened and fd is the open file descriptor. We 138*55868Sbostic * do this to save time and avoid using up file descriptors for tc= 139*55868Sbostic * recursions. 140*55868Sbostic * 141*55868Sbostic * Getent returns the same success/failure codes as cgetent. On success, a 142*55868Sbostic * pointer to a malloc'ed capability record with all tc= capabilities fully 143*55868Sbostic * expanded and its length (not including trailing ASCII NUL) are left in 144*55868Sbostic * *cap and *len. 145*55868Sbostic * 146*55868Sbostic * Basic algorithm: 147*55868Sbostic * + Allocate memory incrementally as needed in chunks of size BFRAG 148*55868Sbostic * for capability buffer. 149*55868Sbostic * + Recurse for each tc=name and interpolate result. Stop when all 150*55868Sbostic * names interpolated, a name can't be found, or depth exceeds 151*55868Sbostic * MAX_RECURSION. 152*55868Sbostic */ 153*55868Sbostic static int 154*55868Sbostic getent(cap, len, db_array, fd, name, depth) 155*55868Sbostic char **cap, **db_array, *name; 156*55868Sbostic u_int *len; 157*55868Sbostic int fd, depth; 158*55868Sbostic { 159*55868Sbostic register char *r_end, *rp, **db_p; 160*55868Sbostic int myfd, eof, foundit; 161*55868Sbostic char *record; 162*55868Sbostic 163*55868Sbostic /* 164*55868Sbostic * Return with ``loop detected'' error if we've recursed more than 165*55868Sbostic * MAX_RECURSION times. 166*55868Sbostic */ 167*55868Sbostic if (depth > MAX_RECURSION) 168*55868Sbostic return (-3); 169*55868Sbostic 170*55868Sbostic /* 171*55868Sbostic * Check if we have a top record from cgetset(). 172*55868Sbostic */ 173*55868Sbostic if (depth == 0 && toprec != NULL) { 174*55868Sbostic if ((record = malloc (topreclen + BFRAG)) == NULL) { 175*55868Sbostic errno = ENOMEM; 176*55868Sbostic return (-2); 177*55868Sbostic } 178*55868Sbostic (void)strcpy(record, toprec); 179*55868Sbostic myfd = 0; 180*55868Sbostic db_p = db_array; 181*55868Sbostic rp = record + topreclen + 1; 182*55868Sbostic r_end = rp + BFRAG; 183*55868Sbostic goto tc_exp; 184*55868Sbostic } 185*55868Sbostic /* 186*55868Sbostic * Allocate first chunk of memory. 187*55868Sbostic */ 188*55868Sbostic if ((record = malloc(BFRAG)) == NULL) { 189*55868Sbostic errno = ENOMEM; 190*55868Sbostic return (-2); 191*55868Sbostic } 192*55868Sbostic r_end = record + BFRAG; 193*55868Sbostic foundit = 0; 194*55868Sbostic 195*55868Sbostic /* 196*55868Sbostic * Loop through database array until finding the record. 197*55868Sbostic */ 198*55868Sbostic 199*55868Sbostic for (db_p = db_array; *db_p != NULL; db_p++) { 200*55868Sbostic eof = 0; 201*55868Sbostic 202*55868Sbostic /* 203*55868Sbostic * Open database if not already open. 204*55868Sbostic */ 205*55868Sbostic if (fd >= 0) { 206*55868Sbostic (void)lseek(fd, 0L, L_SET); 207*55868Sbostic myfd = 0; 208*55868Sbostic } else { 209*55868Sbostic fd = open(*db_p, O_RDONLY, 0); 210*55868Sbostic if (fd < 0) { 211*55868Sbostic free(record); 212*55868Sbostic return (-2); 213*55868Sbostic } 214*55868Sbostic myfd = 1; 215*55868Sbostic } 216*55868Sbostic 217*55868Sbostic /* 218*55868Sbostic * Find the requested capability record ... 219*55868Sbostic */ 220*55868Sbostic { 221*55868Sbostic char buf[BUFSIZ]; 222*55868Sbostic register char *b_end, *bp; 223*55868Sbostic register int c; 224*55868Sbostic 225*55868Sbostic /* 226*55868Sbostic * Loop invariants: 227*55868Sbostic * There is always room for one more character in record. 228*55868Sbostic * R_end always points just past end of record. 229*55868Sbostic * Rp always points just past last character in record. 230*55868Sbostic * B_end always points just past last character in buf. 231*55868Sbostic * Bp always points at next character in buf. 232*55868Sbostic */ 233*55868Sbostic b_end = buf; 234*55868Sbostic bp = buf; 235*55868Sbostic for (;;) { 236*55868Sbostic 237*55868Sbostic /* 238*55868Sbostic * Read in a line implementing (\, newline) 239*55868Sbostic * line continuation. 240*55868Sbostic */ 241*55868Sbostic rp = record; 242*55868Sbostic for (;;) { 243*55868Sbostic if (bp >= b_end) { 244*55868Sbostic int n; 245*55868Sbostic 246*55868Sbostic n = read(fd, buf, sizeof(buf)); 247*55868Sbostic if (n <= 0) { 248*55868Sbostic if (myfd) 249*55868Sbostic (void)close(fd); 250*55868Sbostic if (n < 0) { 251*55868Sbostic free(record); 252*55868Sbostic return (-2); 253*55868Sbostic } else { 254*55868Sbostic fd = -1; 255*55868Sbostic eof = 1; 256*55868Sbostic break; 257*55868Sbostic } 258*55868Sbostic } 259*55868Sbostic b_end = buf+n; 260*55868Sbostic bp = buf; 261*55868Sbostic } 262*55868Sbostic 263*55868Sbostic c = *bp++; 264*55868Sbostic if (c == '\n') { 265*55868Sbostic if (rp > record && *(rp-1) == '\\') { 266*55868Sbostic rp--; 267*55868Sbostic continue; 268*55868Sbostic } else 269*55868Sbostic break; 270*55868Sbostic } 271*55868Sbostic *rp++ = c; 272*55868Sbostic 273*55868Sbostic /* 274*55868Sbostic * Enforce loop invariant: if no room 275*55868Sbostic * left in record buffer, try to get 276*55868Sbostic * some more. 277*55868Sbostic */ 278*55868Sbostic if (rp >= r_end) { 279*55868Sbostic u_int pos, newsize; 280*55868Sbostic 281*55868Sbostic pos = rp - record; 282*55868Sbostic newsize = r_end - record + BFRAG; 283*55868Sbostic record = realloc(record, newsize); 284*55868Sbostic if (record == NULL) { 285*55868Sbostic errno = ENOMEM; 286*55868Sbostic if (myfd) 287*55868Sbostic (void)close(fd); 288*55868Sbostic return (-2); 289*55868Sbostic } 290*55868Sbostic r_end = record + newsize; 291*55868Sbostic rp = record + pos; 292*55868Sbostic } 293*55868Sbostic } 294*55868Sbostic /* loop invariant let's us do this */ 295*55868Sbostic *rp++ = '\0'; 296*55868Sbostic 297*55868Sbostic /* 298*55868Sbostic * If encountered eof check next file. 299*55868Sbostic */ 300*55868Sbostic if (eof) 301*55868Sbostic break; 302*55868Sbostic 303*55868Sbostic /* 304*55868Sbostic * Toss blank lines and comments. 305*55868Sbostic */ 306*55868Sbostic if (*record == '\0' || *record == '#') 307*55868Sbostic continue; 308*55868Sbostic 309*55868Sbostic /* 310*55868Sbostic * See if this is the record we want ... 311*55868Sbostic */ 312*55868Sbostic if (cgetmatch(record, name) == 0) { 313*55868Sbostic foundit = 1; 314*55868Sbostic break; /* found it! */ 315*55868Sbostic } 316*55868Sbostic } 317*55868Sbostic } 318*55868Sbostic if (foundit) 319*55868Sbostic break; 320*55868Sbostic } 321*55868Sbostic 322*55868Sbostic if (!foundit) 323*55868Sbostic return (-1); 324*55868Sbostic 325*55868Sbostic /* 326*55868Sbostic * Got the capability record, but now we have to expand all tc=name 327*55868Sbostic * references in it ... 328*55868Sbostic */ 329*55868Sbostic tc_exp: { 330*55868Sbostic register char *newicap, *s; 331*55868Sbostic register int newilen; 332*55868Sbostic u_int ilen; 333*55868Sbostic int diff, iret, tclen; 334*55868Sbostic char *icap, *scan, *tc, *tcstart, *tcend; 335*55868Sbostic 336*55868Sbostic /* 337*55868Sbostic * Loop invariants: 338*55868Sbostic * There is room for one more character in record. 339*55868Sbostic * R_end points just past end of record. 340*55868Sbostic * Rp points just past last character in record. 341*55868Sbostic * Scan points at remainder of record that needs to be 342*55868Sbostic * scanned for tc=name constructs. 343*55868Sbostic */ 344*55868Sbostic scan = record; 345*55868Sbostic for (;;) { 346*55868Sbostic if ((tc = cgetcap(scan, "tc", '=')) == NULL) 347*55868Sbostic break; 348*55868Sbostic 349*55868Sbostic /* 350*55868Sbostic * Find end of tc=name and stomp on the trailing `:' 351*55868Sbostic * (if present) so we can use it to call ourselves. 352*55868Sbostic */ 353*55868Sbostic s = tc; 354*55868Sbostic for (;;) 355*55868Sbostic if (*s == '\0') 356*55868Sbostic break; 357*55868Sbostic else 358*55868Sbostic if (*s++ == ':') { 359*55868Sbostic *(s-1) = '\0'; 360*55868Sbostic break; 361*55868Sbostic } 362*55868Sbostic tcstart = tc - 3; 363*55868Sbostic tclen = s - tcstart; 364*55868Sbostic tcend = s; 365*55868Sbostic 366*55868Sbostic iret = getent(&icap, &ilen, db_p, fd, tc, depth+1); 367*55868Sbostic newicap = icap; /* Put into a register. */ 368*55868Sbostic newilen = ilen; 369*55868Sbostic if (iret != 0) { 370*55868Sbostic /* an error or couldn't resolve tc= */ 371*55868Sbostic if (myfd) 372*55868Sbostic (void)close(fd); 373*55868Sbostic free(record); 374*55868Sbostic return (iret); 375*55868Sbostic } 376*55868Sbostic 377*55868Sbostic /* not interested in name field of tc'ed record */ 378*55868Sbostic s = newicap; 379*55868Sbostic for (;;) 380*55868Sbostic if (*s == '\0') 381*55868Sbostic break; 382*55868Sbostic else 383*55868Sbostic if (*s++ == ':') 384*55868Sbostic break; 385*55868Sbostic newilen -= s - newicap; 386*55868Sbostic newicap = s; 387*55868Sbostic 388*55868Sbostic /* make sure interpolated record is `:'-terminated */ 389*55868Sbostic s += newilen; 390*55868Sbostic if (*(s-1) != ':') { 391*55868Sbostic *s = ':'; /* overwrite NUL with : */ 392*55868Sbostic newilen++; 393*55868Sbostic } 394*55868Sbostic 395*55868Sbostic /* 396*55868Sbostic * Make sure there's enough room to insert the 397*55868Sbostic * new record. 398*55868Sbostic */ 399*55868Sbostic diff = newilen - tclen; 400*55868Sbostic if (diff >= r_end - rp) { 401*55868Sbostic u_int pos, newsize, tcpos, tcposend; 402*55868Sbostic 403*55868Sbostic pos = rp - record; 404*55868Sbostic newsize = r_end - record + diff + BFRAG; 405*55868Sbostic tcpos = tcstart - record; 406*55868Sbostic tcposend = tcend - record; 407*55868Sbostic record = realloc(record, newsize); 408*55868Sbostic if (record == NULL) { 409*55868Sbostic errno = ENOMEM; 410*55868Sbostic if (myfd) 411*55868Sbostic (void)close(fd); 412*55868Sbostic free(icap); 413*55868Sbostic return (-2); 414*55868Sbostic } 415*55868Sbostic r_end = record + newsize; 416*55868Sbostic rp = record + pos; 417*55868Sbostic tcstart = record + tcpos; 418*55868Sbostic tcend = record + tcposend; 419*55868Sbostic } 420*55868Sbostic 421*55868Sbostic /* 422*55868Sbostic * Insert tc'ed record into our record. 423*55868Sbostic */ 424*55868Sbostic s = tcstart + newilen; 425*55868Sbostic bcopy(tcend, s, rp - tcend); 426*55868Sbostic bcopy(newicap, tcstart, newilen); 427*55868Sbostic rp += diff; 428*55868Sbostic free(icap); 429*55868Sbostic 430*55868Sbostic /* 431*55868Sbostic * Start scan on `:' so next cgetcap works properly 432*55868Sbostic * (cgetcap always skips first field). 433*55868Sbostic */ 434*55868Sbostic scan = s-1; 435*55868Sbostic } 436*55868Sbostic } 437*55868Sbostic 438*55868Sbostic /* 439*55868Sbostic * Close file (if we opened it), give back any extra memory, and 440*55868Sbostic * return capability, length and success. 441*55868Sbostic */ 442*55868Sbostic if (myfd) 443*55868Sbostic (void)close(fd); 444*55868Sbostic *len = rp - record - 1; /* don't count NUL */ 445*55868Sbostic if (r_end > rp) 446*55868Sbostic record = realloc(record, (u_int)(rp - record)); 447*55868Sbostic *cap = record; 448*55868Sbostic return (0); 449*55868Sbostic } 450*55868Sbostic 451*55868Sbostic /* 452*55868Sbostic * Cgetmatch will return 0 if name is one of the names of the capability 453*55868Sbostic * record buf, -1 if not. 454*55868Sbostic */ 455*55868Sbostic int 456*55868Sbostic cgetmatch(buf, name) 457*55868Sbostic char *buf, *name; 458*55868Sbostic { 459*55868Sbostic register char *np, *bp; 460*55868Sbostic 461*55868Sbostic /* 462*55868Sbostic * Start search at beginning of record. 463*55868Sbostic */ 464*55868Sbostic bp = buf; 465*55868Sbostic for (;;) { 466*55868Sbostic /* 467*55868Sbostic * Try to match a record name. 468*55868Sbostic */ 469*55868Sbostic np = name; 470*55868Sbostic for (;;) 471*55868Sbostic if (*np == '\0') 472*55868Sbostic if (*bp == '|' || *bp == ':' || *bp == '\0') 473*55868Sbostic return (0); 474*55868Sbostic else 475*55868Sbostic break; 476*55868Sbostic else 477*55868Sbostic if (*bp++ != *np++) 478*55868Sbostic break; 479*55868Sbostic 480*55868Sbostic /* 481*55868Sbostic * Match failed, skip to next name in record. 482*55868Sbostic */ 483*55868Sbostic bp--; /* a '|' or ':' may have stopped the match */ 484*55868Sbostic for (;;) 485*55868Sbostic if (*bp == '\0' || *bp == ':') 486*55868Sbostic return (-1); /* match failed totally */ 487*55868Sbostic else 488*55868Sbostic if (*bp++ == '|') 489*55868Sbostic break; /* found next name */ 490*55868Sbostic } 491*55868Sbostic } 492*55868Sbostic 493*55868Sbostic int 494*55868Sbostic cgetfirst(buf, db_array) 495*55868Sbostic char **buf, **db_array; 496*55868Sbostic { 497*55868Sbostic (void)cgetclose(); 498*55868Sbostic return (cgetnext(buf, db_array)); 499*55868Sbostic } 500*55868Sbostic 501*55868Sbostic static FILE *pfp; 502*55868Sbostic static int slash; 503*55868Sbostic static char **dbp; 504*55868Sbostic 505*55868Sbostic int 506*55868Sbostic cgetclose() 507*55868Sbostic { 508*55868Sbostic if (pfp != NULL) { 509*55868Sbostic (void)fclose(pfp); 510*55868Sbostic pfp = NULL; 511*55868Sbostic } 512*55868Sbostic dbp = NULL; 513*55868Sbostic slash = 0; 514*55868Sbostic return (0); 515*55868Sbostic } 516*55868Sbostic 517*55868Sbostic /* 518*55868Sbostic * Cgetnext() gets either the first or next entry in the logical database 519*55868Sbostic * specified by db_array. It returns 0 upon completion of the database, 1 520*55868Sbostic * upon returning an entry with more remaining, and -1 if an error occurs. 521*55868Sbostic */ 522*55868Sbostic int 523*55868Sbostic cgetnext(bp, db_array) 524*55868Sbostic register char **bp; 525*55868Sbostic char **db_array; 526*55868Sbostic { 527*55868Sbostic size_t len; 528*55868Sbostic int status; 529*55868Sbostic char *cp, *line, *rp, buf[BSIZE]; 530*55868Sbostic 531*55868Sbostic if (dbp == NULL) 532*55868Sbostic dbp = db_array; 533*55868Sbostic 534*55868Sbostic if (pfp == NULL && (pfp = fopen(*dbp, "r")) == NULL) 535*55868Sbostic return (-1); 536*55868Sbostic 537*55868Sbostic for(;;) { 538*55868Sbostic line = fgetline(pfp, &len); 539*55868Sbostic if (line == NULL) { 540*55868Sbostic (void)fclose(pfp); 541*55868Sbostic if (ferror(pfp)) { 542*55868Sbostic pfp = NULL; 543*55868Sbostic dbp = NULL; 544*55868Sbostic slash = 0; 545*55868Sbostic return (-1); 546*55868Sbostic } else { 547*55868Sbostic dbp++; 548*55868Sbostic if (*dbp == NULL) { 549*55868Sbostic pfp = NULL; 550*55868Sbostic dbp = NULL; 551*55868Sbostic slash = 0; 552*55868Sbostic return (0); 553*55868Sbostic } else if ((pfp = fopen(*dbp, "r")) == NULL) { 554*55868Sbostic pfp = NULL; 555*55868Sbostic dbp = NULL; 556*55868Sbostic slash = 0; 557*55868Sbostic return (-1); 558*55868Sbostic } else 559*55868Sbostic continue; 560*55868Sbostic } 561*55868Sbostic } 562*55868Sbostic if (isspace(*line) || *line == ':' || *line == '#' 563*55868Sbostic || len == 0 || slash) { 564*55868Sbostic if (len > 0 && line[len - 1] == '\\') 565*55868Sbostic slash = 1; 566*55868Sbostic else 567*55868Sbostic slash = 0; 568*55868Sbostic continue; 569*55868Sbostic } 570*55868Sbostic if (len > 0 && line[len - 1] == '\\') 571*55868Sbostic slash = 1; 572*55868Sbostic else 573*55868Sbostic slash = 0; 574*55868Sbostic 575*55868Sbostic /* line points to a name line */ 576*55868Sbostic 577*55868Sbostic rp = buf; 578*55868Sbostic for(cp = line; *cp != NULL; cp++) 579*55868Sbostic if (*cp == '|' || *cp == ':') 580*55868Sbostic break; 581*55868Sbostic else 582*55868Sbostic *rp++ = *cp; 583*55868Sbostic 584*55868Sbostic *rp = '\0'; 585*55868Sbostic status = cgetent(bp, db_array, &buf[0]); 586*55868Sbostic if (status == 0) 587*55868Sbostic return (1); 588*55868Sbostic if (status == -2 || status == -3) { 589*55868Sbostic pfp = NULL; 590*55868Sbostic dbp = NULL; 591*55868Sbostic slash = 0; 592*55868Sbostic return (status + 1); 593*55868Sbostic } 594*55868Sbostic } 595*55868Sbostic /* NOTREACHED */ 596*55868Sbostic } 597*55868Sbostic 598*55868Sbostic /* 599*55868Sbostic * Cgetstr retrieves the value of the string capability cap from the 600*55868Sbostic * capability record pointed to by buf. A pointer to a decoded, NUL 601*55868Sbostic * terminated, malloc'd copy of the string is returned in the char * 602*55868Sbostic * pointed to by str. The length of the string not including the trailing 603*55868Sbostic * NUL is returned on success, -1 if the requested string capability 604*55868Sbostic * couldn't be found, -2 if a system error was encountered (storage 605*55868Sbostic * allocation failure). 606*55868Sbostic */ 607*55868Sbostic int 608*55868Sbostic cgetstr(buf, cap, str) 609*55868Sbostic char *buf, *cap; 610*55868Sbostic char **str; 611*55868Sbostic { 612*55868Sbostic register u_int m_room; 613*55868Sbostic register char *bp, *mp; 614*55868Sbostic int len; 615*55868Sbostic char *mem; 616*55868Sbostic 617*55868Sbostic /* 618*55868Sbostic * Find string capability cap 619*55868Sbostic */ 620*55868Sbostic bp = cgetcap(buf, cap, '='); 621*55868Sbostic if (bp == NULL) 622*55868Sbostic return (-1); 623*55868Sbostic 624*55868Sbostic /* 625*55868Sbostic * Conversion / storage allocation loop ... Allocate memory in 626*55868Sbostic * chunks SFRAG in size. 627*55868Sbostic */ 628*55868Sbostic if ((mem = malloc(SFRAG)) == NULL) { 629*55868Sbostic errno = ENOMEM; 630*55868Sbostic return (-2); /* couldn't even allocate the first fragment */ 631*55868Sbostic } 632*55868Sbostic m_room = SFRAG; 633*55868Sbostic mp = mem; 634*55868Sbostic 635*55868Sbostic while (*bp != ':' && *bp != '\0') { 636*55868Sbostic /* 637*55868Sbostic * Loop invariants: 638*55868Sbostic * There is always room for one more character in mem. 639*55868Sbostic * Mp always points just past last character in mem. 640*55868Sbostic * Bp always points at next character in buf. 641*55868Sbostic */ 642*55868Sbostic if (*bp == '^') { 643*55868Sbostic bp++; 644*55868Sbostic if (*bp == ':' || *bp == '\0') 645*55868Sbostic break; /* drop unfinished escape */ 646*55868Sbostic *mp++ = *bp++ & 037; 647*55868Sbostic } else if (*bp == '\\') { 648*55868Sbostic bp++; 649*55868Sbostic if (*bp == ':' || *bp == '\0') 650*55868Sbostic break; /* drop unfinished escape */ 651*55868Sbostic if ('0' <= *bp && *bp <= '7') { 652*55868Sbostic register int n, i; 653*55868Sbostic 654*55868Sbostic n = 0; 655*55868Sbostic i = 3; /* maximum of three octal digits */ 656*55868Sbostic do { 657*55868Sbostic n = n * 8 + (*bp++ - '0'); 658*55868Sbostic } while (--i && '0' <= *bp && *bp <= '7'); 659*55868Sbostic *mp++ = n; 660*55868Sbostic } 661*55868Sbostic else switch (*bp++) { 662*55868Sbostic case 'b': case 'B': 663*55868Sbostic *mp++ = '\b'; 664*55868Sbostic break; 665*55868Sbostic case 't': case 'T': 666*55868Sbostic *mp++ = '\t'; 667*55868Sbostic break; 668*55868Sbostic case 'n': case 'N': 669*55868Sbostic *mp++ = '\n'; 670*55868Sbostic break; 671*55868Sbostic case 'f': case 'F': 672*55868Sbostic *mp++ = '\f'; 673*55868Sbostic break; 674*55868Sbostic case 'r': case 'R': 675*55868Sbostic *mp++ = '\r'; 676*55868Sbostic break; 677*55868Sbostic case 'e': case 'E': 678*55868Sbostic *mp++ = ESC; 679*55868Sbostic break; 680*55868Sbostic case 'c': case 'C': 681*55868Sbostic *mp++ = ':'; 682*55868Sbostic break; 683*55868Sbostic default: 684*55868Sbostic /* 685*55868Sbostic * Catches '\', '^', and 686*55868Sbostic * everything else. 687*55868Sbostic */ 688*55868Sbostic *mp++ = *(bp-1); 689*55868Sbostic break; 690*55868Sbostic } 691*55868Sbostic } else 692*55868Sbostic *mp++ = *bp++; 693*55868Sbostic m_room--; 694*55868Sbostic 695*55868Sbostic /* 696*55868Sbostic * Enforce loop invariant: if no room left in current 697*55868Sbostic * buffer, try to get some more. 698*55868Sbostic */ 699*55868Sbostic if (m_room == 0) { 700*55868Sbostic u_int size = mp - mem; 701*55868Sbostic 702*55868Sbostic if ((mem = realloc(mem, size + SFRAG)) == NULL) 703*55868Sbostic return (-2); 704*55868Sbostic m_room = SFRAG; 705*55868Sbostic mp = mem + size; 706*55868Sbostic } 707*55868Sbostic } 708*55868Sbostic *mp++ = '\0'; /* loop invariant let's us do this */ 709*55868Sbostic m_room--; 710*55868Sbostic len = mp - mem - 1; 711*55868Sbostic 712*55868Sbostic /* 713*55868Sbostic * Give back any extra memory and return value and success. 714*55868Sbostic */ 715*55868Sbostic if (m_room != 0) 716*55868Sbostic mem = realloc(mem, (u_int)(mp - mem)); 717*55868Sbostic *str = mem; 718*55868Sbostic return (len); 719*55868Sbostic } 720*55868Sbostic 721*55868Sbostic /* 722*55868Sbostic * Cgetustr retrieves the value of the string capability cap from the 723*55868Sbostic * capability record pointed to by buf. The difference between cgetustr() 724*55868Sbostic * and cgetstr() is that cgetustr does not decode escapes but rather treats 725*55868Sbostic * all characters literally. A pointer to a NUL terminated malloc'd 726*55868Sbostic * copy of the string is returned in the char pointed to by str. The 727*55868Sbostic * length of the string not including the trailing NUL is returned on success, 728*55868Sbostic * -1 if the requested string capability couldn't be found, -2 if a system 729*55868Sbostic * error was encountered (storage allocation failure). 730*55868Sbostic */ 731*55868Sbostic int 732*55868Sbostic cgetustr(buf, cap, str) 733*55868Sbostic char *buf, *cap, **str; 734*55868Sbostic { 735*55868Sbostic register u_int m_room; 736*55868Sbostic register char *bp, *mp; 737*55868Sbostic int len; 738*55868Sbostic char *mem; 739*55868Sbostic 740*55868Sbostic /* 741*55868Sbostic * Find string capability cap 742*55868Sbostic */ 743*55868Sbostic if ((bp = cgetcap(buf, cap, '=')) == NULL) 744*55868Sbostic return (-1); 745*55868Sbostic 746*55868Sbostic /* 747*55868Sbostic * Conversion / storage allocation loop ... Allocate memory in 748*55868Sbostic * chunks SFRAG in size. 749*55868Sbostic */ 750*55868Sbostic if ((mem = malloc(SFRAG)) == NULL) { 751*55868Sbostic errno = ENOMEM; 752*55868Sbostic return (-2); /* couldn't even allocate the first fragment */ 753*55868Sbostic } 754*55868Sbostic m_room = SFRAG; 755*55868Sbostic mp = mem; 756*55868Sbostic 757*55868Sbostic while (*bp != ':' && *bp != '\0') { 758*55868Sbostic /* 759*55868Sbostic * Loop invariants: 760*55868Sbostic * There is always room for one more character in mem. 761*55868Sbostic * Mp always points just past last character in mem. 762*55868Sbostic * Bp always points at next character in buf. 763*55868Sbostic */ 764*55868Sbostic *mp++ = *bp++; 765*55868Sbostic m_room--; 766*55868Sbostic 767*55868Sbostic /* 768*55868Sbostic * Enforce loop invariant: if no room left in current 769*55868Sbostic * buffer, try to get some more. 770*55868Sbostic */ 771*55868Sbostic if (m_room == 0) { 772*55868Sbostic u_int size = mp - mem; 773*55868Sbostic 774*55868Sbostic if ((mem = realloc(mem, size + SFRAG)) == NULL) 775*55868Sbostic return (-2); 776*55868Sbostic m_room = SFRAG; 777*55868Sbostic mp = mem + size; 778*55868Sbostic } 779*55868Sbostic } 780*55868Sbostic *mp++ = '\0'; /* loop invariant let's us do this */ 781*55868Sbostic m_room--; 782*55868Sbostic len = mp - mem - 1; 783*55868Sbostic 784*55868Sbostic /* 785*55868Sbostic * Give back any extra memory and return value and success. 786*55868Sbostic */ 787*55868Sbostic if (m_room != 0) 788*55868Sbostic mem = realloc(mem, (u_int)(mp - mem)); 789*55868Sbostic *str = mem; 790*55868Sbostic return (len); 791*55868Sbostic } 792*55868Sbostic 793*55868Sbostic /* 794*55868Sbostic * Cgetnum retrieves the value of the numeric capability cap from the 795*55868Sbostic * capability record pointed to by buf. The numeric value is returned in 796*55868Sbostic * the long pointed to by num. 0 is returned on success, -1 if the requested 797*55868Sbostic * numeric capability couldn't be found. 798*55868Sbostic */ 799*55868Sbostic int 800*55868Sbostic cgetnum(buf, cap, num) 801*55868Sbostic char *buf, *cap; 802*55868Sbostic long *num; 803*55868Sbostic { 804*55868Sbostic register long n; 805*55868Sbostic register int base, digit; 806*55868Sbostic register char *bp; 807*55868Sbostic 808*55868Sbostic /* 809*55868Sbostic * Find numeric capability cap 810*55868Sbostic */ 811*55868Sbostic bp = cgetcap(buf, cap, '#'); 812*55868Sbostic if (bp == NULL) 813*55868Sbostic return (-1); 814*55868Sbostic 815*55868Sbostic /* 816*55868Sbostic * Look at value and determine numeric base: 817*55868Sbostic * 0x... or 0X... hexadecimal, 818*55868Sbostic * else 0... octal, 819*55868Sbostic * else decimal. 820*55868Sbostic */ 821*55868Sbostic if (*bp == '0') { 822*55868Sbostic bp++; 823*55868Sbostic if (*bp == 'x' || *bp == 'X') { 824*55868Sbostic bp++; 825*55868Sbostic base = 16; 826*55868Sbostic } else 827*55868Sbostic base = 8; 828*55868Sbostic } else 829*55868Sbostic base = 10; 830*55868Sbostic 831*55868Sbostic /* 832*55868Sbostic * Conversion loop ... 833*55868Sbostic */ 834*55868Sbostic n = 0; 835*55868Sbostic for (;;) { 836*55868Sbostic if ('0' <= *bp && *bp <= '9') 837*55868Sbostic digit = *bp - '0'; 838*55868Sbostic else 839*55868Sbostic if ( ('a' <= *bp && *bp <= 'f') 840*55868Sbostic || ('A' <= *bp && *bp <= 'F')) 841*55868Sbostic digit = 10 + *bp - 'a'; 842*55868Sbostic else 843*55868Sbostic break; 844*55868Sbostic 845*55868Sbostic if (digit >= base) 846*55868Sbostic break; 847*55868Sbostic 848*55868Sbostic n = n * base + digit; 849*55868Sbostic bp++; 850*55868Sbostic } 851*55868Sbostic 852*55868Sbostic /* 853*55868Sbostic * Return value and success. 854*55868Sbostic */ 855*55868Sbostic *num = n; 856*55868Sbostic return (0); 857*55868Sbostic } 858