|
|
@ -1,110 +0,0 @@ |
|
|
|
--- a/modules/pam_faillock/pam_faillock.c
|
|
|
|
+++ b/modules/pam_faillock/pam_faillock.c
|
|
|
|
@@ -348,42 +348,81 @@ set_conf_opt(pam_handle_t *pamh, struct options *opts, const char *name, const c
|
|
|
|
static int |
|
|
|
check_local_user (pam_handle_t *pamh, const char *user) |
|
|
|
{ |
|
|
|
- struct passwd pw, *pwp;
|
|
|
|
- char buf[16384];
|
|
|
|
- int found = 0;
|
|
|
|
+ int rc;
|
|
|
|
+ size_t user_len;
|
|
|
|
FILE *fp; |
|
|
|
- int errn;
|
|
|
|
+ char line[BUFSIZ];
|
|
|
|
|
|
|
|
- fp = fopen(PATH_PASSWD, "r");
|
|
|
|
- if (fp == NULL) {
|
|
|
|
- pam_syslog(pamh, LOG_ERR, "unable to open %s: %m",
|
|
|
|
- PATH_PASSWD);
|
|
|
|
- return -1;
|
|
|
|
+ /* Validate the user name. */
|
|
|
|
+ if ((user_len = strlen(user)) == 0) {
|
|
|
|
+ pam_syslog(pamh, LOG_NOTICE, "user name is not valid");
|
|
|
|
+ return PAM_SERVICE_ERR;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if (user_len > sizeof(line) - sizeof(":")) {
|
|
|
|
+ pam_syslog(pamh, LOG_NOTICE, "user name is too long");
|
|
|
|
+ return PAM_SERVICE_ERR;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if (strchr(user, ':') != NULL) {
|
|
|
|
+ /*
|
|
|
|
+ * "root:x" is not a local user name even if the passwd file
|
|
|
|
+ * contains a line starting with "root:x:".
|
|
|
|
+ */
|
|
|
|
+ return PAM_PERM_DENIED;
|
|
|
|
} |
|
|
|
|
|
|
|
- for (;;) {
|
|
|
|
- errn = fgetpwent_r(fp, &pw, buf, sizeof (buf), &pwp);
|
|
|
|
- if (errn == ERANGE) {
|
|
|
|
- pam_syslog(pamh, LOG_WARNING, "%s contains very long lines; corrupted?",
|
|
|
|
- PATH_PASSWD);
|
|
|
|
+ /* Open the passwd file. */
|
|
|
|
+ FILE *file_name = "/etc/passwd";
|
|
|
|
+ if ((fp = fopen(file_name, "r")) == NULL) {
|
|
|
|
+ pam_syslog(pamh, LOG_ERR, "error opening %s: %m", file_name);
|
|
|
|
+ return PAM_SERVICE_ERR;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /*
|
|
|
|
+ * Scan the file using fgets() instead of fgetpwent_r() because
|
|
|
|
+ * the latter is not flexible enough in handling long lines
|
|
|
|
+ * in passwd files.
|
|
|
|
+ */
|
|
|
|
+ rc = PAM_PERM_DENIED;
|
|
|
|
+ while (fgets(line, sizeof(line), fp) != NULL) {
|
|
|
|
+ size_t line_len;
|
|
|
|
+ const char *str;
|
|
|
|
+
|
|
|
|
+ /*
|
|
|
|
+ * Does this line start with the user name
|
|
|
|
+ * followed by a colon?
|
|
|
|
+ */
|
|
|
|
+ if (strncmp(user, line, user_len) == 0 &&
|
|
|
|
+ line[user_len] == ':') {
|
|
|
|
+ rc = PAM_SUCCESS;
|
|
|
|
break; |
|
|
|
} |
|
|
|
- if (errn != 0)
|
|
|
|
- break;
|
|
|
|
- if (strcmp(pwp->pw_name, user) == 0) {
|
|
|
|
- found = 1;
|
|
|
|
+ /* 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. */
|
|
|
|
} |
|
|
|
|
|
|
|
- fclose (fp);
|
|
|
|
-
|
|
|
|
- if (errn != 0 && errn != ENOENT) {
|
|
|
|
- pam_syslog(pamh, LOG_ERR, "unable to enumerate local accounts: %m");
|
|
|
|
- return -1;
|
|
|
|
- } else {
|
|
|
|
- return found;
|
|
|
|
- }
|
|
|
|
+ fclose(fp);
|
|
|
|
+ return rc;
|
|
|
|
} |
|
|
|
|
|
|
|
static int |