The `getpwent_r` function is a non-standard but reentrant version of the
POSIX-defined `getpwent` function. While it should provide the benefit
of being safe to use in multi-threaded environments, it disallows us
from compiling with libc implementations which stick to the POSIX
standard more closely.
As libsemanage may be used in a multi-threaded environment, being
reentrant may in fact be quite important to us. As such, simply
switching out `getpwent_r` against its non-reentrant function can prove
quite dangerous. But interestingly enough, the glibc implementation of
`getpwent_r` does not even guarantee being reentrant. Quoting from
getpwent_r(7):
NOTES
The function getpwent_r() is not really reentrant since it shares
the reading position in the stream with all other threads.
As such, it is non-reentrant in the same sense as its simple `getpwent`
brother and can simply be switched out without losing any guarantees
here.
Signed-off-by: Patrick Steinhardt <[email protected]>
---
libsemanage/src/genhomedircon.c | 34 +++++++---------------------------
1 file changed, 7 insertions(+), 27 deletions(-)
diff --git a/libsemanage/src/genhomedircon.c b/libsemanage/src/genhomedircon.c
index e8c95ee4..b9a74b73 100644
--- a/libsemanage/src/genhomedircon.c
+++ b/libsemanage/src/genhomedircon.c
@@ -290,14 +290,11 @@ static semanage_list_t
*get_home_dirs(genhomedircon_settings_t * s)
semanage_list_t *homedir_list = NULL;
semanage_list_t *shells = NULL;
fc_match_handle_t hand;
- char *rbuf = NULL;
char *path = NULL;
- long rbuflen;
uid_t temp, minuid = 500, maxuid = 60000;
int minuid_set = 0;
- struct passwd pwstorage, *pwbuf;
+ struct passwd *pwbuf;
struct stat buf;
- int retval;
path = semanage_findval(PATH_ETC_USERADD, "HOME", "=");
if (path && *path) {
@@ -362,14 +359,9 @@ static semanage_list_t
*get_home_dirs(genhomedircon_settings_t * s)
free(path);
path = NULL;
- rbuflen = sysconf(_SC_GETPW_R_SIZE_MAX);
- if (rbuflen <= 0)
- goto fail;
- rbuf = malloc(rbuflen);
- if (rbuf == NULL)
- goto fail;
+ errno = 0;
setpwent();
- while ((retval = getpwent_r(&pwstorage, rbuf, rbuflen, &pwbuf)) == 0) {
+ while ((pwbuf = getpwent()) != NULL) {
if (pwbuf->pw_uid < minuid || pwbuf->pw_uid > maxuid)
continue;
if (!semanage_list_find(shells, pwbuf->pw_shell))
@@ -411,9 +403,10 @@ static semanage_list_t
*get_home_dirs(genhomedircon_settings_t * s)
}
free(path);
path = NULL;
+ errno = 0;
}
- if (retval && retval != ENOENT) {
+ if (errno) {
WARN(s->h_semanage, "Error while fetching users. "
"Returning list so far.");
}
@@ -422,14 +415,12 @@ static semanage_list_t
*get_home_dirs(genhomedircon_settings_t * s)
goto fail;
endpwent();
- free(rbuf);
semanage_list_destroy(&shells);
return homedir_list;
fail:
endpwent();
- free(rbuf);
free(path);
semanage_list_destroy(&homedir_list);
semanage_list_destroy(&shells);
@@ -1064,10 +1055,7 @@ static int get_group_users(genhomedircon_settings_t * s,
long grbuflen;
char *grbuf = NULL;
struct group grstorage, *group = NULL;
-
- long prbuflen;
- char *pwbuf = NULL;
- struct passwd pwstorage, *pw = NULL;
+ struct passwd *pw = NULL;
grbuflen = sysconf(_SC_GETGR_R_SIZE_MAX);
if (grbuflen <= 0)
@@ -1104,15 +1092,8 @@ static int get_group_users(genhomedircon_settings_t * s,
}
}
- prbuflen = sysconf(_SC_GETPW_R_SIZE_MAX);
- if (prbuflen <= 0)
- goto cleanup;
- pwbuf = malloc(prbuflen);
- if (pwbuf == NULL)
- goto cleanup;
-
setpwent();
- while ((retval = getpwent_r(&pwstorage, pwbuf, prbuflen, &pw)) == 0) {
+ while ((pw = getpwent()) != NULL) {
// skip users who also have this group as their
// primary group
if (lfind(pw->pw_name, group->gr_mem, &nmembers,
@@ -1131,7 +1112,6 @@ static int get_group_users(genhomedircon_settings_t * s,
retval = STATUS_SUCCESS;
cleanup:
endpwent();
- free(pwbuf);
free(grbuf);
return retval;
--
2.13.1