|
|
- --- 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
|