pam_modutil_check_user.c 2.0 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192
  1. #include "pam_modutil_private.h"
  2. #include <security/pam_ext.h>
  3. #include <stdio.h>
  4. #include <string.h>
  5. #include <syslog.h>
  6. int
  7. pam_modutil_check_user_in_passwd(pam_handle_t *pamh,
  8. const char *user_name,
  9. const char *file_name)
  10. {
  11. int rc;
  12. size_t user_len;
  13. FILE *fp;
  14. char line[BUFSIZ];
  15. /* Validate the user name. */
  16. if ((user_len = strlen(user_name)) == 0) {
  17. pam_syslog(pamh, LOG_NOTICE, "user name is not valid");
  18. return PAM_SERVICE_ERR;
  19. }
  20. if (user_len > sizeof(line) - sizeof(":")) {
  21. pam_syslog(pamh, LOG_NOTICE, "user name is too long");
  22. return PAM_SERVICE_ERR;
  23. }
  24. if (strchr(user_name, ':') != NULL) {
  25. /*
  26. * "root:x" is not a local user name even if the passwd file
  27. * contains a line starting with "root:x:".
  28. */
  29. return PAM_PERM_DENIED;
  30. }
  31. /* Open the passwd file. */
  32. if (file_name == NULL) {
  33. file_name = "/etc/passwd";
  34. }
  35. if ((fp = fopen(file_name, "r")) == NULL) {
  36. pam_syslog(pamh, LOG_ERR, "error opening %s: %m", file_name);
  37. return PAM_SERVICE_ERR;
  38. }
  39. /*
  40. * Scan the file using fgets() instead of fgetpwent_r() because
  41. * the latter is not flexible enough in handling long lines
  42. * in passwd files.
  43. */
  44. rc = PAM_PERM_DENIED;
  45. while (fgets(line, sizeof(line), fp) != NULL) {
  46. size_t line_len;
  47. const char *str;
  48. /*
  49. * Does this line start with the user name
  50. * followed by a colon?
  51. */
  52. if (strncmp(user_name, line, user_len) == 0 &&
  53. line[user_len] == ':') {
  54. rc = PAM_SUCCESS;
  55. /*
  56. * Continue reading the file to avoid timing attacks.
  57. */
  58. }
  59. /* Has a newline been read? */
  60. line_len = strlen(line);
  61. if (line_len < sizeof(line) - 1 ||
  62. line[line_len - 1] == '\n') {
  63. /* Yes, continue with the next line. */
  64. continue;
  65. }
  66. /* No, read till the end of this line first. */
  67. while ((str = fgets(line, sizeof(line), fp)) != NULL) {
  68. line_len = strlen(line);
  69. if (line_len == 0 ||
  70. line[line_len - 1] == '\n') {
  71. break;
  72. }
  73. }
  74. if (str == NULL) {
  75. /* fgets returned NULL, we are done. */
  76. break;
  77. }
  78. /* Continue with the next line. */
  79. }
  80. fclose(fp);
  81. return rc;
  82. }