You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

110 lines
2.7 KiB

  1. --- a/modules/pam_faillock/pam_faillock.c
  2. +++ b/modules/pam_faillock/pam_faillock.c
  3. @@ -348,42 +348,81 @@ set_conf_opt(pam_handle_t *pamh, struct options *opts, const char *name, const c
  4. static int
  5. check_local_user (pam_handle_t *pamh, const char *user)
  6. {
  7. - struct passwd pw, *pwp;
  8. - char buf[16384];
  9. - int found = 0;
  10. + int rc;
  11. + size_t user_len;
  12. FILE *fp;
  13. - int errn;
  14. + char line[BUFSIZ];
  15. - fp = fopen(PATH_PASSWD, "r");
  16. - if (fp == NULL) {
  17. - pam_syslog(pamh, LOG_ERR, "unable to open %s: %m",
  18. - PATH_PASSWD);
  19. - return -1;
  20. + /* Validate the user name. */
  21. + if ((user_len = strlen(user)) == 0) {
  22. + pam_syslog(pamh, LOG_NOTICE, "user name is not valid");
  23. + return PAM_SERVICE_ERR;
  24. + }
  25. +
  26. + if (user_len > sizeof(line) - sizeof(":")) {
  27. + pam_syslog(pamh, LOG_NOTICE, "user name is too long");
  28. + return PAM_SERVICE_ERR;
  29. + }
  30. +
  31. + if (strchr(user, ':') != NULL) {
  32. + /*
  33. + * "root:x" is not a local user name even if the passwd file
  34. + * contains a line starting with "root:x:".
  35. + */
  36. + return PAM_PERM_DENIED;
  37. }
  38. - for (;;) {
  39. - errn = fgetpwent_r(fp, &pw, buf, sizeof (buf), &pwp);
  40. - if (errn == ERANGE) {
  41. - pam_syslog(pamh, LOG_WARNING, "%s contains very long lines; corrupted?",
  42. - PATH_PASSWD);
  43. + /* Open the passwd file. */
  44. + FILE *file_name = "/etc/passwd";
  45. + if ((fp = fopen(file_name, "r")) == NULL) {
  46. + pam_syslog(pamh, LOG_ERR, "error opening %s: %m", file_name);
  47. + return PAM_SERVICE_ERR;
  48. + }
  49. +
  50. + /*
  51. + * Scan the file using fgets() instead of fgetpwent_r() because
  52. + * the latter is not flexible enough in handling long lines
  53. + * in passwd files.
  54. + */
  55. + rc = PAM_PERM_DENIED;
  56. + while (fgets(line, sizeof(line), fp) != NULL) {
  57. + size_t line_len;
  58. + const char *str;
  59. +
  60. + /*
  61. + * Does this line start with the user name
  62. + * followed by a colon?
  63. + */
  64. + if (strncmp(user, line, user_len) == 0 &&
  65. + line[user_len] == ':') {
  66. + rc = PAM_SUCCESS;
  67. break;
  68. }
  69. - if (errn != 0)
  70. - break;
  71. - if (strcmp(pwp->pw_name, user) == 0) {
  72. - found = 1;
  73. + /* Has a newline been read? */
  74. + line_len = strlen(line);
  75. + if (line_len < sizeof(line) - 1 ||
  76. + line[line_len - 1] == '\n') {
  77. + /* Yes, continue with the next line. */
  78. + continue;
  79. + }
  80. +
  81. + /* No, read till the end of this line first. */
  82. + while ((str = fgets(line, sizeof(line), fp)) != NULL) {
  83. + line_len = strlen(line);
  84. + if (line_len == 0 ||
  85. + line[line_len - 1] == '\n') {
  86. + break;
  87. + }
  88. + }
  89. + if (str == NULL) {
  90. + /* fgets returned NULL, we are done. */
  91. break;
  92. }
  93. + /* Continue with the next line. */
  94. }
  95. - fclose (fp);
  96. -
  97. - if (errn != 0 && errn != ENOENT) {
  98. - pam_syslog(pamh, LOG_ERR, "unable to enumerate local accounts: %m");
  99. - return -1;
  100. - } else {
  101. - return found;
  102. - }
  103. + fclose(fp);
  104. + return rc;
  105. }
  106. static int