version 1.17, 2011/07/04 21:34:54 |
version 1.18, 2011/07/22 01:11:05 |
|
|
#define TCERR (char)1 |
#define TCERR (char)1 |
#define SHADOW (char)2 |
#define SHADOW (char)2 |
|
|
static int getent(char **, u_int *, char **, int, char *, int); |
static int getent(char **, u_int *, char **, FILE *, char *, int); |
static char *igetcap(char *, char *, int); |
static char *igetcap(char *, char *, int); |
static int igetmatch(char *, char *); |
static int igetmatch(char *, char *); |
static int igetclose(void); |
static int igetclose(void); |
|
|
} |
} |
|
|
/* |
/* |
* Getent implements the functions of igetent. If fd is non-negative, |
* Getent implements the functions of igetent. If fp is non-NULL, |
* *db_array has already been opened and fd is the open file descriptor. We |
* *db_array has already been opened and fp is the open file descriptor. We |
* do this to save time and avoid using up file descriptors for use= |
* do this to save time and avoid using up file descriptors for use= |
* recursions. |
* recursions. |
* |
* |
|
|
* MAX_RECURSION. |
* MAX_RECURSION. |
*/ |
*/ |
static int |
static int |
getent(char **cap, u_int *len, char **db_array, int fd, char *name, int depth) |
getent(char **cap, u_int *len, char **db_array, FILE *fp, char *name, int depth) |
{ |
{ |
char *r_end, *rp, **db_p; |
char *r_end, *rp, **db_p; |
int myfd, eof, foundit; |
int myfd, eof, foundit; |
|
|
if (depth > MAX_RECURSION) |
if (depth > MAX_RECURSION) |
return (-3); |
return (-3); |
|
|
|
/* |
|
* If no name we better have a record in cap |
|
*/ |
|
if (depth == 0 && name == NULL) { |
|
if ((record = malloc(*len + 1 + BFRAG)) == NULL) |
|
return (-2); |
|
memcpy(record, *cap, *len); |
|
myfd = 0; |
|
db_p = db_array; |
|
rp = record + *len + 1; |
|
r_end = rp + BFRAG; |
|
*rp = '\0'; |
|
goto exp_use; |
|
} |
|
|
/* |
/* |
* Allocate first chunk of memory. |
* Allocate first chunk of memory. |
*/ |
*/ |
|
|
foundit = 0; |
foundit = 0; |
rp = NULL; |
rp = NULL; |
myfd = -1; |
myfd = -1; |
|
|
/* |
/* |
* Loop through database array until finding the record. |
* Loop through database array until finding the record. |
*/ |
*/ |
|
|
for (db_p = db_array; *db_p != NULL; db_p++) { |
for (db_p = db_array; *db_p != NULL; db_p++) { |
eof = 0; |
eof = 0; |
|
|
|
|
* Open database if not already open. |
* Open database if not already open. |
*/ |
*/ |
|
|
if (fd >= 0) { |
if (fp != NULL) { |
(void)lseek(fd, (off_t)0, SEEK_SET); |
(void)fseek(fp, 0L, SEEK_SET); |
myfd = 0; |
myfd = 0; |
} else { |
} else { |
fd = open(*db_p, O_RDONLY, 0); |
fp = fopen(*db_p, "r"); |
if (fd < 0) { |
if (fp == NULL) { |
/* No error on unfound file. */ |
/* No error on unfound file. */ |
continue; |
continue; |
} |
} |
|
|
for (;;) { |
for (;;) { |
|
|
/* |
/* |
* Read in a line implementing (\, newline) |
* Read in a record implementing line continuation. |
* line continuation. |
|
*/ |
*/ |
rp = record; |
rp = record; |
for (;;) { |
for (;;) { |
if (bp >= b_end) { |
if (bp >= b_end) { |
int n; |
size_t n; |
|
|
n = read(fd, buf, sizeof(buf)); |
n = fread(buf, 1, sizeof(buf), fp); |
if (n <= 0) { |
if (n == 0) { |
|
eof = feof(fp); |
if (myfd) |
if (myfd) |
(void)close(fd); |
(void)fclose(fp); |
if (n < 0) { |
if (eof) { |
free(record); |
fp = NULL; |
return (-2); |
|
} else { |
|
fd = -1; |
|
eof = 1; |
|
break; |
break; |
} |
} |
|
free(record); |
|
return (-2); |
} |
} |
b_end = buf+n; |
b_end = buf+n; |
bp = buf; |
bp = buf; |
|
|
c = *bp++; |
c = *bp++; |
if (c == '\n') { |
if (c == '\n') { |
if (bp >= b_end) { |
if (bp >= b_end) { |
int n; |
size_t n; |
|
|
n = read(fd, buf, sizeof(buf)); |
n = fread(buf, 1, sizeof(buf), fp); |
if (n <= 0) { |
if (n == 0) { |
|
eof = feof(fp); |
if (myfd) |
if (myfd) |
(void)close(fd); |
(void)fclose(fp); |
if (n < 0) { |
if (eof) { |
free(record); |
fp = NULL; |
return (-2); |
|
} else { |
|
fd = -1; |
|
eof = 1; |
|
break; |
break; |
} |
} |
|
free(record); |
|
return (-2); |
} |
} |
b_end = buf+n; |
b_end = buf+n; |
bp = buf; |
bp = buf; |
|
|
* some more. |
* some more. |
*/ |
*/ |
if (rp >= r_end) { |
if (rp >= r_end) { |
u_int pos; |
size_t off; |
size_t newsize; |
size_t newsize; |
|
|
pos = rp - record; |
off = rp - record; |
newsize = r_end - record + BFRAG; |
newsize = r_end - record + BFRAG; |
s = realloc(record, newsize); |
s = realloc(record, newsize); |
if (s == NULL) { |
if (s == NULL) { |
free(record); |
free(record); |
errno = ENOMEM; |
errno = ENOMEM; |
if (myfd) |
if (myfd) |
(void)close(fd); |
(void)fclose(fp); |
return (-2); |
return (-2); |
} |
} |
record = s; |
record = s; |
r_end = record + newsize; |
r_end = record + newsize; |
rp = record + pos; |
rp = record + off; |
} |
} |
} |
} |
/* loop invariant lets us do this */ |
/* loop invariant lets us do this */ |
|
|
* Got the capability record, but now we have to expand all use=name |
* Got the capability record, but now we have to expand all use=name |
* references in it ... |
* references in it ... |
*/ |
*/ |
{ |
exp_use: { |
char *newicap; |
char *newicap; |
int newilen; |
int newilen; |
u_int ilen; |
u_int ilen; |
|
|
tclen = s - tcstart; |
tclen = s - tcstart; |
tcend = s; |
tcend = s; |
|
|
iret = getent(&icap, &ilen, db_p, fd, tc, depth+1); |
iret = getent(&icap, &ilen, db_p, fp, tc, depth+1); |
newicap = icap; /* Put into a register. */ |
newicap = icap; /* Put into a register. */ |
newilen = ilen; |
newilen = ilen; |
if (iret != 0) { |
if (iret != 0) { |
/* an error */ |
/* an error */ |
if (iret < -1) { |
if (iret < -1) { |
if (myfd) |
if (myfd) |
(void)close(fd); |
(void)fclose(fp); |
free(record); |
free(record); |
return (iret); |
return (iret); |
} |
} |
|
|
*/ |
*/ |
diff = newilen - tclen; |
diff = newilen - tclen; |
if (diff >= r_end - rp) { |
if (diff >= r_end - rp) { |
u_int pos, tcpos, tcposend; |
size_t off, tcoff, tcoffend; |
size_t newsize; |
size_t newsize; |
|
|
pos = rp - record; |
off = rp - record; |
newsize = r_end - record + diff + BFRAG; |
newsize = r_end - record + diff + BFRAG; |
tcpos = tcstart - record; |
tcoff = tcstart - record; |
tcposend = tcend - record; |
tcoffend = tcend - record; |
s = realloc(record, newsize); |
s = realloc(record, newsize); |
if (s == NULL) { |
if (s == NULL) { |
free(record); |
free(record); |
errno = ENOMEM; |
errno = ENOMEM; |
if (myfd) |
if (myfd) |
(void)close(fd); |
(void)fclose(fp); |
free(icap); |
free(icap); |
return (-2); |
return (-2); |
} |
} |
record = s; |
record = s; |
r_end = record + newsize; |
r_end = record + newsize; |
rp = record + pos; |
rp = record + off; |
tcstart = record + tcpos; |
tcstart = record + tcoff; |
tcend = record + tcposend; |
tcend = record + tcoffend; |
} |
} |
|
|
/* |
/* |
|
|
* return capability, length and success. |
* return capability, length and success. |
*/ |
*/ |
if (myfd) |
if (myfd) |
(void)close(fd); |
(void)fclose(fp); |
*len = rp - record - 1; /* don't count NUL */ |
*len = rp - record - 1; /* don't count NUL */ |
if (r_end > rp) { |
if (r_end > rp) { |
if ((s = |
if ((s = |
|
|
* upon returning an entry with more remaining, and -1 if an error occurs. |
* upon returning an entry with more remaining, and -1 if an error occurs. |
*/ |
*/ |
int |
int |
igetnext(char **bp, char **db_array) |
igetnext(char **cap, char **db_array) |
{ |
{ |
size_t len; |
int c, eof = 0, serrno, status = -1; |
int status, done; |
char buf[BUFSIZ]; |
char *cp, *line, *rp, *np, buf[BSIZE], nbuf[BSIZE]; |
char *b_end, *bp, *r_end, *rp; |
u_int dummy; |
char *record = NULL; |
|
u_int len; |
|
off_t pos; |
|
|
if (dbp == NULL) |
if (dbp == NULL) |
dbp = db_array; |
dbp = db_array; |
|
|
if (pfp == NULL && (pfp = fopen(*dbp, "r")) == NULL) { |
if (pfp == NULL && (pfp = fopen(*dbp, "r")) == NULL) |
(void)igetclose(); |
goto done; |
return (-1); |
|
} |
/* |
|
* Allocate first chunk of memory. |
|
*/ |
|
if ((record = malloc(BFRAG)) == NULL) |
|
goto done; |
|
r_end = record + BFRAG; |
|
|
|
/* |
|
* Find the next capability record |
|
*/ |
|
/* |
|
* Loop invariants: |
|
* There is always room for one more character in record. |
|
* R_end always points just past end of record. |
|
* Rp always points just past last character in record. |
|
* B_end always points just past last character in buf. |
|
* Bp always points at next character in buf. |
|
*/ |
|
b_end = buf; |
|
bp = buf; |
for (;;) { |
for (;;) { |
line = fgetln(pfp, &len); |
/* |
if (line == NULL) { |
* If encountered EOF check next file. |
if (ferror(pfp)) { |
*/ |
(void)igetclose(); |
if (eof) { |
return (-1); |
(void)fclose(pfp); |
} else { |
pfp = NULL; |
(void)fclose(pfp); |
if (*++dbp == NULL) { |
pfp = NULL; |
status = 0; |
if (*++dbp == NULL) { |
break; |
(void)igetclose(); |
|
return (0); |
|
} else if ((pfp = |
|
fopen(*dbp, "r")) == NULL) { |
|
(void)igetclose(); |
|
return (-1); |
|
} else |
|
continue; |
|
} |
} |
} else |
if ((pfp = fopen(*dbp, "r")) == NULL) |
line[len - 1] = '\0';/* XXX - assumes newline */ |
break; |
if (len == 1) { |
eof = 0; |
slash = 0; |
|
continue; |
|
} |
} |
if (isspace(*line) || |
|
*line == ',' || *line == '#' || slash) { |
|
if (line[len - 2] == '\\') |
|
slash = 1; |
|
else |
|
slash = 0; |
|
continue; |
|
} |
|
if (line[len - 2] == '\\') |
|
slash = 1; |
|
else |
|
slash = 0; |
|
|
|
/* |
/* |
* Line points to a name line. |
* Read in a record implementing line continuation. |
*/ |
*/ |
done = 0; |
rp = record; |
np = nbuf; |
|
for (;;) { |
for (;;) { |
for (cp = line; *cp != '\0'; cp++) { |
if (bp >= b_end) { |
if (*cp == ',') { |
size_t n; |
*np++ = ','; |
|
done = 1; |
n = fread(buf, 1, sizeof(buf), pfp); |
break; |
if (n == 0) { |
|
eof = feof(pfp); |
|
if (eof) |
|
break; |
|
else |
|
goto done; |
} |
} |
*np++ = *cp; |
b_end = buf + n; |
|
bp = buf; |
} |
} |
if (done) { |
|
*np = '\0'; |
c = *bp++; |
break; |
if (c == '\n') { |
} else { /* name field extends beyond the line */ |
if (bp >= b_end) { |
line = fgetln(pfp, &len); |
size_t n; |
if (line == NULL) { |
|
if (ferror(pfp)) { |
n = fread(buf, 1, sizeof(buf), pfp); |
(void)igetclose(); |
if (n == 0) { |
return (-1); |
eof = feof(pfp); |
|
if (eof) |
|
break; |
|
else |
|
goto done; |
} |
} |
/* Move on to next file. */ |
b_end = buf + n; |
(void)fclose(pfp); |
bp = buf; |
pfp = NULL; |
} |
++dbp; |
if (rp > record && isspace(*bp)) |
/* NUL terminate nbuf. */ |
continue; |
*np = '\0'; |
else |
break; |
break; |
} else |
|
/* XXX - assumes newline */ |
|
line[len - 1] = '\0'; |
|
} |
} |
|
if (rp <= record || *(rp - 1) != ',' || !isspace(c)) |
|
*rp++ = c; |
|
|
|
/* |
|
* Enforce loop invariant: if no room |
|
* left in record buffer, try to get |
|
* some more. |
|
*/ |
|
if (rp >= r_end) { |
|
size_t newsize, off; |
|
char *nrecord; |
|
|
|
off = rp - record; |
|
newsize = r_end - record + BFRAG; |
|
nrecord = realloc(record, newsize); |
|
if (nrecord == NULL) |
|
goto done; |
|
record = nrecord; |
|
r_end = record + newsize; |
|
rp = record + off; |
|
} |
} |
} |
rp = buf; |
/* loop invariant lets us do this */ |
for(cp = nbuf; *cp != '\0'; cp++) |
*rp++ = '\0'; |
if (*cp == '|' || *cp == ',') |
|
break; |
|
else |
|
*rp++ = *cp; |
|
|
|
*rp = '\0'; |
/* |
status = getent(bp, &dummy, db_array, -1, buf, 0); |
* Toss blank lines and comments. |
if (status == -2 || status == -3) |
*/ |
(void)igetclose(); |
if (*record == '\0' || *record == '#') |
|
continue; |
|
|
return (status + 1); |
/* rewind to end of record */ |
|
fseeko(pfp, (off_t)(bp - b_end), SEEK_CUR); |
|
|
|
/* we pass the record to getent() in cap */ |
|
*cap = record; |
|
len = rp - record; |
|
|
|
/* return value of getent() is one less than igetnext() */ |
|
pos = ftello(pfp); |
|
status = getent(cap, &len, dbp, pfp, NULL, 0) + 1; |
|
if (status > 0) |
|
fseeko(pfp, pos, SEEK_SET); |
|
break; |
} |
} |
/* NOTREACHED */ |
done: |
|
serrno = errno; |
|
free(record); |
|
if (status <= 0) |
|
(void)igetclose(); |
|
errno = serrno; |
|
|
|
return (status); |
} |
} |