diff options
author | Tobias Stoeckmann <tobias@stoeckmann.org> | 2024-01-02 20:46:54 +0100 |
---|---|---|
committer | Dmitry V. Levin <ldv@strace.io> | 2024-01-03 17:16:02 +0000 |
commit | 8f2ca5919b26843ef774ef0aeb9bf261dec943a0 (patch) | |
tree | 4f5889eb2617a0d966a84d34eaa6a567358fc2d2 /modules/pam_unix | |
parent | 4b5eea2e5e76a945b388aca62e8d4b7e7043ba29 (diff) | |
download | pam-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/pam_unix')
-rw-r--r-- | modules/pam_unix/pam_unix_passwd.c | 18 |
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! |