aboutsummaryrefslogtreecommitdiff
path: root/modules
diff options
context:
space:
mode:
authorTobias Stoeckmann <tobias@stoeckmann.org>2024-01-02 20:46:54 +0100
committerDmitry V. Levin <ldv@strace.io>2024-01-03 17:16:02 +0000
commit8f2ca5919b26843ef774ef0aeb9bf261dec943a0 (patch)
tree4f5889eb2617a0d966a84d34eaa6a567358fc2d2 /modules
parent4b5eea2e5e76a945b388aca62e8d4b7e7043ba29 (diff)
downloadpam-8f2ca5919b26843ef774ef0aeb9bf261dec943a0.tar.gz
pam-8f2ca5919b26843ef774ef0aeb9bf261dec943a0.tar.bz2
pam-8f2ca5919b26843ef774ef0aeb9bf261dec943a0.zip
pam_unix: avoid reading uninitialized variable
The function _unix_comesfromsource calls _unix_getpwnam internally. When changing the authentication token, it is first called to read local passwd file and optionally contacting NIS. If an entry is found, _unix_getpwnam is called, this time definitely reading passwd file and contacting NIS (if support exists) and parsing the entry. This is meant to check if the entry is not just available but also valid. Since the return value of _unix_getpwnam is not checked and the supplied pointer is only set in case of success, the check for a NULl pointer afterwards can lead to undefined behavior. It is easier to call _unix_getpwnam directly, check its return value and then check if the entry could be parsed. This in turn reduces the amount of /etc/passwd accesses (and fixes a theoretical TOCTOU race). Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
Diffstat (limited to 'modules')
-rw-r--r--modules/pam_unix/pam_unix_passwd.c18
1 files changed, 8 insertions, 10 deletions
diff --git a/modules/pam_unix/pam_unix_passwd.c b/modules/pam_unix/pam_unix_passwd.c
index 9dde2aee..9947f12a 100644
--- a/modules/pam_unix/pam_unix_passwd.c
+++ b/modules/pam_unix/pam_unix_passwd.c
@@ -601,6 +601,7 @@ pam_sm_chauthtok(pam_handle_t *pamh, int flags, int argc, const char **argv)
int remember = -1;
int rounds = 0;
int pass_min_len = 0;
+ struct passwd *pwd;
/* <DO NOT free() THESE> */
const char *user;
@@ -646,21 +647,18 @@ pam_sm_chauthtok(pam_handle_t *pamh, int flags, int argc, const char **argv)
* getpwnam() doesn't tell you *where* the information it gives you
* came from, nor should it. That's our job.
*/
- if (_unix_comesfromsource(pamh, user, 1, on(UNIX_NIS, ctrl)) == 0) {
+ if (_unix_getpwnam(pamh, user, 1, on(UNIX_NIS, ctrl), &pwd) == 0) {
pam_syslog(pamh, LOG_DEBUG,
"user \"%s\" does not exist in /etc/passwd%s",
user, on(UNIX_NIS, ctrl) ? " or NIS" : "");
return PAM_USER_UNKNOWN;
- } else {
- struct passwd *pwd;
- _unix_getpwnam(pamh, user, 1, 1, &pwd);
- if (pwd == NULL) {
- pam_syslog(pamh, LOG_DEBUG,
- "user \"%s\" has corrupted passwd entry",
- user);
- return PAM_USER_UNKNOWN;
- }
+ } else if (pwd == NULL) {
+ pam_syslog(pamh, LOG_DEBUG,
+ "user \"%s\" has corrupted passwd entry",
+ user);
+ return PAM_USER_UNKNOWN;
}
+ _pam_drop(pwd);
/*
* This is not an AUTH module!