aboutsummaryrefslogtreecommitdiff
path: root/Linux-PAM/modules/pammodutil
diff options
context:
space:
mode:
Diffstat (limited to 'Linux-PAM/modules/pammodutil')
-rw-r--r--Linux-PAM/modules/pammodutil/Makefile55
-rw-r--r--Linux-PAM/modules/pammodutil/README15
-rw-r--r--Linux-PAM/modules/pammodutil/include/security/_pam_modutil.h66
-rw-r--r--Linux-PAM/modules/pammodutil/modutil_cleanup.c16
-rw-r--r--Linux-PAM/modules/pammodutil/modutil_getgrgid.c150
-rw-r--r--Linux-PAM/modules/pammodutil/modutil_getgrnam.c139
-rw-r--r--Linux-PAM/modules/pammodutil/modutil_getlogin.c72
-rw-r--r--Linux-PAM/modules/pammodutil/modutil_getpwnam.c139
-rw-r--r--Linux-PAM/modules/pammodutil/modutil_getpwuid.c150
-rw-r--r--Linux-PAM/modules/pammodutil/modutil_getspnam.c139
-rw-r--r--Linux-PAM/modules/pammodutil/modutil_ingroup.c121
-rw-r--r--Linux-PAM/modules/pammodutil/modutil_ioloop.c52
-rw-r--r--Linux-PAM/modules/pammodutil/pammodutil.h22
13 files changed, 1136 insertions, 0 deletions
diff --git a/Linux-PAM/modules/pammodutil/Makefile b/Linux-PAM/modules/pammodutil/Makefile
new file mode 100644
index 00000000..bad1bf62
--- /dev/null
+++ b/Linux-PAM/modules/pammodutil/Makefile
@@ -0,0 +1,55 @@
+#
+# $Id: Makefile,v 1.4 2004/09/24 13:13:22 kukuk Exp $
+#
+#
+
+include ../../Make.Rules
+
+LIBNAME=libpammodutil
+
+# ---------------------------------------------
+
+dummy: all
+
+# ---------------------------------------------
+
+CFLAGS += $(PIC) $(STATIC) $(MOREFLAGS) \
+ -DLIBPAM_VERSION_MAJOR=$(MAJOR_REL) \
+ -DLIBPAM_VERSION_MINOR=$(MINOR_REL)
+
+# all the object files we care about
+LIBOBJECTS = modutil_cleanup.o modutil_getpwnam.o modutil_getpwuid.o \
+ modutil_getspnam.o modutil_getgrnam.o modutil_getgrgid.o \
+ modutil_ingroup.o modutil_getlogin.o modutil_ioloop.o
+
+# static library name
+LIBSTATIC = $(LIBNAME).a
+
+SLIBOBJECTS = $(addprefix static/,$(LIBOBJECTS) $(STATICOBJ))
+
+# ---------------------------------------------
+## rules
+
+all: dirs $(LIBSTATIC) ../../Make.Rules
+
+dirs:
+ $(MKDIR) static
+
+static/%.o : %.c
+ $(CC) $(CFLAGS) $(CPPFLAGS) $(TARGET_ARCH) -c $< -o $@
+
+$(LIBSTATIC): $(SLIBOBJECTS)
+ ar cr $@ $(SLIBOBJECTS)
+ $(RANLIB) $@
+
+install:
+ @echo "at this time, we're not installing $(LIBSTATIC)"
+
+remove:
+ @echo "at this time, there is nothing to remove"
+
+clean:
+ rm -f a.out core *~ static/*.o
+ rm -f *.a *.o
+ if [ -d dynamic ]; then rmdir dynamic ; fi
+ if [ -d static ]; then rmdir static ; fi
diff --git a/Linux-PAM/modules/pammodutil/README b/Linux-PAM/modules/pammodutil/README
new file mode 100644
index 00000000..ea44f310
--- /dev/null
+++ b/Linux-PAM/modules/pammodutil/README
@@ -0,0 +1,15 @@
+$Id: README,v 1.1 2001/12/09 22:15:12 agmorgan Exp $
+
+This is a libarary of routines for use by modules. The routines seem
+to have a common use for modules, but are not part of libpam and never
+will be. They are also a convenient layer of abstraction for providing
+thread-safe functions that may require use of pam_handle_t 'data'
+items to make their thread-safeness tied to the use of a single
+pam_handle_t per thread.
+
+Functions provided so far are all listed in
+
+ include/security/_pam_modutil.h
+
+.
+
diff --git a/Linux-PAM/modules/pammodutil/include/security/_pam_modutil.h b/Linux-PAM/modules/pammodutil/include/security/_pam_modutil.h
new file mode 100644
index 00000000..ec0c8964
--- /dev/null
+++ b/Linux-PAM/modules/pammodutil/include/security/_pam_modutil.h
@@ -0,0 +1,66 @@
+#ifndef _PAM_MODUTIL_H
+#define _PAM_MODUTIL_H
+
+/*
+ * $Id: _pam_modutil.h,v 1.4 2004/09/24 13:13:22 kukuk Exp $
+ *
+ * This file is a list of handy libc wrappers that attempt to provide some
+ * thread-safe and other convenient functionality to modules in a form that
+ * is common, but not dynamically linked with yet another dynamic pam
+ * library extension.
+ *
+ * A number of these functions reserve space in a pam_[sg]et_data item.
+ * In all cases, the name of the item is prefixed with "_pammodutil_*".
+ *
+ * On systems that simply can't support thread safe programming, these
+ * functions don't support it either - sorry.
+ *
+ * Copyright (c) 2001-2002 Andrew Morgan <morgan@kernel.org>
+ */
+
+#include <pwd.h>
+#include <grp.h>
+#include <shadow.h>
+#include <sys/types.h>
+
+extern struct passwd *_pammodutil_getpwnam(pam_handle_t *pamh,
+ const char *user);
+
+extern struct passwd *_pammodutil_getpwuid(pam_handle_t *pamh,
+ uid_t uid);
+
+extern struct group *_pammodutil_getgrnam(pam_handle_t *pamh,
+ const char *group);
+
+extern struct group *_pammodutil_getgrgid(pam_handle_t *pamh,
+ gid_t gid);
+
+extern struct spwd *_pammodutil_getspnam(pam_handle_t *pamh,
+ const char *user);
+
+extern int _pammodutil_user_in_group_nam_nam(pam_handle_t *pamh,
+ const char *user,
+ const char *group);
+
+extern int _pammodutil_user_in_group_nam_gid(pam_handle_t *pamh,
+ const char *user,
+ gid_t group);
+
+extern int _pammodutil_user_in_group_uid_nam(pam_handle_t *pamh,
+ uid_t user,
+ const char *group);
+
+extern int _pammodutil_user_in_group_uid_gid(pam_handle_t *pamh,
+ uid_t user,
+ gid_t group);
+
+extern void _pammodutil_cleanup(pam_handle_t *pamh, void *data,
+ int error_status);
+
+extern const char *_pammodutil_getlogin(pam_handle_t *pamh);
+
+extern int _pammodutil_read(int fd, char *buffer, int count);
+
+extern int _pammodutil_write(int fd, const char *buffer, int count);
+
+#endif /* _PAM_MODUTIL_H */
diff --git a/Linux-PAM/modules/pammodutil/modutil_cleanup.c b/Linux-PAM/modules/pammodutil/modutil_cleanup.c
new file mode 100644
index 00000000..5477481f
--- /dev/null
+++ b/Linux-PAM/modules/pammodutil/modutil_cleanup.c
@@ -0,0 +1,16 @@
+/*
+ * $Id: modutil_cleanup.c,v 1.1 2001/12/09 22:15:12 agmorgan Exp $
+ *
+ * This function provides a common pam_set_data() friendly version of free().
+ */
+
+#include "pammodutil.h"
+
+void _pammodutil_cleanup(pam_handle_t *pamh, void *data, int error_status)
+{
+ if (data) {
+ /* junk it */
+ (void) free(data);
+ }
+}
+
diff --git a/Linux-PAM/modules/pammodutil/modutil_getgrgid.c b/Linux-PAM/modules/pammodutil/modutil_getgrgid.c
new file mode 100644
index 00000000..f97a9239
--- /dev/null
+++ b/Linux-PAM/modules/pammodutil/modutil_getgrgid.c
@@ -0,0 +1,150 @@
+/*
+ * $Id: modutil_getgrgid.c,v 1.3 2005/03/30 14:59:41 kukuk Exp $
+ *
+ * This function provides a thread safer version of getgrgid() for use
+ * with PAM modules that care about this sort of thing.
+ *
+ * XXX - or at least it should provide a thread-safe alternative.
+ */
+
+#include "pammodutil.h"
+
+#include <errno.h>
+#include <limits.h>
+#include <grp.h>
+#include <pthread.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;
+}
+
+static int longlen(long number)
+{
+ int len = 2;
+ while (number != 0) {
+ number /= 10;
+ len++;
+ }
+ return len;
+}
+
+struct group *_pammodutil_getgrgid(pam_handle_t *pamh, gid_t gid)
+{
+#ifdef HAVE_GETGRGID_R
+
+ void *buffer=NULL;
+ size_t length = PWD_INITIAL_LENGTH;
+
+ do {
+ int status;
+ void *new_buffer;
+ struct group *result = NULL;
+
+ new_buffer = realloc(buffer, sizeof(struct group) + 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 grp structure */
+ errno = 0;
+ status = getgrgid_r(gid, buffer,
+ sizeof(struct group) + (char *) buffer,
+ length, &result);
+ if (!status && (result == buffer)) {
+ char *data_name;
+ const void *ignore;
+ int i;
+
+ data_name = malloc(strlen("_pammodutil_getgrgid") + 1 +
+ longlen((long)gid) + 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_getgrgid_%ld_%d",
+ (long) gid, 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;
+ }
+
+ 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(("grp structure took %u bytes or so of memory",
+ length+sizeof(struct group)));
+
+ free(buffer);
+ return NULL;
+
+#else /* ie. ifndef HAVE_GETGRGID_R */
+
+ /*
+ * Sorry, there does not appear to be a reentrant version of
+ * getgrgid(). So, we use the standard libc function.
+ */
+
+ return getgrgid(gid);
+
+#endif /* def HAVE_GETGRGID_R */
+}
diff --git a/Linux-PAM/modules/pammodutil/modutil_getgrnam.c b/Linux-PAM/modules/pammodutil/modutil_getgrnam.c
new file mode 100644
index 00000000..0727618c
--- /dev/null
+++ b/Linux-PAM/modules/pammodutil/modutil_getgrnam.c
@@ -0,0 +1,139 @@
+/*
+ * $Id: modutil_getgrnam.c,v 1.3 2005/03/30 14:59:41 kukuk Exp $
+ *
+ * This function provides a thread safer version of getgrnam() for use
+ * with PAM modules that care about this sort of thing.
+ *
+ * XXX - or at least it should provide a thread-safe alternative.
+ */
+
+#include "pammodutil.h"
+
+#include <errno.h>
+#include <limits.h>
+#include <grp.h>
+#include <pthread.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 group *_pammodutil_getgrnam(pam_handle_t *pamh, const char *group)
+{
+#ifdef HAVE_GETGRNAM_R
+
+ void *buffer=NULL;
+ size_t length = PWD_INITIAL_LENGTH;
+
+ do {
+ int status;
+ void *new_buffer;
+ struct group *result = NULL;
+
+ new_buffer = realloc(buffer, sizeof(struct group) + length);
+ if (new_buffer == NULL) {
+
+ D(("out of memory"));
+
+ /* no memory for the group - so delete the memory */
+ if (buffer) {
+ free(buffer);
+ }
+ return NULL;
+ }
+ buffer = new_buffer;
+
+ /* make the re-entrant call to get the grp structure */
+ errno = 0;
+ status = getgrnam_r(group, buffer,
+ sizeof(struct group) + (char *) buffer,
+ length, &result);
+ if (!status && (result == buffer)) {
+ char *data_name;
+ const void *ignore;
+ int i;
+
+ data_name = malloc(strlen("_pammodutil_getgrnam") + 1 +
+ strlen(group) + 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_getgrnam_%s_%d", group, 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;
+ }
+
+ 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(("grp structure took %u bytes or so of memory",
+ length+sizeof(struct group)));
+
+ free(buffer);
+ return NULL;
+
+#else /* ie. ifndef HAVE_GETGRNAM_R */
+
+ /*
+ * Sorry, there does not appear to be a reentrant version of
+ * getgrnam(). So, we use the standard libc function.
+ */
+
+ return getgrnam(group);
+
+#endif /* def HAVE_GETGRNAM_R */
+}
diff --git a/Linux-PAM/modules/pammodutil/modutil_getlogin.c b/Linux-PAM/modules/pammodutil/modutil_getlogin.c
new file mode 100644
index 00000000..0e4a48d8
--- /dev/null
+++ b/Linux-PAM/modules/pammodutil/modutil_getlogin.c
@@ -0,0 +1,72 @@
+/*
+ * $Id: modutil_getlogin.c,v 1.4 2004/11/08 10:57:15 t8m Exp $
+ *
+ * A central point for invoking getlogin(). Hopefully, this is a
+ * little harder to spoof than all the other versions that are out
+ * there.
+ */
+
+#include "pammodutil.h"
+
+#include <stdlib.h>
+#include <unistd.h>
+#include <utmp.h>
+
+#define _PAMMODUTIL_GETLOGIN "_pammodutil_getlogin"
+
+const char *_pammodutil_getlogin(pam_handle_t *pamh)
+{
+ int status;
+ char *logname;
+ const char *curr_tty;
+ char *curr_user;
+ struct utmp *ut, line;
+
+ status = pam_get_data(pamh, _PAMMODUTIL_GETLOGIN,
+ (const void **) &logname);
+ if (status == PAM_SUCCESS) {
+ return logname;
+ }
+
+ status = pam_get_item(pamh, PAM_TTY, (const void **) &curr_tty);
+ if ((status != PAM_SUCCESS) || (curr_tty == NULL)) {
+ curr_tty = ttyname(0);
+ }
+
+ if ((curr_tty == NULL) || memcmp(curr_tty, "/dev/", 5)) {
+ return NULL;
+ }
+
+ curr_tty += 5; /* strlen("/dev/") */
+ logname = NULL;
+
+ setutent();
+ strncpy(line.ut_line, curr_tty, sizeof(line.ut_line));
+
+ if ((ut = getutline(&line)) == NULL) {
+ goto clean_up_and_go_home;
+ }
+
+ curr_user = calloc(sizeof(line.ut_user)+1, 1);
+ if (curr_user == NULL) {
+ goto clean_up_and_go_home;
+ }
+
+ strncpy(curr_user, ut->ut_user, sizeof(ut->ut_user));
+ /* calloc already zeroed the memory */
+
+ status = pam_set_data(pamh, _PAMMODUTIL_GETLOGIN, curr_user,
+ _pammodutil_cleanup);
+ if (status != PAM_SUCCESS) {
+ free(curr_user);
+ goto clean_up_and_go_home;
+ }
+
+ logname = curr_user;
+
+clean_up_and_go_home:
+
+ endutent();
+
+ return logname;
+}
diff --git a/Linux-PAM/modules/pammodutil/modutil_getpwnam.c b/Linux-PAM/modules/pammodutil/modutil_getpwnam.c
new file mode 100644
index 00000000..eb359544
--- /dev/null
+++ b/Linux-PAM/modules/pammodutil/modutil_getpwnam.c
@@ -0,0 +1,139 @@
+/*
+ * $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.
+ *
+ * XXX - or at least it should provide a thread-safe alternative.
+ */
+
+#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
+
+ void *buffer=NULL;
+ size_t length = PWD_INITIAL_LENGTH;
+
+ do {
+ int status;
+ void *new_buffer;
+ struct passwd *result = NULL;
+
+ new_buffer = realloc(buffer, sizeof(struct passwd) + 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 pwd structure */
+ errno = 0;
+ status = getpwnam_r(user, buffer,
+ sizeof(struct passwd) + (char *) buffer,
+ length, &result);
+ 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;
+ }
+
+ 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(("pwd structure took %u bytes or so of memory",
+ length+sizeof(struct passwd)));
+
+ free(buffer);
+ return NULL;
+
+#else /* ie. ifndef HAVE_GETPWNAM_R */
+
+ /*
+ * Sorry, there does not appear to be a reentrant version of
+ * getpwnam(). So, we use the standard libc function.
+ */
+
+ return getpwnam(user);
+
+#endif /* def HAVE_GETPWNAM_R */
+}
diff --git a/Linux-PAM/modules/pammodutil/modutil_getpwuid.c b/Linux-PAM/modules/pammodutil/modutil_getpwuid.c
new file mode 100644
index 00000000..8ba20d17
--- /dev/null
+++ b/Linux-PAM/modules/pammodutil/modutil_getpwuid.c
@@ -0,0 +1,150 @@
+/*
+ * $Id: modutil_getpwuid.c,v 1.4 2005/03/30 14:59:41 kukuk Exp $
+ *
+ * This function provides a thread safer version of getpwuid() for use
+ * with PAM modules that care about this sort of thing.
+ *
+ * XXX - or at least it should provide a thread-safe alternative.
+ */
+
+#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;
+}
+
+static int longlen(long number)
+{
+ int len = 2;
+ while (number != 0) {
+ number /= 10;
+ len++;
+ }
+ return len;
+}
+
+struct passwd *_pammodutil_getpwuid(pam_handle_t *pamh, uid_t uid)
+{
+#ifdef HAVE_GETPWUID_R
+
+ void *buffer=NULL;
+ size_t length = PWD_INITIAL_LENGTH;
+
+ do {
+ int status;
+ void *new_buffer;
+ struct passwd *result = NULL;
+
+ new_buffer = realloc(buffer, sizeof(struct passwd) + 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 pwd structure */
+ errno = 0;
+ status = getpwuid_r(uid, buffer,
+ sizeof(struct passwd) + (char *) buffer,
+ length, &result);
+ if (!status && (result == buffer)) {
+ char *data_name;
+ const void *ignore;
+ int i;
+
+ data_name = malloc(strlen("_pammodutil_getpwuid") + 1 +
+ longlen((long) uid) + 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_getpwuid_%ld_%d",
+ (long) uid, 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;
+ }
+
+ 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(("pwd structure took %u bytes or so of memory",
+ length+sizeof(struct passwd)));
+
+ free(buffer);
+ return NULL;
+
+#else /* ie. ifndef HAVE_GETPWUID_R */
+
+ /*
+ * Sorry, there does not appear to be a reentrant version of
+ * getpwuid(). So, we use the standard libc function.
+ */
+
+ return getpwuid(uid);
+
+#endif /* def HAVE_GETPWUID_R */
+}
diff --git a/Linux-PAM/modules/pammodutil/modutil_getspnam.c b/Linux-PAM/modules/pammodutil/modutil_getspnam.c
new file mode 100644
index 00000000..e966bb52
--- /dev/null
+++ b/Linux-PAM/modules/pammodutil/modutil_getspnam.c
@@ -0,0 +1,139 @@
+/*
+ * $Id: modutil_getspnam.c,v 1.3 2005/03/30 14:59:41 kukuk Exp $
+ *
+ * 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 "pammodutil.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 *_pammodutil_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, _pammodutil_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 */
+}
diff --git a/Linux-PAM/modules/pammodutil/modutil_ingroup.c b/Linux-PAM/modules/pammodutil/modutil_ingroup.c
new file mode 100644
index 00000000..e1f88b81
--- /dev/null
+++ b/Linux-PAM/modules/pammodutil/modutil_ingroup.c
@@ -0,0 +1,121 @@
+/*
+ * $Id: modutil_ingroup.c,v 1.1 2004/09/24 13:14:14 kukuk Exp $
+ *
+ * This function provides common methods for checking if a user is in a
+ * specified group.
+ */
+
+#include "pammodutil.h"
+#include "include/security/_pam_modutil.h"
+#include <pwd.h>
+#include <grp.h>
+
+#ifdef HAVE_GETGROUPLIST
+static int checkgrouplist(const char *user, gid_t primary, gid_t target)
+{
+ gid_t *grouplist = NULL;
+ int agroups, ngroups, i;
+ ngroups = agroups = 3;
+ do {
+ grouplist = malloc(sizeof(gid_t) * agroups);
+ if (grouplist == NULL) {
+ return 0;
+ }
+ ngroups = agroups;
+ i = getgrouplist(user, primary, grouplist, &ngroups);
+ if ((i < 0) || (ngroups < 1)) {
+ agroups *= 2;
+ free(grouplist);
+ } else {
+ for (i = 0; i < ngroups; i++) {
+ if (grouplist[i] == target) {
+ free(grouplist);
+ return 1;
+ }
+ }
+ free(grouplist);
+ }
+ } while (((i < 0) || (ngroups < 1)) && (agroups < 10000));
+ return 0;
+}
+#endif
+
+static int _pammodutil_user_in_group_common(pam_handle_t *pamh,
+ struct passwd *pwd,
+ struct group *grp)
+{
+ int i;
+
+ if (pwd == NULL) {
+ return 0;
+ }
+ if (grp == NULL) {
+ return 0;
+ }
+
+ if (pwd->pw_gid == grp->gr_gid) {
+ return 1;
+ }
+
+ for (i = 0; (grp->gr_mem != NULL) && (grp->gr_mem[i] != NULL); i++) {
+ if (strcmp(pwd->pw_name, grp->gr_mem[i]) == 0) {
+ return 1;
+ }
+ }
+
+#ifdef HAVE_GETGROUPLIST
+ if (checkgrouplist(pwd->pw_name, pwd->pw_gid, grp->gr_gid)) {
+ return 1;
+ }
+#endif
+
+ return 0;
+}
+
+int _pammodutil_user_in_group_nam_nam(pam_handle_t *pamh,
+ const char *user, const char *group)
+{
+ struct passwd *pwd;
+ struct group *grp;
+
+ pwd = _pammodutil_getpwnam(pamh, user);
+ grp = _pammodutil_getgrnam(pamh, group);
+
+ return _pammodutil_user_in_group_common(pamh, pwd, grp);
+}
+
+int _pammodutil_user_in_group_nam_gid(pam_handle_t *pamh,
+ const char *user, gid_t group)
+{
+ struct passwd *pwd;
+ struct group *grp;
+
+ pwd = _pammodutil_getpwnam(pamh, user);
+ grp = _pammodutil_getgrgid(pamh, group);
+
+ return _pammodutil_user_in_group_common(pamh, pwd, grp);
+}
+
+int _pammodutil_user_in_group_uid_nam(pam_handle_t *pamh,
+ uid_t user, const char *group)
+{
+ struct passwd *pwd;
+ struct group *grp;
+
+ pwd = _pammodutil_getpwuid(pamh, user);
+ grp = _pammodutil_getgrnam(pamh, group);
+
+ return _pammodutil_user_in_group_common(pamh, pwd, grp);
+}
+
+int _pammodutil_user_in_group_uid_gid(pam_handle_t *pamh,
+ uid_t user, gid_t group)
+{
+ struct passwd *pwd;
+ struct group *grp;
+
+ pwd = _pammodutil_getpwuid(pamh, user);
+ grp = _pammodutil_getgrgid(pamh, group);
+
+ return _pammodutil_user_in_group_common(pamh, pwd, grp);
+}
diff --git a/Linux-PAM/modules/pammodutil/modutil_ioloop.c b/Linux-PAM/modules/pammodutil/modutil_ioloop.c
new file mode 100644
index 00000000..37ac76fc
--- /dev/null
+++ b/Linux-PAM/modules/pammodutil/modutil_ioloop.c
@@ -0,0 +1,52 @@
+/*
+ * $Id: modutil_ioloop.c,v 1.2 2004/09/24 09:18:22 kukuk Exp $
+ *
+ * These functions provides common methods for ensure a complete read or
+ * write occurs. It handles EINTR and partial read/write returns.
+ */
+
+#include <unistd.h>
+#include <errno.h>
+
+#include <security/pam_modules.h>
+#include "include/security/_pam_modutil.h"
+
+int _pammodutil_read(int fd, char *buffer, int count)
+{
+ int block, offset = 0;
+
+ while (count > 0) {
+ block = read(fd, &buffer[offset], count);
+
+ if (block < 0) {
+ if (errno == EINTR) continue;
+ return block;
+ }
+ if (block == 0) return offset;
+
+ offset += block;
+ count -= block;
+ }
+
+ return offset;
+}
+
+int _pammodutil_write(int fd, const char *buffer, int count)
+{
+ int block, offset = 0;
+
+ while (count > 0) {
+ block = write(fd, &buffer[offset], count);
+
+ if (block < 0) {
+ if (errno == EINTR) continue;
+ return block;
+ }
+ if (block == 0) return offset;
+
+ offset += block;
+ count -= block;
+ }
+
+ return offset;
+}
diff --git a/Linux-PAM/modules/pammodutil/pammodutil.h b/Linux-PAM/modules/pammodutil/pammodutil.h
new file mode 100644
index 00000000..2b80c852
--- /dev/null
+++ b/Linux-PAM/modules/pammodutil/pammodutil.h
@@ -0,0 +1,22 @@
+#ifndef PAMMODUTIL_H
+#define PAMMODUTIL_H
+
+/*
+ * $Id: pammodutil.h,v 1.2 2005/03/30 10:42:54 t8m Exp $
+ *
+ * Copyright (c) 2001 Andrew Morgan <morgan@kernel.org>
+ */
+
+#include <security/_pam_aconf.h>
+#include <security/_pam_macros.h>
+#include <security/pam_modules.h>
+#include <security/_pam_modutil.h>
+
+#define PWD_INITIAL_LENGTH 0x100
+#define PWD_ABSURD_PWD_LENGTH 0x8000
+
+/* This is a simple cleanup, it just free()s the 'data' memory */
+extern void _pammodutil_cleanup(pam_handle_t *pamh, void *data,
+ int error_status);
+
+#endif /* PAMMODUTIL_H */