pam_modutil_getpwuid.c 2.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138
  1. /*
  2. * $Id$
  3. *
  4. * This function provides a thread safer version of getpwuid() 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. static int longlen(long number)
  25. {
  26. int len = 2;
  27. while (number != 0) {
  28. number /= 10;
  29. len++;
  30. }
  31. return len;
  32. }
  33. struct passwd *
  34. pam_modutil_getpwuid(pam_handle_t *pamh, uid_t uid)
  35. {
  36. #ifdef HAVE_GETPWUID_R
  37. void *buffer=NULL;
  38. size_t length = PWD_INITIAL_LENGTH;
  39. do {
  40. int status;
  41. void *new_buffer;
  42. struct passwd *result = NULL;
  43. new_buffer = realloc(buffer, sizeof(struct passwd) + length);
  44. if (new_buffer == NULL) {
  45. D(("out of memory"));
  46. /* no memory for the user - so delete the memory */
  47. if (buffer) {
  48. free(buffer);
  49. }
  50. return NULL;
  51. }
  52. buffer = new_buffer;
  53. /* make the re-entrant call to get the pwd structure */
  54. errno = 0;
  55. status = getpwuid_r(uid, buffer,
  56. sizeof(struct passwd) + (char *) buffer,
  57. length, &result);
  58. if (!status && (result == buffer)) {
  59. char *data_name;
  60. const void *ignore;
  61. int i;
  62. data_name = malloc(strlen("_pammodutil_getpwuid") + 1 +
  63. longlen((long) uid) + 1 + intlen(INT_MAX) + 1);
  64. if ((pamh != NULL) && (data_name == NULL)) {
  65. D(("was unable to register the data item [%s]",
  66. pam_strerror(pamh, status)));
  67. free(buffer);
  68. return NULL;
  69. }
  70. if (pamh != NULL) {
  71. for (i = 0; i < INT_MAX; i++) {
  72. sprintf(data_name, "_pammodutil_getpwuid_%ld_%d",
  73. (long) uid, i);
  74. status = PAM_NO_MODULE_DATA;
  75. if (pam_get_data(pamh, data_name, &ignore) != PAM_SUCCESS) {
  76. status = pam_set_data(pamh, data_name,
  77. result, pam_modutil_cleanup);
  78. }
  79. if (status == PAM_SUCCESS) {
  80. break;
  81. }
  82. }
  83. } else {
  84. status = PAM_SUCCESS;
  85. }
  86. free(data_name);
  87. if (status == PAM_SUCCESS) {
  88. D(("success"));
  89. return result;
  90. }
  91. D(("was unable to register the data item [%s]",
  92. pam_strerror(pamh, status)));
  93. free(buffer);
  94. return NULL;
  95. } else if (errno != ERANGE && errno != EINTR) {
  96. /* no sense in repeating the call */
  97. break;
  98. }
  99. length <<= PWD_LENGTH_SHIFT;
  100. } while (length < PWD_ABSURD_PWD_LENGTH);
  101. D(("pwd structure took %u bytes or so of memory",
  102. length+sizeof(struct passwd)));
  103. free(buffer);
  104. return NULL;
  105. #else /* ie. ifndef HAVE_GETPWUID_R */
  106. /*
  107. * Sorry, there does not appear to be a reentrant version of
  108. * getpwuid(). So, we use the standard libc function.
  109. */
  110. return getpwuid(uid);
  111. #endif /* def HAVE_GETPWUID_R */
  112. }