libc/nss: Restore iterator state when doing passwd/group lookups

The getpwent(3) and getgrent(3) implementations maintain some internal
iterator state.  Interleaved calls to functions which do passwd/group
lookups using a key, such as getpwnam(3), would in some cases clobber
this state, causing a subsequent getpwent() or getgrent() call to
restart iteration from the beginning of the database or to terminate
early.  This is particularly troublesome in programming environments
where execution of green threads is interleaved within a single OS
thread.

Take care to restore any iterator state following a keyed lookup.  The
"files" provider for the passwd database was already handling this
correctly, but "compat" was not, and both providers had this problem
when accessing the group database.

PR:		252094
Submitted by:	Viktor Dukhovni <ietf-dane@dukhovni.org>
MFC after:	1 month
This commit is contained in:
Mark Johnston 2021-01-21 14:30:19 -05:00
parent 7abc10098b
commit 5619d49e07
2 changed files with 26 additions and 26 deletions

View file

@ -882,16 +882,12 @@ files_group(void *retval, void *mdata, va_list ap)
}
fresh = 1;
}
if (how == nss_lt_all)
stayopen = 1;
else {
if (!fresh)
rewind(st->fp);
stayopen = st->stayopen;
}
rv = NS_NOTFOUND;
stayopen = (how == nss_lt_all || !fresh) ? 1 : st->stayopen;
if (stayopen)
pos = ftello(st->fp);
if (how != nss_lt_all && !fresh)
rewind(st->fp);
rv = NS_NOTFOUND;
while ((line = fgetln(st->fp, &linesize)) != NULL) {
if (line[linesize-1] == '\n')
linesize--;
@ -913,13 +909,15 @@ files_group(void *retval, void *mdata, va_list ap)
&buffer[linesize + 1], bufsize - linesize - 1, errnop);
if (rv & NS_TERMINATE)
break;
if (stayopen)
if (how == nss_lt_all)
pos = ftello(st->fp);
}
if (st->fp != NULL && !stayopen) {
fclose(st->fp);
st->fp = NULL;
}
if (st->fp != NULL && how != nss_lt_all)
fseeko(st->fp, pos, SEEK_SET);
if (rv == NS_SUCCESS && retval != NULL)
*(struct group **)retval = grp;
else if (rv == NS_RETURN && *errnop == ERANGE && st->fp != NULL)
@ -1364,13 +1362,11 @@ compat_group(void *retval, void *mdata, va_list ap)
}
fresh = 1;
}
if (how == nss_lt_all)
stayopen = 1;
else {
if (!fresh)
rewind(st->fp);
stayopen = st->stayopen;
}
stayopen = (how == nss_lt_all || !fresh) ? 1 : st->stayopen;
if (stayopen)
pos = ftello(st->fp);
if (how != nss_lt_all && !fresh)
rewind(st->fp);
docompat:
switch (st->compat) {
case COMPAT_MODE_ALL:
@ -1431,8 +1427,6 @@ compat_group(void *retval, void *mdata, va_list ap)
break;
}
rv = NS_NOTFOUND;
if (stayopen)
pos = ftello(st->fp);
while ((line = fgetln(st->fp, &linesize)) != NULL) {
if (line[linesize-1] == '\n')
linesize--;
@ -1473,7 +1467,7 @@ compat_group(void *retval, void *mdata, va_list ap)
&buffer[linesize + 1], bufsize - linesize - 1, errnop);
if (rv & NS_TERMINATE)
break;
if (stayopen)
if (how == nss_lt_all)
pos = ftello(st->fp);
}
fin:
@ -1481,6 +1475,8 @@ compat_group(void *retval, void *mdata, va_list ap)
fclose(st->fp);
st->fp = NULL;
}
if (st->fp != NULL && how != nss_lt_all)
fseeko(st->fp, pos, SEEK_SET);
if (rv == NS_SUCCESS && retval != NULL)
*(struct group **)retval = grp;
else if (rv == NS_RETURN && *errnop == ERANGE && st->fp != NULL)

View file

@ -1733,6 +1733,7 @@ compat_passwd(void *retval, void *mdata, va_list ap)
{
char keybuf[MAXLOGNAME + 1];
DBT key, entry;
pwkeynum keynum;
struct compat_state *st;
enum nss_lookup_type how;
const char *name;
@ -1783,9 +1784,10 @@ compat_passwd(void *retval, void *mdata, va_list ap)
rv = NS_NOTFOUND;
goto fin;
}
keynum = st->keynum;
stayopen = 1;
} else {
st->keynum = 0;
keynum = 0;
stayopen = st->stayopen;
}
docompat:
@ -1829,13 +1831,13 @@ compat_passwd(void *retval, void *mdata, va_list ap)
}
key.data = keybuf;
rv = NS_NOTFOUND;
while (st->keynum >= 0) {
st->keynum++;
while (keynum >= 0) {
keynum++;
if (st->version < _PWD_CURRENT_VERSION) {
memcpy(&keybuf[1], &st->keynum, sizeof(st->keynum));
key.size = sizeof(st->keynum) + 1;
memcpy(&keybuf[1], &keynum, sizeof(keynum));
key.size = sizeof(keynum) + 1;
} else {
store = htonl(st->keynum);
store = htonl(keynum);
memcpy(&keybuf[1], &store, sizeof(store));
key.size = sizeof(store) + 1;
}
@ -1846,7 +1848,7 @@ compat_passwd(void *retval, void *mdata, va_list ap)
rv = NS_UNAVAIL;
goto fin;
} else if (rv == 1) {
st->keynum = -1;
keynum = -1;
rv = NS_NOTFOUND;
goto fin;
}
@ -1931,6 +1933,8 @@ compat_passwd(void *retval, void *mdata, va_list ap)
break;
}
fin:
if (how == nss_lt_all)
st->keynum = keynum;
if (st->db != NULL && !stayopen) {
(void)st->db->close(st->db);
st->db = NULL;