summaryrefslogtreecommitdiff
path: root/Linux-PAM/modules/pammodutil/modutil_getpwnam.c
diff options
context:
space:
mode:
Diffstat (limited to 'Linux-PAM/modules/pammodutil/modutil_getpwnam.c')
-rw-r--r--Linux-PAM/modules/pammodutil/modutil_getpwnam.c71
1 files changed, 65 insertions, 6 deletions
diff --git a/Linux-PAM/modules/pammodutil/modutil_getpwnam.c b/Linux-PAM/modules/pammodutil/modutil_getpwnam.c
index e3a8f270..eb359544 100644
--- a/Linux-PAM/modules/pammodutil/modutil_getpwnam.c
+++ b/Linux-PAM/modules/pammodutil/modutil_getpwnam.c
@@ -1,5 +1,5 @@
/*
- * $Id: modutil_getpwnam.c,v 1.1.1.1 2002/09/15 20:09:04 hartmans Exp $
+ * $Id: modutil_getpwnam.c,v 1.4 2005/03/30 14:59:41 kukuk Exp $
*
* This function provides a thread safer version of getpwnam() for use
* with PAM modules that care about this sort of thing.
@@ -9,9 +9,33 @@
#include "pammodutil.h"
+#include <errno.h>
+#include <limits.h>
+#include <pthread.h>
#include <pwd.h>
+#include <stdio.h>
#include <stdlib.h>
+static pthread_mutex_t _pammodutil_mutex = PTHREAD_MUTEX_INITIALIZER;
+static void _pammodutil_lock(void)
+{
+ pthread_mutex_lock(&_pammodutil_mutex);
+}
+static void _pammodutil_unlock(void)
+{
+ pthread_mutex_unlock(&_pammodutil_mutex);
+}
+
+static int intlen(int number)
+{
+ int len = 2;
+ while (number != 0) {
+ number /= 10;
+ len++;
+ }
+ return len;
+}
+
struct passwd *_pammodutil_getpwnam(pam_handle_t *pamh, const char *user)
{
#ifdef HAVE_GETPWNAM_R
@@ -38,12 +62,44 @@ struct passwd *_pammodutil_getpwnam(pam_handle_t *pamh, const char *user)
buffer = new_buffer;
/* make the re-entrant call to get the pwd structure */
+ errno = 0;
status = getpwnam_r(user, buffer,
sizeof(struct passwd) + (char *) buffer,
length, &result);
- if (!status && result) {
- status = pam_set_data(pamh, "_pammodutil_getpwnam", result,
- _pammodutil_cleanup);
+ if (!status && (result == buffer)) {
+ char *data_name;
+ const void *ignore;
+ int i;
+
+ data_name = malloc(strlen("_pammodutil_getpwnam") + 1 +
+ strlen(user) + 1 + intlen(INT_MAX) + 1);
+ if ((pamh != NULL) && (data_name == NULL)) {
+ D(("was unable to register the data item [%s]",
+ pam_strerror(pamh, status)));
+ free(buffer);
+ return NULL;
+ }
+
+ if (pamh != NULL) {
+ for (i = 0; i < INT_MAX; i++) {
+ sprintf(data_name, "_pammodutil_getpwnam_%s_%d", user, i);
+ _pammodutil_lock();
+ status = PAM_NO_MODULE_DATA;
+ if (pam_get_data(pamh, data_name, &ignore) != PAM_SUCCESS) {
+ status = pam_set_data(pamh, data_name,
+ result, _pammodutil_cleanup);
+ }
+ _pammodutil_unlock();
+ if (status == PAM_SUCCESS) {
+ break;
+ }
+ }
+ } else {
+ status = PAM_SUCCESS;
+ }
+
+ free(data_name);
+
if (status == PAM_SUCCESS) {
D(("success"));
return result;
@@ -55,9 +111,12 @@ struct passwd *_pammodutil_getpwnam(pam_handle_t *pamh, const char *user)
free(buffer);
return NULL;
- }
+ } else if (errno != ERANGE && errno != EINTR) {
+ /* no sense in repeating the call */
+ break;
+ }
- length <<= 1;
+ length <<= 2;
} while (length < PWD_ABSURD_PWD_LENGTH);