pam_modutil_getpwnam.c 2.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127
  1. /*
  2. * $Id$
  3. *
  4. * This function provides a thread safer version of getpwnam() for use
  5. * with PAM modules that care about this sort of thing.
  6. *
  7. * XXX - or at least it should provide a thread-safe alternative.
  8. */
  9. #include "pam_modutil_private.h"
  10. #include <errno.h>
  11. #include <limits.h>
  12. #include <pwd.h>
  13. #include <stdio.h>
  14. #include <stdlib.h>
  15. static int intlen(int number)
  16. {
  17. int len = 2;
  18. while (number != 0) {
  19. number /= 10;
  20. len++;
  21. }
  22. return len;
  23. }
  24. struct passwd *
  25. pam_modutil_getpwnam(pam_handle_t *pamh, const char *user)
  26. {
  27. #ifdef HAVE_GETPWNAM_R
  28. void *buffer=NULL;
  29. size_t length = PWD_INITIAL_LENGTH;
  30. do {
  31. int status;
  32. void *new_buffer;
  33. struct passwd *result = NULL;
  34. new_buffer = realloc(buffer, sizeof(struct passwd) + length);
  35. if (new_buffer == NULL) {
  36. D(("out of memory"));
  37. /* no memory for the user - so delete the memory */
  38. if (buffer) {
  39. free(buffer);
  40. }
  41. return NULL;
  42. }
  43. buffer = new_buffer;
  44. /* make the re-entrant call to get the pwd structure */
  45. errno = 0;
  46. status = getpwnam_r(user, buffer,
  47. sizeof(struct passwd) + (char *) buffer,
  48. length, &result);
  49. if (!status && (result == buffer)) {
  50. char *data_name;
  51. const void *ignore;
  52. int i;
  53. data_name = malloc(strlen("_pammodutil_getpwnam") + 1 +
  54. strlen(user) + 1 + intlen(INT_MAX) + 1);
  55. if ((pamh != NULL) && (data_name == NULL)) {
  56. D(("was unable to register the data item [%s]",
  57. pam_strerror(pamh, status)));
  58. free(buffer);
  59. return NULL;
  60. }
  61. if (pamh != NULL) {
  62. for (i = 0; i < INT_MAX; i++) {
  63. sprintf(data_name, "_pammodutil_getpwnam_%s_%d", user, i);
  64. status = PAM_NO_MODULE_DATA;
  65. if (pam_get_data(pamh, data_name, &ignore) != PAM_SUCCESS) {
  66. status = pam_set_data(pamh, data_name,
  67. result, pam_modutil_cleanup);
  68. }
  69. if (status == PAM_SUCCESS) {
  70. break;
  71. }
  72. }
  73. } else {
  74. status = PAM_SUCCESS;
  75. }
  76. free(data_name);
  77. if (status == PAM_SUCCESS) {
  78. D(("success"));
  79. return result;
  80. }
  81. D(("was unable to register the data item [%s]",
  82. pam_strerror(pamh, status)));
  83. free(buffer);
  84. return NULL;
  85. } else if (errno != ERANGE && errno != EINTR) {
  86. /* no sense in repeating the call */
  87. break;
  88. }
  89. length <<= PWD_LENGTH_SHIFT;
  90. } while (length < PWD_ABSURD_PWD_LENGTH);
  91. D(("pwd structure took %u bytes or so of memory",
  92. length+sizeof(struct passwd)));
  93. free(buffer);
  94. return NULL;
  95. #else /* ie. ifndef HAVE_GETPWNAM_R */
  96. /*
  97. * Sorry, there does not appear to be a reentrant version of
  98. * getpwnam(). So, we use the standard libc function.
  99. */
  100. return getpwnam(user);
  101. #endif /* def HAVE_GETPWNAM_R */
  102. }