summaryrefslogtreecommitdiff
path: root/libpam/pam_modutil_getspnam.c
diff options
context:
space:
mode:
authorTomas Mraz <tm@t8m.info>2005-09-21 10:00:58 +0000
committerTomas Mraz <tm@t8m.info>2005-09-21 10:00:58 +0000
commitbe09d6354efcb2571731bdffc47da86f22621ac8 (patch)
tree82117bfbaadb46495a545ba4f567dc9bddd97c33 /libpam/pam_modutil_getspnam.c
parent627a0401899af257f0fb711ad54194e14a75c530 (diff)
Relevant BUGIDs:
Purpose of commit: new feature Commit summary: --------------- Moved functions from pammodutil to libpam.
Diffstat (limited to 'libpam/pam_modutil_getspnam.c')
-rw-r--r--libpam/pam_modutil_getspnam.c140
1 files changed, 140 insertions, 0 deletions
diff --git a/libpam/pam_modutil_getspnam.c b/libpam/pam_modutil_getspnam.c
new file mode 100644
index 00000000..7fc696e2
--- /dev/null
+++ b/libpam/pam_modutil_getspnam.c
@@ -0,0 +1,140 @@
+/*
+ * $Id$
+ *
+ * This function provides a thread safer version of getspnam() for use
+ * with PAM modules that care about this sort of thing.
+ *
+ * XXX - or at least it should provide a thread-safe alternative.
+ */
+
+#include "pam_modutil_private.h"
+
+#include <errno.h>
+#include <limits.h>
+#include <pthread.h>
+#include <shadow.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 spwd *
+pam_modutil_getspnam(pam_handle_t *pamh, const char *user)
+{
+#ifdef HAVE_GETSPNAM_R
+
+ void *buffer=NULL;
+ size_t length = PWD_INITIAL_LENGTH;
+
+ do {
+ int status;
+ void *new_buffer;
+ struct spwd *result = NULL;
+
+ new_buffer = realloc(buffer, sizeof(struct spwd) + length);
+ if (new_buffer == NULL) {
+
+ D(("out of memory"));
+
+ /* no memory for the user - so delete the memory */
+ if (buffer) {
+ free(buffer);
+ }
+ return NULL;
+ }
+ buffer = new_buffer;
+
+ /* make the re-entrant call to get the spwd structure */
+ errno = 0;
+ status = getspnam_r(user, buffer,
+ sizeof(struct spwd) + (char *) buffer,
+ length, &result);
+ if (!status && (result == buffer)) {
+ char *data_name;
+ const void *ignore;
+ int i;
+
+ data_name = malloc(strlen("_pammodutil_getspnam") + 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_getspnam_%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, pam_modutil_cleanup);
+ }
+ _pammodutil_unlock();
+ if (status == PAM_SUCCESS) {
+ break;
+ }
+ }
+ } else {
+ status = PAM_SUCCESS;
+ }
+
+ free(data_name);
+
+ if (status == PAM_SUCCESS) {
+ D(("success"));
+ return result;
+ }
+
+ D(("was unable to register the data item [%s]",
+ pam_strerror(pamh, status)));
+
+ free(buffer);
+ return NULL;
+
+ } else if (errno != ERANGE && errno != EINTR) {
+ /* no sense in repeating the call */
+ break;
+ }
+
+ length <<= 2;
+
+ } while (length < PWD_ABSURD_PWD_LENGTH);
+
+ D(("spwd structure took %u bytes or so of memory",
+ length+sizeof(struct spwd)));
+
+ free(buffer);
+ return NULL;
+
+#else /* ie. ifndef HAVE_GETSPNAM_R */
+
+ /*
+ * Sorry, there does not appear to be a reentrant version of
+ * getspnam(). So, we use the standard libc function.
+ */
+
+ return getspnam(user);
+
+#endif /* def HAVE_GETSPNAM_R */
+}