summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDmitry V. Levin <ldv@altlinux.org>2020-05-01 21:44:59 +0000
committerDmitry V. Levin <ldv@altlinux.org>2020-05-21 16:51:52 +0000
commited74a6c898df2963d0587262caf6996259025426 (patch)
treed6b4021361b866dd13b9da04b0cda5c1a89d3b91
parent378ff917604725de6109b2a039de963de1f3245b (diff)
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.
-rw-r--r--modules/pam_localuser/pam_localuser.c35
1 files 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 */