From ed74a6c898df2963d0587262caf6996259025426 Mon Sep 17 00:00:00 2001 From: "Dmitry V. Levin" Date: Fri, 1 May 2020 21:44:59 +0000 Subject: pam_localuser: handle long lines in passwd files properly Before this change, a long line in the passwd file used to be treated as several lines which could potentially result to false match and, consequently, to incorrect PAM_SUCCESS return value. * modules/pam_localuser/pam_localuser.c (pam_sm_authenticate): Handle long lines in passwd files properly. --- modules/pam_localuser/pam_localuser.c | 35 ++++++++++++++++++++++++++++++++--- 1 file changed, 32 insertions(+), 3 deletions(-) diff --git a/modules/pam_localuser/pam_localuser.c b/modules/pam_localuser/pam_localuser.c index 3ce0aaa0..66ca2d08 100644 --- a/modules/pam_localuser/pam_localuser.c +++ b/modules/pam_localuser/pam_localuser.c @@ -130,13 +130,20 @@ pam_sm_authenticate (pam_handle_t *pamh, int flags UNUSED, return PAM_PERM_DENIED; } - /* scan the file, using fgets() instead of fgetpwent() because i - * don't want to mess with applications which call fgetpwent() */ + /* + * Scan the file using fgets() instead of fgetpwent_r() because + * the latter is not flexible enough in handling long lines + * in passwd files. + */ ret = PAM_PERM_DENIED; - while(fgets(line, sizeof(line), fp) != NULL) { + while (fgets(line, sizeof(line), fp) != NULL) { + size_t line_len; + const char *str; + if(debug) { pam_syslog (pamh, LOG_DEBUG, "checking \"%s\"", line); } + /* * Does this line start with the user name * followed by a colon? @@ -146,6 +153,28 @@ pam_sm_authenticate (pam_handle_t *pamh, int flags UNUSED, ret = PAM_SUCCESS; break; } + + /* Has a newline been read? */ + line_len = strlen(line); + if (line_len < sizeof(line) - 1 || + line[line_len - 1] == '\n') { + /* Yes, continue with the next line. */ + continue; + } + + /* No, read till the end of this line first. */ + while ((str = fgets(line, sizeof(line), fp)) != NULL) { + line_len = strlen(line); + if (line_len == 0 || + line[line_len - 1] == '\n') { + break; + } + } + if (str == NULL) { + /* fgets returned NULL, we are done. */ + break; + } + /* Continue with the next line. */ } /* okay, we're done */ -- cgit v1.2.3