From f5a1c506c2037991ff69501b4d1cb49f3f41bc07 Mon Sep 17 00:00:00 2001 From: Sebastien Marie Date: Mon, 27 Oct 2025 13:47:27 +0100 Subject: [PATCH 1/2] unixpwd: fix reentrance of unixpwd_setpwd() and unixpwd_setspw() - prefer fgetpwent_r() over getpwent_r() to avoid ETC_PASSWD FILE to be shared against threads - prefer fgetspent_r() over getspent_r() to avoid ETC_SPASSWD FILE to be shared against threads - while here, unlink(2) tmp_name on error in unixpwd_setpwd() to avoid leaving temporary file on error Signed-off-by: Sebastien Marie --- unixpwd/c/unixpwd.c | 42 ++++++++++++++++++++++++++++++++---------- 1 file changed, 32 insertions(+), 10 deletions(-) diff --git a/unixpwd/c/unixpwd.c b/unixpwd/c/unixpwd.c index 6ff872184da..d47f29fd7d1 100644 --- a/unixpwd/c/unixpwd.c +++ b/unixpwd/c/unixpwd.c @@ -86,7 +86,8 @@ unixpwd_setpwd(const char *user, char *password) *pw; char buf[BUFLEN]; int tmp; - FILE *tmp_file; + FILE *tmp_file, + *passwd_file; char tmp_name[PATH_MAX]; struct stat statbuf; int rc; @@ -96,18 +97,28 @@ unixpwd_setpwd(const char *user, char *password) tmp = mkstemp(tmp_name); if (tmp == -1) return errno; - if (stat(ETC_PASSWD, &statbuf) != 0 + + passwd_file = fopen(ETC_PASSWD, "rbe"); + if (passwd_file == NULL) { + rc = errno; + close(tmp); + unlink(tmp_name); + return rc; + } + + if (fstat(fileno(passwd_file), &statbuf) != 0 || fchown(tmp, statbuf.st_uid, statbuf.st_gid) != 0 || fchmod(tmp, statbuf.st_mode) != 0 || (tmp_file = fdopen(tmp, "w")) == NULL) { rc = errno ? errno : EPERM; + fclose(passwd_file); close(tmp); + unlink(tmp_name); return rc; } - setpwent(); while (1) { - rc = getpwent_r(&pwd, buf, BUFLEN, &pw); + rc = fgetpwent_r(passwd_file, &pwd, buf, BUFLEN, &pw); if (rc != 0 || !pw) break; if (!strcmp(user, pw->pw_name)) { @@ -116,8 +127,8 @@ unixpwd_setpwd(const char *user, char *password) } putpwent(pw, tmp_file); } - endpwent(); + fclose(passwd_file); fclose(tmp_file); if (rc != ENOENT) { unlink(tmp_name); @@ -144,7 +155,8 @@ unixpwd_setspw(const char *user, char *password) *sp; char buf[BUFLEN]; int tmp; - FILE *tmp_file = NULL; + FILE *tmp_file = NULL, + *spasswd_file; char tmp_name[PATH_MAX]; struct stat statbuf; int rc; @@ -154,16 +166,27 @@ unixpwd_setspw(const char *user, char *password) tmp = mkstemp(tmp_name); if (tmp == -1) return errno; - if (stat(ETC_SPASSWD, &statbuf) != 0 + + spasswd_file = fopen(ETC_SPASSWD, "rbe"); + if (spasswd_file == NULL) { + rc = errno; + close(tmp); + unlink(tmp_name); + return rc; + } + + if (fstat(fileno(spasswd_file), &statbuf) != 0 || fchown(tmp, statbuf.st_uid, statbuf.st_gid) != 0 || fchmod(tmp, statbuf.st_mode) != 0 || (tmp_file = fdopen(tmp, "w")) == NULL) { rc = errno ? errno : EPERM; + fclose(spasswd_file); close(tmp); unlink(tmp_name); return rc; } if (lckpwdf() != 0) { + fclose(spasswd_file); if (tmp_file) fclose(tmp_file); close(tmp); @@ -171,9 +194,8 @@ unixpwd_setspw(const char *user, char *password) return ENOLCK; } - setspent(); while (1) { - rc = getspent_r(&spw, buf, BUFLEN, &sp); + rc = fgetspent_r(spasswd_file, &spw, buf, BUFLEN, &sp); if (rc != 0 || !sp) break; if (!strcmp(user, sp->sp_namp)) { @@ -182,8 +204,8 @@ unixpwd_setspw(const char *user, char *password) } putspent(sp, tmp_file); } - endspent(); + fclose(spasswd_file); fclose(tmp_file); if (rc != ENOENT) { ulckpwdf(); From 2a73b8202535178c68c8df924a39e25082097f63 Mon Sep 17 00:00:00 2001 From: Sebastien Marie Date: Mon, 27 Oct 2025 15:16:27 +0100 Subject: [PATCH 2/2] unixpwd: avoid double closing tmp descriptor on error Signed-off-by: Sebastien Marie --- unixpwd/c/unixpwd.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/unixpwd/c/unixpwd.c b/unixpwd/c/unixpwd.c index d47f29fd7d1..08276ecb780 100644 --- a/unixpwd/c/unixpwd.c +++ b/unixpwd/c/unixpwd.c @@ -189,7 +189,8 @@ unixpwd_setspw(const char *user, char *password) fclose(spasswd_file); if (tmp_file) fclose(tmp_file); - close(tmp); + else + close(tmp); unlink(tmp_name); return ENOLCK; }