summaryrefslogtreecommitdiff
path: root/libpam
diff options
context:
space:
mode:
Diffstat (limited to 'libpam')
-rw-r--r--libpam/.cvsignore2
-rw-r--r--libpam/Makefile162
-rw-r--r--libpam/include/security/_pam_compat.h122
-rw-r--r--libpam/include/security/_pam_macros.h166
-rw-r--r--libpam/include/security/_pam_types.h316
-rw-r--r--libpam/include/security/pam_appl.h92
-rw-r--r--libpam/include/security/pam_malloc.h79
-rw-r--r--libpam/include/security/pam_modules.h195
-rw-r--r--libpam/pam_account.c13
-rw-r--r--libpam/pam_auth.c67
-rw-r--r--libpam/pam_data.c105
-rw-r--r--libpam/pam_delay.c168
-rw-r--r--libpam/pam_dispatch.c282
-rw-r--r--libpam/pam_end.c72
-rw-r--r--libpam/pam_env.c389
-rw-r--r--libpam/pam_handlers.c896
-rw-r--r--libpam/pam_item.c304
-rw-r--r--libpam/pam_log.c382
-rw-r--r--libpam/pam_malloc.c404
-rw-r--r--libpam/pam_map.c85
-rw-r--r--libpam/pam_misc.c305
-rw-r--r--libpam/pam_password.c52
-rw-r--r--libpam/pam_private.h312
-rw-r--r--libpam/pam_second.c46
-rw-r--r--libpam/pam_session.c41
-rw-r--r--libpam/pam_start.c112
-rw-r--r--libpam/pam_static.c141
-rw-r--r--libpam/pam_strerror.c112
-rw-r--r--libpam/pam_tokens.h111
29 files changed, 5533 insertions, 0 deletions
diff --git a/libpam/.cvsignore b/libpam/.cvsignore
new file mode 100644
index 00000000..dd17fdcf
--- /dev/null
+++ b/libpam/.cvsignore
@@ -0,0 +1,2 @@
+dynamic
+static
diff --git a/libpam/Makefile b/libpam/Makefile
new file mode 100644
index 00000000..66b2a705
--- /dev/null
+++ b/libpam/Makefile
@@ -0,0 +1,162 @@
+#
+# $Id$
+#
+#
+
+# need to tell libpam about the default directory for PAMs
+MOREFLAGS=-D"DEFAULT_MODULE_PATH=\"$(SECUREDIR)/\""
+
+# you may uncomment the following to build libpam in modified ways
+
+# lots of debugging information goes to /tmp/pam-debug.log
+#MOREFLAGS += -D"DEBUG"
+
+# pay attention to locked /etc/pam.conf or /etc/pam.d/* files
+#MOREFLAGS += -D"PAM_LOCKING"
+
+# read both the /etc/pam.d/ and pam.conf files specific to the deisred service
+#MOREFLAGS += -D"PAM_READ_BOTH_CONFS"
+
+# make a kludge attempt to be compatible with the old pam_strerror
+# calling convention
+#MOREFLAGS += -D"UGLY_HACK_FOR_PRIOR_BEHAVIOR_SUPPORT"
+
+# libpam.so needs -ldl, too.
+LINKLIBS += $(LIBDL)
+
+ifeq ($(DEBUG_REL),yes)
+ LIBNAME=libpamd
+else
+ LIBNAME=libpam
+endif
+VERSION=.$(MAJOR_REL)
+MODIFICATION=.$(MINOR_REL)
+
+# ---------------------------------------------
+
+dummy:
+ @echo "*** This is not a top-level Makefile!"
+
+# ---------------------------------------------
+
+CFLAGS += $(DYNAMIC) $(STATIC) $(MOREFLAGS)
+
+# dynamic library names
+
+LIBPAM = $(LIBNAME).$(DYNTYPE)
+LIBPAMNAME = $(LIBPAM)$(VERSION)
+LIBPAMFULL = $(LIBPAMNAME)$(MODIFICATION)
+
+# static library name
+
+LIBPAMSTATIC = $(LIBNAME).a
+
+ifdef STATIC
+MODULES = $(shell cat ../modules/_static_module_objects)
+STATICOBJ = pam_static.o
+endif
+
+ifdef MEMORY_DEBUG
+EXTRAS += pam_malloc.o
+endif
+
+LIBOBJECTS = pam_item.o pam_strerror.o pam_end.o pam_start.o pam_data.o \
+ pam_delay.o pam_dispatch.o pam_handlers.o pam_misc.o \
+ pam_account.o pam_auth.o pam_session.o pam_password.o \
+ pam_env.o pam_log.o $(EXTRAS)
+
+ifdef DYNAMIC_LIBPAM
+DLIBOBJECTS = $(addprefix dynamic/,$(LIBOBJECTS) $(STATICOBJ))
+ifdef STATICOBJ
+dynamic/pam_static.o: pam_static.c ../modules/_static_module_objects
+ $(CC) $(CFLAGS) -c pam_static.c -o $@
+endif
+endif
+
+ifdef STATIC_LIBPAM
+SLIBOBJECTS = $(addprefix static/,$(LIBOBJECTS) $(STATICOBJ))
+ifdef STATICOBJ
+static/pam_static.o: pam_static.c ../modules/_static_module_objects
+ $(CC) $(CFLAGS) -c pam_static.c -o $@
+endif
+endif
+
+# ---------------------------------------------
+## rules
+
+all: dirs $(LIBPAM) $(LIBPAMSTATIC)
+
+dirs:
+ifdef DYNAMIC_LIBPAM
+ mkdir -p dynamic
+endif
+ifdef STATIC_LIBPAM
+ mkdir -p static
+endif
+
+dynamic/%.o : %.c
+ $(CC) $(CFLAGS) $(DYNAMIC) $(CPPFLAGS) $(TARGET_ARCH) -c $< -o $@
+
+static/%.o : %.c
+ $(CC) $(CFLAGS) $(STATIC) $(CPPFLAGS) $(TARGET_ARCH) -c $< -o $@
+
+$(LIBPAM): $(DLIBOBJECTS)
+ifdef DYNAMIC_LIBPAM
+ ifeq ($(USESONAME),yes)
+ $(LD_L) $(SOSWITCH) $(LIBPAMNAME) -o $@ $(DLIBOBJECTS) $(MODULES) $(LINKLIBS)
+ else
+ $(LD_L) -o $@ $(DLIBOBJECTS) $(MODULES)
+ endif
+ ifeq ($(NEEDSONAME),yes)
+ rm -f $(LIBPAMFULL)
+ ln -s $(LIBPAM) $(LIBPAMFULL)
+ rm -f $(LIBPAMNAME)
+ ln -s $(LIBPAM) $(LIBPAMNAME)
+ endif
+endif
+
+$(LIBPAMSTATIC): $(SLIBOBJECTS)
+ifdef STATIC_LIBPAM
+ $(AR) $@ $(SLIBOBJECTS) $(MODULES)
+ $(RANLIB) $@
+endif
+
+install: all
+ $(MKDIR) $(FAKEROOT)$(INCLUDED) $(FAKEROOT)$(LIBDIR)
+ $(INSTALL) -m 644 include/security/pam_appl.h $(FAKEROOT)$(INCLUDED)
+ $(INSTALL) -m 644 include/security/pam_modules.h $(FAKEROOT)$(INCLUDED)
+ $(INSTALL) -m 644 include/security/_pam_macros.h $(FAKEROOT)$(INCLUDED)
+ $(INSTALL) -m 644 include/security/_pam_types.h $(FAKEROOT)$(INCLUDED)
+ $(INSTALL) -m 644 include/security/_pam_compat.h $(FAKEROOT)$(INCLUDED)
+ifdef MEMORY_DEBUG
+ $(INSTALL) -m 644 include/security/pam_malloc.h $(FAKEROOT)$(INCLUDED)
+endif
+ifdef DYNAMIC_LIBPAM
+ $(INSTALL) -m $(SHLIBMODE) $(LIBPAM) $(FAKEROOT)$(LIBDIR)/$(LIBPAMFULL)
+ $(LDCONFIG)
+ ifneq ($(DYNTYPE),"sl")
+ ( cd $(FAKEROOT)$(LIBDIR) ; rm -f $(LIBPAM) ; ln -s $(LIBPAMNAME) $(LIBPAM) )
+ endif
+endif
+ifdef STATIC_LIBPAM
+ $(INSTALL) -m 644 $(LIBPAMSTATIC) $(FAKEROOT)$(LIBDIR)
+endif
+
+remove:
+ rm -f $(FAKEROOT)$(INCLUDED)/_pam_types.h
+ rm -f $(FAKEROOT)$(INCLUDED)/_pam_macros.h
+ rm -f $(FAKEROOT)$(INCLUDED)/pam_appl.h
+ rm -f $(FAKEROOT)$(INCLUDED)/pam_modules.h
+ rm -f $(FAKEROOT)$(INCLUDED)/pam_malloc.h
+ rm -f $(FAKEROOT)$(LIBDIR)/$(LIBPAM).*
+ rm -f $(FAKEROOT)$(LIBDIR)/$(LIBPAM)
+ $(LDCONFIG)
+ rm -f $(FAKEROOT)$(LIBDIR)/$(LIBPAMSTATIC)
+
+clean:
+ rm -f a.out core *~ static/*.o dynamic/*.o
+
+extraclean: clean
+ rm -f *.a *.out *.o *.so ./include/security/*~
+ if [ -d dynamic ]; then rmdir dynamic ; fi
+ if [ -d static ]; then rmdir static ; fi
diff --git a/libpam/include/security/_pam_compat.h b/libpam/include/security/_pam_compat.h
new file mode 100644
index 00000000..a5f77e7a
--- /dev/null
+++ b/libpam/include/security/_pam_compat.h
@@ -0,0 +1,122 @@
+#ifndef _PAM_COMPAT_H
+#define _PAM_COMPAT_H
+
+/*
+ * $Id$
+ *
+ * This file was contributed by Derrick J Brashear <shadow@dementia.org>
+ * slight modification by Brad M. Garcia <bgarcia@fore.com>
+ *
+ * A number of operating systems have started to implement PAM.
+ * unfortunately, they have a different set of numeric values for
+ * certain constants. This file is included for compatibility's sake.
+ */
+
+/* Solaris uses different constants. We redefine to those here */
+#if defined(solaris) || (defined(__SVR4) && defined(sun))
+
+#ifndef _SECURITY__PAM_TYPES_H
+
+# ifdef _SECURITY_PAM_MODULES_H
+
+/* flags for pam_chauthtok() */
+# undef PAM_PRELIM_CHECK
+# define PAM_PRELIM_CHECK 0x1
+
+# undef PAM_UPDATE_AUTHTOK
+# define PAM_UPDATE_AUTHTOK 0x2
+
+# endif /* _SECURITY_PAM_MODULES_H */
+
+#else /* _SECURITY__PAM_TYPES_H */
+
+/* generic for pam_* functions */
+# undef PAM_SILENT
+# define PAM_SILENT 0x80000000
+
+/* flags for pam_setcred() */
+# undef PAM_ESTABLISH_CRED
+# define PAM_ESTABLISH_CRED 0x1
+
+# undef PAM_DELETE_CRED
+# define PAM_DELETE_CRED 0x2
+
+# undef PAM_REINITIALIZE_CRED
+# define PAM_REINITIALIZE_CRED 0x4
+
+# undef PAM_REFRESH_CRED
+# define PAM_REFRESH_CRED 0x8
+
+/* another binary incompatibility comes from the return codes! */
+
+# undef PAM_CONV_ERR
+# define PAM_CONV_ERR 6
+
+# undef PAM_PERM_DENIED
+# define PAM_PERM_DENIED 7
+
+# undef PAM_MAXTRIES
+# define PAM_MAXTRIES 8
+
+# undef PAM_AUTH_ERR
+# define PAM_AUTH_ERR 9
+
+# undef PAM_NEW_AUTHTOK_REQD
+# define PAM_NEW_AUTHTOK_REQD 10
+
+# undef PAM_CRED_INSUFFICIENT
+# define PAM_CRED_INSUFFICIENT 11
+
+# undef PAM_AUTHINFO_UNAVAIL
+# define PAM_AUTHINFO_UNAVAIL 12
+
+# undef PAM_USER_UNKNOWN
+# define PAM_USER_UNKNOWN 13
+
+# undef PAM_CRED_UNAVAIL
+# define PAM_CRED_UNAVAIL 14
+
+# undef PAM_CRED_EXPIRED
+# define PAM_CRED_EXPIRED 15
+
+# undef PAM_CRED_ERR
+# define PAM_CRED_ERR 16
+
+# undef PAM_ACCT_EXPIRED
+# define PAM_ACCT_EXPIRED 17
+
+# undef PAM_AUTHTOK_EXPIRED
+# define PAM_AUTHTOK_EXPIRED 18
+
+# undef PAM_SESSION_ERR
+# define PAM_SESSION_ERR 19
+
+# undef PAM_AUTHTOK_ERR
+# define PAM_AUTHTOK_ERR 20
+
+# undef PAM_AUTHTOK_RECOVERY_ERR
+# define PAM_AUTHTOK_RECOVERY_ERR 21
+
+# undef PAM_AUTHTOK_LOCK_BUSY
+# define PAM_AUTHTOK_LOCK_BUSY 22
+
+# undef PAM_AUTHTOK_DISABLE_AGING
+# define PAM_AUTHTOK_DISABLE_AGING 23
+
+# undef PAM_NO_MODULE_DATA
+# define PAM_NO_MODULE_DATA 24
+
+# undef PAM_IGNORE
+# define PAM_IGNORE 25
+
+# undef PAM_ABORT
+# define PAM_ABORT 26
+
+# undef PAM_TRY_AGAIN
+# define PAM_TRY_AGAIN 27
+
+#endif /* _SECURITY__PAM_TYPES_H */
+
+#endif /* defined(solaris) || (defined(__SVR4) && defined(sun)) */
+
+#endif /* _PAM_COMPAT_H */
diff --git a/libpam/include/security/_pam_macros.h b/libpam/include/security/_pam_macros.h
new file mode 100644
index 00000000..7c3dde1d
--- /dev/null
+++ b/libpam/include/security/_pam_macros.h
@@ -0,0 +1,166 @@
+#ifndef PAM_MACROS_H
+#define PAM_MACROS_H
+
+/*
+ * All kind of macros used by PAM, but usable in some other
+ * programs too.
+ * Organized by Cristian Gafton <gafton@redhat.com>
+ */
+
+/* a 'safe' version of strdup */
+
+#include <string.h>
+#include <stdlib.h>
+
+#define x_strdup(s) ( (s) ? strdup(s):NULL )
+
+/* Good policy to strike out passwords with some characters not just
+ free the memory */
+
+#define _pam_overwrite(x) \
+do { \
+ register char *__xx__; \
+ if ((__xx__=(x))) \
+ while (*__xx__) \
+ *__xx__++ = '\0'; \
+} while (0)
+
+/*
+ * Don't just free it, forget it too.
+ */
+
+#define _pam_drop(X) \
+do { \
+ if (X) { \
+ free(X); \
+ X=NULL; \
+ } \
+} while (0)
+
+#define _pam_drop_reply(/* struct pam_response * */ reply, /* int */ replies) \
+do { \
+ int reply_i; \
+ \
+ for (reply_i=0; reply_i<replies; ++reply_i) { \
+ if (reply[reply_i].resp) { \
+ _pam_overwrite(reply[reply_i].resp); \
+ free(reply[reply_i].resp); \
+ } \
+ } \
+ if (reply) \
+ free(reply); \
+} while (0)
+
+/* some debugging code */
+
+#ifdef DEBUG
+
+/*
+ * This provides the necessary function to do debugging in PAM.
+ * Cristian Gafton <gafton@redhat.com>
+ */
+
+#include <stdio.h>
+#include <sys/types.h>
+#include <stdarg.h>
+#include <errno.h>
+
+/*
+ * This is for debugging purposes ONLY. DO NOT use on live systems !!!
+ * You have been warned :-) - CG
+ *
+ * to get automated debugging to the log file, it must be created manually.
+ * _PAM_LOGFILE must exist, mode 666
+ */
+
+#ifndef _PAM_LOGFILE
+#define _PAM_LOGFILE "/tmp/pam-debug.log"
+#endif
+
+static void _pam_output_debug_info(const char *file, const char *fn
+ , const int line)
+{
+ FILE *logfile;
+ int must_close = 1;
+
+ if (!(logfile = fopen(_PAM_LOGFILE,"a"))) {
+ logfile = stderr;
+ must_close = 0;
+ }
+ fprintf(logfile,"[%s:%s(%d)] ",file, fn, line);
+ if (must_close) {
+ fflush(logfile);
+ fclose(logfile);
+ }
+}
+
+static void _pam_output_debug(const char *format, ...)
+{
+ va_list args;
+ FILE *logfile;
+ int must_close = 1;
+
+ va_start(args, format);
+
+ if (!(logfile = fopen(_PAM_LOGFILE,"a"))) {
+ logfile = stderr;
+ must_close = 0;
+ }
+ vfprintf(logfile, format, args);
+ fprintf(logfile, "\n");
+ if (must_close) {
+ fflush(logfile);
+ fclose(logfile);
+ }
+
+ va_end(args);
+}
+
+#define D(x) do { \
+ _pam_output_debug_info(__FILE__, __FUNCTION__, __LINE__); \
+ _pam_output_debug x ; \
+} while (0)
+
+#define _pam_show_mem(X,XS) do { \
+ int i; \
+ register unsigned char *x; \
+ x = (unsigned char *)X; \
+ fprintf(stderr, " <start at %p>\n", X); \
+ for (i = 0; i < XS ; ++x, ++i) { \
+ fprintf(stderr, " %02X. <%p:%02X>\n", i, x, *x); \
+ } \
+ fprintf(stderr, " <end for %p after %d bytes>\n", X, XS); \
+} while (0)
+
+#define _pam_show_reply(/* struct pam_response * */reply, /* int */replies) \
+do { \
+ int reply_i; \
+ setbuf(stderr, NULL); \
+ fprintf(stderr, "array at %p of size %d\n",reply,replies); \
+ fflush(stderr); \
+ if (reply) { \
+ for (reply_i = 0; reply_i < replies; reply_i++) { \
+ fprintf(stderr, " elem# %d at %p: resp = %p, retcode = %d\n", \
+ reply_i, reply+reply_i, reply[reply_i].resp, \
+ reply[reply_i].resp, _retcode); \
+ fflush(stderr); \
+ if (reply[reply_i].resp) { \
+ fprintf(stderr, " resp[%d] = '%s'\n", \
+ strlen(reply[reply_i].resp), reply[reply_i].resp); \
+ fflush(stderr); \
+ } \
+ } \
+ } \
+ fprintf(stderr, "done here\n"); \
+ fflush(stderr); \
+} while (0)
+
+#else
+
+#define D(x) do { } while (0)
+#define _pam_show_mem(X,XS) do { } while (0)
+#define _pam_show_reply(reply, replies) do { } while (0)
+
+#endif /* DEBUG */
+
+#endif /* PAM_MACROS_H */
diff --git a/libpam/include/security/_pam_types.h b/libpam/include/security/_pam_types.h
new file mode 100644
index 00000000..fe4ada39
--- /dev/null
+++ b/libpam/include/security/_pam_types.h
@@ -0,0 +1,316 @@
+/*
+ * <security/_pam_types.h>
+ *
+ * $Id$
+ *
+ * This file defines all of the types common to the Linux-PAM library
+ * applications and modules.
+ *
+ * Note, the copyright+license information is at end of file.
+ *
+ * Created: 1996/3/5 by AGM
+ */
+
+#ifndef _SECURITY__PAM_TYPES_H
+#define _SECURITY__PAM_TYPES_H
+
+/*
+ * include local definition for POSIX - NULL
+ */
+
+#include <locale.h>
+
+/* This is a blind structure; users aren't allowed to see inside a
+ * pam_handle_t, so we don't define struct pam_handle here. This is
+ * defined in a file private to the PAM library. (i.e., it's private
+ * to PAM service modules, too!) */
+
+typedef struct pam_handle pam_handle_t;
+
+/* ----------------- The Linux-PAM return values ------------------ */
+
+#define PAM_SUCCESS 0 /* Successful function return */
+#define PAM_OPEN_ERR 1 /* dlopen() failure when dynamically */
+ /* loading a service module */
+#define PAM_SYMBOL_ERR 2 /* Symbol not found */
+#define PAM_SERVICE_ERR 3 /* Error in service module */
+#define PAM_SYSTEM_ERR 4 /* System error */
+#define PAM_BUF_ERR 5 /* Memory buffer error */
+#define PAM_PERM_DENIED 6 /* Permission denied */
+#define PAM_AUTH_ERR 7 /* Authentication failure */
+#define PAM_CRED_INSUFFICIENT 8 /* Can not access authentication data */
+ /* due to insufficient credentials */
+#define PAM_AUTHINFO_UNAVAIL 9 /* Underlying authentication service */
+ /* can not retrieve authenticaiton */
+ /* information */
+#define PAM_USER_UNKNOWN 10 /* User not known to the underlying */
+ /* authenticaiton module */
+#define PAM_MAXTRIES 11 /* An authentication service has */
+ /* maintained a retry count which has */
+ /* been reached. No further retries */
+ /* should be attempted */
+#define PAM_NEW_AUTHTOK_REQD 12 /* New authentication token required. */
+ /* This is normally returned if the */
+ /* machine security policies require */
+ /* that the password should be changed */
+ /* beccause the password is NULL or it */
+ /* has aged */
+#define PAM_ACCT_EXPIRED 13 /* User account has expired */
+#define PAM_SESSION_ERR 14 /* Can not make/remove an entry for */
+ /* the specified session */
+#define PAM_CRED_UNAVAIL 15 /* Underlying authentication service */
+ /* can not retrieve user credentials */
+ /* unavailable */
+#define PAM_CRED_EXPIRED 16 /* User credentials expired */
+#define PAM_CRED_ERR 17 /* Failure setting user credentials */
+#define PAM_NO_MODULE_DATA 18 /* No module specific data is present */
+#define PAM_CONV_ERR 19 /* Conversation error */
+#define PAM_AUTHTOK_ERR 20 /* Authentication token manipulation error */
+#define PAM_AUTHTOK_RECOVER_ERR 21 /* Authentication information */
+ /* cannot be recovered */
+#define PAM_AUTHTOK_LOCK_BUSY 22 /* Authentication token lock busy */
+#define PAM_AUTHTOK_DISABLE_AGING 23 /* Authentication token aging disabled */
+#define PAM_TRY_AGAIN 24 /* Preliminary check by password service */
+#define PAM_IGNORE 25 /* Ingore underlying account module */
+ /* regardless of whether the control */
+ /* flag is required, optional, or sufficient */
+#define PAM_ABORT 26 /* Critical error (?module fail now request) */
+#define PAM_AUTHTOK_EXPIRED 27 /* user's authentication token has expired */
+#define PAM_MODULE_UNKNOWN 28 /* module is not known */
+
+#define PAM_BAD_ITEM 29 /* Bad item passed to pam_*_item() */
+#define PAM_CONV_AGAIN 30 /* conversation function is event driven
+ and data is not available yet */
+#define PAM_INCOMPLETE 31 /* please call this function again to
+ complete authentication stack. Before
+ calling again, verify that conversation
+ is completed */
+
+/* Add new #define's here */
+
+#define _PAM_RETURN_VALUES 32 /* this is the number of return values */
+
+
+/* ---------------------- The Linux-PAM flags -------------------- */
+
+/* Authentication service should not generate any messages */
+#define PAM_SILENT 0x8000U
+
+/* Note: these flags are used by pam_authenticate{,_secondary}() */
+
+/* The authentication service should return PAM_AUTH_ERROR if the
+ * user has a null authentication token */
+#define PAM_DISALLOW_NULL_AUTHTOK 0x0001U
+
+/* Note: these flags are used for pam_setcred() */
+
+/* Set user credentials for an authentication service */
+#define PAM_ESTABLISH_CRED 0x0002U
+
+/* Delete user credentials associated with an authentication service */
+#define PAM_DELETE_CRED 0x0004U
+
+/* Reinitialize user credentials */
+#define PAM_REINITIALIZE_CRED 0x0008U
+
+/* Extend lifetime of user credentials */
+#define PAM_REFRESH_CRED 0x0010U
+
+/* Note: these flags are used by pam_chauthtok */
+
+/* The password service should only update those passwords that have
+ * aged. If this flag is not passed, the password service should
+ * update all passwords. */
+#define PAM_CHANGE_EXPIRED_AUTHTOK 0x0020U
+
+/* ------------------ The Linux-PAM item types ------------------- */
+
+/* these defines are used by pam_set_item() and pam_get_item() */
+
+#define PAM_SERVICE 1 /* The service name */
+#define PAM_USER 2 /* The user name */
+#define PAM_TTY 3 /* The tty name */
+#define PAM_RHOST 4 /* The remote host name */
+#define PAM_CONV 5 /* The pam_conv structure */
+
+/* missing entries found in <security/pam_modules.h> for modules only! */
+
+#define PAM_RUSER 8 /* The remote user name */
+#define PAM_USER_PROMPT 9 /* the prompt for getting a username */
+#define PAM_FAIL_DELAY 10 /* app supplied function to override failure
+ delays */
+
+/* ---------- Common Linux-PAM application/module PI ----------- */
+
+extern int pam_set_item(pam_handle_t *pamh, int item_type, const void *item);
+extern int pam_get_item(const pam_handle_t *pamh, int item_type,
+ const void **item);
+extern const char *pam_strerror(pam_handle_t *pamh, int errnum);
+
+extern int pam_putenv(pam_handle_t *pamh, const char *name_value);
+extern const char *pam_getenv(pam_handle_t *pamh, const char *name);
+extern char **pam_getenvlist(pam_handle_t *pamh);
+
+/* ---------- Common Linux-PAM application/module PI ----------- */
+
+/*
+ * here are some proposed error status definitions for the
+ * 'error_status' argument used by the cleanup function associated
+ * with data items they should be logically OR'd with the error_status
+ * of the latest return from libpam -- new with .52 and positive
+ * impression from Sun although not official as of 1996/9/4
+ * [generally the other flags are to be found in pam_modules.h]
+ */
+
+#define PAM_DATA_SILENT 0x40000000 /* used to suppress messages... */
+
+/*
+ * here we define an externally (by apps or modules) callable function
+ * that primes the libpam library to delay when a stacked set of
+ * modules results in a failure. In the case of PAM_SUCCESS this delay
+ * is ignored.
+ *
+ * Note, the pam_[gs]et_item(... PAM_FAIL_DELAY ...) can be used to set
+ * a function pointer which can override the default fail-delay behavior.
+ * This item was added to accommodate event driven programs that need to
+ * manage delays more carefully. The function prototype for this data
+ * item is
+ * void (*fail_delay)(int status, unsigned int delay);
+ */
+
+#define HAVE_PAM_FAIL_DELAY
+extern int pam_fail_delay(pam_handle_t *pamh, unsigned int musec_delay);
+
+#include <syslog.h>
+#ifndef LOG_AUTHPRIV
+# ifdef LOG_PRIV
+# define LOG_AUTHPRIV LOG_PRIV
+# endif /* LOG_PRIV */
+#endif /* !LOG_AUTHPRIV */
+
+#ifdef MEMORY_DEBUG
+/*
+ * this defines some macros that keep track of what memory has been
+ * allocated and indicates leakage etc... It should not be included in
+ * production application/modules.
+ */
+#include <security/pam_malloc.h>
+#endif
+
+/* ------------ The Linux-PAM conversation structures ------------ */
+
+/* Message styles */
+
+#define PAM_PROMPT_ECHO_OFF 1
+#define PAM_PROMPT_ECHO_ON 2
+#define PAM_ERROR_MSG 3
+#define PAM_TEXT_INFO 4
+
+/* Linux-PAM specific types */
+
+#define PAM_RADIO_TYPE 5 /* yes/no/maybe conditionals */
+
+/* This is for server client non-human interaction.. these are NOT
+ part of the X/Open PAM specification. */
+
+#define PAM_BINARY_PROMPT 7
+
+/* maximum size of messages/responses etc.. (these are mostly
+ arbitrary so Linux-PAM should handle longer values). */
+
+#define PAM_MAX_NUM_MSG 32
+#define PAM_MAX_MSG_SIZE 512
+#define PAM_MAX_RESP_SIZE 512
+
+/* Used to pass prompting text, error messages, or other informatory
+ * text to the user. This structure is allocated and freed by the PAM
+ * library (or loaded module). */
+
+struct pam_message {
+ int msg_style;
+ const char *msg;
+};
+
+/* if the pam_message.msg_style = PAM_BINARY_PROMPT
+ the 'pam_message.msg' is a pointer to a 'const *' for the following
+ pseudo-structure. When used with a PAM_BINARY_PROMPT, the returned
+ pam_response.resp pointer points to an object with the following
+ structure:
+
+ struct {
+ u32 length; # network byte order
+ unsigned char type;
+ unsigned char data[length-5];
+ };
+
+ The 'libpamc' library is designed around this flavor of
+ message and should be used to handle this flavor of msg_style.
+ */
+
+/* Used to return the user's response to the PAM library. This
+ structure is allocated by the application program, and free()'d by
+ the Linux-PAM library (or calling module). */
+
+struct pam_response {
+ char *resp;
+ int resp_retcode; /* currently un-used, zero expected */
+};
+
+/* The actual conversation structure itself */
+
+struct pam_conv {
+ int (*conv)(int num_msg, const struct pam_message **msg,
+ struct pam_response **resp, void *appdata_ptr);
+ void *appdata_ptr;
+};
+
+#ifndef LINUX_PAM
+/*
+ * the following few lines represent a hack. They are there to make
+ * the Linux-PAM headers more compatible with the Sun ones, which have a
+ * less strictly separated notion of module specific and application
+ * specific definitions.
+ */
+#include <security/pam_appl.h>
+#include <security/pam_modules.h>
+#endif
+
+
+/* ... adapted from the pam_appl.h file created by Theodore Ts'o and
+ *
+ * Copyright Theodore Ts'o, 1996. All rights reserved.
+ * Copyright (c) Andrew G. Morgan <morgan@linux.kernel.org>, 1996-8
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, and the entire permission notice in its entirety,
+ * including the disclaimer of warranties.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote
+ * products derived from this software without specific prior
+ * written permission.
+ *
+ * ALTERNATIVELY, this product may be distributed under the terms of
+ * the GNU Public License, in which case the provisions of the GPL are
+ * required INSTEAD OF the above restrictions. (This clause is
+ * necessary due to a potential bad interaction between the GPL and
+ * the restrictions contained in a BSD-style copyright.)
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE. */
+
+#endif /* _SECURITY__PAM_TYPES_H */
+
diff --git a/libpam/include/security/pam_appl.h b/libpam/include/security/pam_appl.h
new file mode 100644
index 00000000..2849970a
--- /dev/null
+++ b/libpam/include/security/pam_appl.h
@@ -0,0 +1,92 @@
+/*
+ * <security/pam_appl.h>
+ *
+ * This header file collects definitions for the PAM API --- that is,
+ * public interface between the PAM library and an application program
+ * that wishes to use it.
+ *
+ * Note, the copyright information is at end of file.
+ *
+ * Created: 15-Jan-96 by TYT
+ * Last modified: 1996/3/5 by AGM
+ *
+ * $Id$
+ */
+
+#ifndef _SECURITY_PAM_APPL_H
+#define _SECURITY_PAM_APPL_H
+
+#include <security/_pam_types.h> /* Linux-PAM common defined types */
+
+/* -------------- The Linux-PAM Framework layer API ------------- */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+extern int pam_start(const char *service_name, const char *user,
+ const struct pam_conv *pam_conversation,
+ pam_handle_t **pamh);
+extern int pam_end(pam_handle_t *pamh, int pam_status);
+
+/* Authentication API's */
+
+extern int pam_authenticate(pam_handle_t *pamh, int flags);
+extern int pam_setcred(pam_handle_t *pamh, int flags);
+
+/* Account Management API's */
+
+extern int pam_acct_mgmt(pam_handle_t *pamh, int flags);
+
+/* Session Management API's */
+
+extern int pam_open_session(pam_handle_t *pamh, int flags);
+extern int pam_close_session(pam_handle_t *pamh, int flags);
+
+/* Password Management API's */
+
+extern int pam_chauthtok(pam_handle_t *pamh, int flags);
+
+#ifdef __cplusplus
+}
+#endif
+
+/* take care of any compatibility issues */
+#include <security/_pam_compat.h>
+
+/*
+ * Copyright Theodore Ts'o, 1996. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, and the entire permission notice in its entirety,
+ * including the disclaimer of warranties.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote
+ * products derived from this software without specific prior
+ * written permission.
+ *
+ * ALTERNATIVELY, this product may be distributed under the terms of
+ * the GNU Public License, in which case the provisions of the GPL are
+ * required INSTEAD OF the above restrictions. (This clause is
+ * necessary due to a potential bad interaction between the GPL and
+ * the restrictions contained in a BSD-style copyright.)
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#endif /* _SECURITY_PAM_APPL_H */
diff --git a/libpam/include/security/pam_malloc.h b/libpam/include/security/pam_malloc.h
new file mode 100644
index 00000000..8daf3f7c
--- /dev/null
+++ b/libpam/include/security/pam_malloc.h
@@ -0,0 +1,79 @@
+/* $Id$
+ *
+ * $Log$
+ * Revision 1.1 2000/06/20 22:11:23 agmorgan
+ * Initial revision
+ *
+ * Revision 1.1.1.1 1998/07/12 05:17:15 morgan
+ * Linux PAM sources pre-0.66
+ *
+ * Revision 1.1 1996/11/10 21:23:14 morgan
+ * Initial revision
+ *
+ */
+
+/*
+ * This file (via the use of macros) defines a wrapper for the malloc
+ * family of calls. It logs where the memory was requested and also
+ * where it was free()'d and keeps a list of currently requested memory.
+ *
+ * It is hoped that it will provide some help in locating memory leaks.
+ */
+
+#ifndef PAM_MALLOC_H
+#define PAM_MALLOC_H
+
+/* these are the macro definitions for the stdlib.h memory functions */
+
+#define malloc(s) pam_malloc(s,__FILE__,__FUNCTION__,__LINE__)
+#define calloc(n,s) pam_calloc(n,s,__FILE__,__FUNCTION__,__LINE__)
+#define free(x) pam_free(x,__FILE__,__FUNCTION__,__LINE__)
+/* #define memalign(a,s) pam_memalign(a,s,__FILE__,__FUNCTION__,__LINE__) */
+#define realloc(x,s) pam_realloc(x,s,__FILE__,__FUNCTION__,__LINE__)
+/* #define valloc(s) pam_valloc(s,__FILE__,__FUNCTION__,__LINE__) */
+/* #define alloca(s) pam_alloca(s,__FILE__,__FUNCTION__,__LINE__) */
+#define exit(i) pam_exit(i,__FILE__,__FUNCTION__,__LINE__)
+
+/* these are the prototypes for the wrapper functions */
+
+#include <sys/types.h>
+
+extern void *pam_malloc(size_t s,const char *,const char *,const int);
+extern void *pam_calloc(size_t n,size_t s,const char *,const char *,const int);
+extern void pam_free(void *x,const char *,const char *,const int);
+extern void *pam_memalign(size_t a,size_t s
+ ,const char *,const char *,const int);
+extern void *pam_realloc(void *x,size_t s,const char *,const char *,const int);
+extern void *pam_valloc(size_t s,const char *,const char *,const int);
+extern void *pam_alloca(size_t s,const char *,const char *,const int);
+extern void pam_exit(int i,const char *,const char *,const int);
+
+/* these are the flags used to turn on and off diagnostics */
+
+#define PAM_MALLOC_LEAKED 01
+#define PAM_MALLOC_REQUEST 02
+#define PAM_MALLOC_FREE 04
+#define PAM_MALLOC_EXCH (PAM_MALLOC_FREED|PAM_MALLOC_EXCH)
+#define PAM_MALLOC_RESIZE 010
+#define PAM_MALLOC_FAIL 020
+#define PAM_MALLOC_NULL 040
+#define PAM_MALLOC_VERIFY 0100
+#define PAM_MALLOC_FUNC 0200
+#define PAM_MALLOC_PAUSE 0400
+#define PAM_MALLOC_STOP 01000
+
+#define PAM_MALLOC_ALL 0777
+
+#define PAM_MALLOC_DEFAULT \
+ (PAM_MALLOC_LEAKED|PAM_MALLOC_PAUSE|PAM_MALLOC_FAIL)
+
+#include <stdio.h>
+
+extern FILE *pam_malloc_outfile; /* defaults to stdout */
+
+/* how much output do you want? */
+
+extern int pam_malloc_flags;
+extern int pam_malloc_delay_length; /* how long to pause on errors */
+
+#endif /* PAM_MALLOC_H */
diff --git a/libpam/include/security/pam_modules.h b/libpam/include/security/pam_modules.h
new file mode 100644
index 00000000..945c1711
--- /dev/null
+++ b/libpam/include/security/pam_modules.h
@@ -0,0 +1,195 @@
+/*
+ * <security/pam_modules.h>
+ *
+ * $Id$
+ *
+ * This header file documents the PAM SPI --- that is, interface
+ * between the PAM library and a PAM service library which is called
+ * by the PAM library.
+ *
+ * Note, the copyright information is at end of file.
+ *
+ * $Log$
+ * Revision 1.1 2000/06/20 22:11:23 agmorgan
+ * Initial revision
+ *
+ * Revision 1.1.1.1 1998/07/12 05:17:15 morgan
+ * Linux PAM sources pre-0.66
+ *
+ * Revision 1.8 1997/01/04 20:14:42 morgan
+ * moved PAM_DATA_SILENT to _pam_types.h so applications can use it too
+ *
+ * Revision 1.7 1996/11/10 19:57:08 morgan
+ * pam_get_user prototype.
+ *
+ * Revision 1.6 1996/09/05 06:18:45 morgan
+ * added some data error_status masks, changed prototype for cleanup()
+ *
+ * Revision 1.5 1996/06/02 07:58:37 morgan
+ * altered the way in which modules obtain static prototypes for
+ * functions
+ *
+ */
+
+#ifndef _SECURITY_PAM_MODULES_H
+#define _SECURITY_PAM_MODULES_H
+
+#include <security/_pam_types.h> /* Linux-PAM common defined types */
+
+/* these defines are used by pam_set_item() and pam_get_item() and are
+ * in addition to those found in <security/_pam_types.h> */
+
+#define PAM_AUTHTOK 6 /* The authentication token (password) */
+#define PAM_OLDAUTHTOK 7 /* The old authentication token */
+
+/* -------------- The Linux-PAM Module PI ------------- */
+
+extern int pam_set_data(pam_handle_t *pamh, const char *module_data_name,
+ void *data,
+ void (*cleanup)(pam_handle_t *pamh, void *data,
+ int error_status));
+extern int pam_get_data(const pam_handle_t *pamh,
+ const char *module_data_name, const void **data);
+
+extern int pam_get_user(pam_handle_t *pamh, const char **user
+ , const char *prompt);
+
+#ifdef PAM_STATIC
+
+#define PAM_EXTERN static
+
+struct pam_module {
+ const char *name; /* Name of the module */
+
+ /* These are function pointers to the module's key functions. */
+
+ int (*pam_sm_authenticate)(pam_handle_t *pamh, int flags,
+ int argc, const char **argv);
+ int (*pam_sm_setcred)(pam_handle_t *pamh, int flags,
+ int argc, const char **argv);
+ int (*pam_sm_acct_mgmt)(pam_handle_t *pamh, int flags,
+ int argc, const char **argv);
+ int (*pam_sm_open_session)(pam_handle_t *pamh, int flags,
+ int argc, const char **argv);
+ int (*pam_sm_close_session)(pam_handle_t *pamh, int flags,
+ int argc, const char **argv);
+ int (*pam_sm_chauthtok)(pam_handle_t *pamh, int flags,
+ int argc, const char **argv);
+};
+
+#else /* !PAM_STATIC */
+
+#define PAM_EXTERN extern
+
+#endif /* PAM_STATIC */
+
+/* Lots of files include pam_modules.h that don't need these
+ * declared. However, when they are declared static, they
+ * need to be defined later. So we have to protect C files
+ * that include these without wanting these functions defined.. */
+
+#if (defined(PAM_STATIC) && defined(PAM_SM_AUTH)) || !defined(PAM_STATIC)
+
+/* Authentication API's */
+PAM_EXTERN int pam_sm_authenticate(pam_handle_t *pamh, int flags,
+ int argc, const char **argv);
+PAM_EXTERN int pam_sm_setcred(pam_handle_t *pamh, int flags,
+ int argc, const char **argv);
+
+#endif /*(defined(PAM_STATIC) && defined(PAM_SM_AUTH))
+ || !defined(PAM_STATIC)*/
+
+#if (defined(PAM_STATIC) && defined(PAM_SM_ACCOUNT)) || !defined(PAM_STATIC)
+
+/* Account Management API's */
+PAM_EXTERN int pam_sm_acct_mgmt(pam_handle_t *pamh, int flags,
+ int argc, const char **argv);
+
+#endif /*(defined(PAM_STATIC) && defined(PAM_SM_ACCOUNT))
+ || !defined(PAM_STATIC)*/
+
+#if (defined(PAM_STATIC) && defined(PAM_SM_SESSION)) || !defined(PAM_STATIC)
+
+/* Session Management API's */
+PAM_EXTERN int pam_sm_open_session(pam_handle_t *pamh, int flags,
+ int argc, const char **argv);
+
+PAM_EXTERN int pam_sm_close_session(pam_handle_t *pamh, int flags,
+ int argc, const char **argv);
+
+#endif /*(defined(PAM_STATIC) && defined(PAM_SM_SESSION))
+ || !defined(PAM_STATIC)*/
+
+#if (defined(PAM_STATIC) && defined(PAM_SM_PASSWORD)) || !defined(PAM_STATIC)
+
+/* Password Management API's */
+PAM_EXTERN int pam_sm_chauthtok(pam_handle_t *pamh, int flags,
+ int argc, const char **argv);
+
+#endif /*(defined(PAM_STATIC) && defined(PAM_SM_PASSWORD))
+ || !defined(PAM_STATIC)*/
+
+/* The following two flags are for use across the Linux-PAM/module
+ * interface only. The Application is not permitted to use these
+ * tokens.
+ *
+ * The password service should only perform preliminary checks. No
+ * passwords should be updated. */
+#define PAM_PRELIM_CHECK 0x4000
+
+/* The password service should update passwords Note: PAM_PRELIM_CHECK
+ * and PAM_UPDATE_AUTHTOK can not both be set simultaneously! */
+#define PAM_UPDATE_AUTHTOK 0x2000
+
+
+/*
+ * here are some proposed error status definitions for the
+ * 'error_status' argument used by the cleanup function associated
+ * with data items they should be logically OR'd with the error_status
+ * of the latest return from libpam -- new with .52 and positive
+ * impression from Sun although not official as of 1996/9/4 there are
+ * others in _pam_types.h -- they are for common module/app use.
+ */
+
+#define PAM_DATA_REPLACE 0x20000000 /* used when replacing a data item */
+
+/* take care of any compatibility issues */
+#include <security/_pam_compat.h>
+
+/* Copyright (C) Theodore Ts'o, 1996.
+ * Copyright (C) Andrew Morgan, 1996-8.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, and the entire permission notice in its entirety,
+ * including the disclaimer of warranties.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote
+ * products derived from this software without specific prior
+ * written permission.
+ *
+ * ALTERNATIVELY, this product may be distributed under the terms of
+ * the GNU General Public License, in which case the provisions of the
+ * GNU GPL are required INSTEAD OF the above restrictions. (This
+ * clause is necessary due to a potential bad interaction between the
+ * GNU GPL and the restrictions contained in a BSD-style copyright.)
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE. */
+
+#endif /* _SECURITY_PAM_MODULES_H */
+
diff --git a/libpam/pam_account.c b/libpam/pam_account.c
new file mode 100644
index 00000000..ffc01acd
--- /dev/null
+++ b/libpam/pam_account.c
@@ -0,0 +1,13 @@
+/* pam_account.c - PAM Account Management */
+
+#include <stdio.h>
+
+#include "pam_private.h"
+
+int pam_acct_mgmt(pam_handle_t *pamh, int flags)
+{
+ D(("called"));
+
+ IF_NO_PAMH("pam_acct_mgmt",pamh,PAM_SYSTEM_ERR);
+ return _pam_dispatch(pamh, flags, PAM_ACCOUNT);
+}
diff --git a/libpam/pam_auth.c b/libpam/pam_auth.c
new file mode 100644
index 00000000..c946eaab
--- /dev/null
+++ b/libpam/pam_auth.c
@@ -0,0 +1,67 @@
+/*
+ * pam_auth.c -- PAM authentication
+ *
+ * $Id$
+ *
+ * $Log$
+ * Revision 1.1 2000/06/20 22:11:13 agmorgan
+ * Initial revision
+ *
+ * Revision 1.1.1.1 1998/07/12 05:17:15 morgan
+ * Linux PAM sources pre-0.66
+ *
+ * Revision 1.7 1997/04/05 06:53:52 morgan
+ * fail-delay changes
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "pam_private.h"
+
+int pam_authenticate(pam_handle_t *pamh, int flags)
+{
+ int retval;
+
+ D(("pam_authenticate called"));
+
+ if (pamh->former.choice == PAM_NOT_STACKED) {
+ _pam_sanitize(pamh);
+ _pam_start_timer(pamh); /* we try to make the time for a failure
+ independent of the time it takes to
+ fail */
+ }
+
+ IF_NO_PAMH("pam_authenticate",pamh,PAM_SYSTEM_ERR);
+ retval = _pam_dispatch(pamh, flags, PAM_AUTHENTICATE);
+
+ if (retval != PAM_INCOMPLETE) {
+ _pam_sanitize(pamh);
+ _pam_await_timer(pamh, retval); /* if unsuccessful then wait now */
+ D(("pam_authenticate exit"));
+ } else {
+ D(("will resume when ready"));
+ }
+
+ return retval;
+}
+
+int pam_setcred(pam_handle_t *pamh, int flags)
+{
+ int retval;
+
+ IF_NO_PAMH("pam_setcred", pamh, PAM_SYSTEM_ERR);
+
+ D(("pam_setcred called"));
+
+ if (! flags) {
+ flags = PAM_ESTABLISH_CRED;
+ }
+
+ retval = _pam_dispatch(pamh, flags, PAM_SETCRED);
+
+ D(("pam_setcred exit"));
+
+ return retval;
+}
diff --git a/libpam/pam_data.c b/libpam/pam_data.c
new file mode 100644
index 00000000..6422b10e
--- /dev/null
+++ b/libpam/pam_data.c
@@ -0,0 +1,105 @@
+/* pam_data.c */
+
+/*
+ * $Id$
+ */
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "pam_private.h"
+
+struct pam_data *_pam_locate_data(const pam_handle_t *pamh, const char *name);
+
+int pam_set_data(
+ pam_handle_t *pamh,
+ const char *module_data_name,
+ void *data,
+ void (*cleanup)(pam_handle_t *pamh, void *data, int error_status))
+{
+ struct pam_data *data_entry;
+
+ IF_NO_PAMH("pam_set_data",pamh,PAM_SYSTEM_ERR);
+
+ /* first check if there is some data already. If so clean it up */
+
+ if ((data_entry = _pam_locate_data(pamh, module_data_name))) {
+ if (data_entry->cleanup) {
+ data_entry->cleanup(pamh, data_entry->data,
+ PAM_DATA_REPLACE | PAM_SUCCESS );
+ }
+ } else if ((data_entry = malloc(sizeof(*data_entry)))) {
+ char *tname;
+
+ if ((tname = _pam_strdup(module_data_name)) == NULL) {
+ _pam_system_log(LOG_CRIT, "pam_set_data: no memory for data name");
+ _pam_drop(data_entry);
+ return PAM_BUF_ERR;
+ }
+ data_entry->next = pamh->data;
+ pamh->data = data_entry;
+ data_entry->name = tname;
+ } else {
+ _pam_system_log(LOG_CRIT, "pam_set_data: cannot allocate data entry");
+ return PAM_BUF_ERR;
+ }
+
+ data_entry->data = data; /* note this could be NULL */
+ data_entry->cleanup = cleanup;
+
+ return PAM_SUCCESS;
+}
+
+int pam_get_data(
+ const pam_handle_t *pamh,
+ const char *module_data_name,
+ const void **datap)
+{
+ struct pam_data *data;
+
+ IF_NO_PAMH("pam_get_data",pamh,PAM_SYSTEM_ERR);
+
+ data = _pam_locate_data(pamh, module_data_name);
+ if (data) {
+ *datap = data->data;
+ return PAM_SUCCESS;
+ }
+
+ return PAM_NO_MODULE_DATA;
+}
+
+struct pam_data *_pam_locate_data(const pam_handle_t *pamh, const char *name)
+{
+ struct pam_data *data;
+
+ IF_NO_PAMH("_pam_locate_data",pamh,NULL);
+ data = pamh->data;
+
+ while (data) {
+ if (!strcmp(data->name, name)) {
+ return data;
+ }
+ data = data->next;
+ }
+
+ return NULL;
+}
+
+void _pam_free_data(pam_handle_t *pamh, int status)
+{
+ struct pam_data *last;
+ struct pam_data *data;
+
+ IF_NO_PAMH("_pam_free_data",pamh,/* no return value for void fn */);
+ data = pamh->data;
+
+ while (data) {
+ last = data;
+ data = data->next;
+ if (last->cleanup) {
+ last->cleanup(pamh, last->data, status);
+ }
+ _pam_drop(last->name);
+ _pam_drop(last);
+ }
+}
diff --git a/libpam/pam_delay.c b/libpam/pam_delay.c
new file mode 100644
index 00000000..b7c6604d
--- /dev/null
+++ b/libpam/pam_delay.c
@@ -0,0 +1,168 @@
+/*
+ * pam_delay.c
+ *
+ * Copyright (c) Andrew G. Morgan <morgan@linux.kernel.org> 1996-9
+ * All rights reserved.
+ *
+ * $Id$
+ *
+ * $Log$
+ * Revision 1.1 2000/06/20 22:11:14 agmorgan
+ * Initial revision
+ *
+ * Revision 1.2 1999/07/04 23:23:42 morgan
+ * add appdata_ptr to app callback function
+ *
+ * Revision 1.1.1.1 1998/07/12 05:17:15 morgan
+ * Linux PAM sources pre-0.66
+ *
+ */
+
+/*
+ * This is a simple implementation of a delay on failure mechanism; an
+ * attempt to overcome authentication-time attacks in a simple manner.
+ */
+
+#include <unistd.h>
+#include "pam_private.h"
+
+/* **********************************************************************
+ * initialize the time as unset, this is set on the return from the
+ * authenticating pair of of the libpam pam_XXX calls.
+ */
+
+void _pam_reset_timer(pam_handle_t *pamh)
+{
+ D(("setting pamh->fail_delay.set to FALSE"));
+ pamh->fail_delay.set = PAM_FALSE;
+}
+
+/* **********************************************************************
+ * this function sets the start time for possible delayed failing.
+ *
+ * Eventually, it may set the timer so libpam knows how long the program
+ * has already been executing. Currently, this value is used to seed
+ * a pseudo-random number generator...
+ */
+
+void _pam_start_timer(pam_handle_t *pamh)
+{
+ pamh->fail_delay.begin = time(NULL);
+ D(("starting timer..."));
+}
+
+/* *******************************************************************
+ * Compute a pseudo random time. The value is base*(1 +/- 1/5) where
+ * the distribution is pseudo gausian (the sum of three evenly
+ * distributed random numbers -- central limit theorem and all ;^) The
+ * linear random numbers are based on a formulae given in Knuth's
+ * Seminumerical recipies that was reproduced in `Numerical Recipies
+ * in C'. It is *not* a cryptographically strong generator, but it is
+ * probably "good enough" for our purposes here.
+ *
+ * /dev/random might be a better place to look for some numbers...
+ */
+
+static unsigned int _pam_rand(unsigned int seed)
+{
+#define N1 1664525
+#define N2 1013904223
+ return N1*seed + N2;
+}
+
+static unsigned int _pam_compute_delay(unsigned int seed, unsigned int base)
+{
+ int i;
+ double sum;
+ unsigned int ans;
+
+ for (sum=i=0; i<3; ++i) {
+ seed = _pam_rand(seed);
+ sum += (double) ((seed / 10) % 1000000);
+ }
+ sum = (sum/3.)/1e6 - .5; /* rescale */
+ ans = (unsigned int) ( base*(1.+sum) );
+ D(("random number: base=%u -> ans=%u\n", base, ans));
+
+ return ans;
+}
+
+/* **********************************************************************
+ * the following function sleeps for a random time. The actual time
+ * slept is computed above.. It is based on the requested time but will
+ * differ by up to +/- 25%.
+ */
+
+void _pam_await_timer(pam_handle_t *pamh, int status)
+{
+ unsigned int delay;
+ D(("waiting?..."));
+
+ delay = _pam_compute_delay(pamh->fail_delay.begin,
+ pamh->fail_delay.delay);
+ if (pamh->fail_delay.delay_fn_ptr) {
+ union {
+ const void *value;
+ void (*fn)(int, unsigned, void *);
+ } hack_fn_u;
+ void *appdata_ptr;
+
+ if (pamh->pam_conversation) {
+ appdata_ptr = pamh->pam_conversation->appdata_ptr;
+ } else {
+ appdata_ptr = NULL;
+ }
+
+ /* always call the applications delay function, even if
+ the delay is zero - indicate status */
+ hack_fn_u.value = pamh->fail_delay.delay_fn_ptr;
+ hack_fn_u.fn(status, delay, appdata_ptr);
+
+ } else if (status != PAM_SUCCESS && pamh->fail_delay.set) {
+
+ D(("will wait %u usec", delay));
+
+ if (delay > 0) {
+ struct timeval tval;
+
+ tval.tv_sec = delay / 1000000;
+ tval.tv_usec = delay % 1000000;
+ select(0, NULL, NULL, NULL, &tval);
+ }
+ }
+
+ _pam_reset_timer(pamh);
+ D(("waiting done"));
+}
+
+/* **********************************************************************
+ * this function is known to both the module and the application, it
+ * keeps a running score of the largest-requested delay so far, as
+ * specified by either modules or an application.
+ */
+
+int pam_fail_delay(pam_handle_t *pamh, unsigned int usec)
+{
+ int largest;
+
+ IF_NO_PAMH("pam_fail_delay", pamh, PAM_SYSTEM_ERR);
+
+ D(("setting delay to %u",usec));
+
+ if (pamh->fail_delay.set) {
+ largest = pamh->fail_delay.delay;
+ } else {
+ pamh->fail_delay.set = PAM_TRUE;
+ largest = 0;
+ }
+
+ D(("largest = %u",largest));
+
+ if (largest < usec) {
+ D(("resetting largest delay"));
+ pamh->fail_delay.delay = usec;
+ }
+
+ return PAM_SUCCESS;
+}
+
diff --git a/libpam/pam_dispatch.c b/libpam/pam_dispatch.c
new file mode 100644
index 00000000..285f3316
--- /dev/null
+++ b/libpam/pam_dispatch.c
@@ -0,0 +1,282 @@
+/* pam_dispatch.c - handles module function dispatch */
+
+/*
+ * Copyright (c) 1998 Andrew G. Morgan <morgan@linux.kernel.org>
+ *
+ * $Id$
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "pam_private.h"
+
+/*
+ * this is the return code we return when a function pointer is NULL
+ * or, the handler structure indicates a broken module config line
+ */
+#define PAM_MUST_FAIL_CODE PAM_PERM_DENIED
+
+/* impression codes - this gives some sense to the logical choices */
+#define _PAM_UNDEF 0
+#define _PAM_POSITIVE +1
+#define _PAM_NEGATIVE -1
+
+/*
+ * walk a stack of modules. Interpret the administrator's instructions
+ * when combining the return code of each module.
+ */
+
+static int _pam_dispatch_aux(pam_handle_t *pamh, int flags, struct handler *h,
+ _pam_boolean resumed)
+{
+ int depth, impression, status, skip_depth;
+
+ IF_NO_PAMH("_pam_dispatch_aux", pamh, PAM_SYSTEM_ERR);
+
+ if (h == NULL) {
+ const char *service=NULL;
+
+ (void) pam_get_item(pamh, PAM_SERVICE, (const void **)&service);
+ _pam_system_log(LOG_ERR, "no modules loaded for `%s' service",
+ service ? service:"<unknown>" );
+ service = NULL;
+ return PAM_MUST_FAIL_CODE;
+ }
+
+ /* if we are recalling this module stack because a former call did
+ not complete, we restore the state of play from pamh. */
+ if (resumed) {
+ skip_depth = pamh->former.depth;
+ status = pamh->former.status;
+ impression = pamh->former.impression;
+ /* forget all that */
+ pamh->former.impression = _PAM_UNDEF;
+ pamh->former.status = PAM_MUST_FAIL_CODE;
+ pamh->former.depth = 0;
+ } else {
+ skip_depth = 0;
+ impression = _PAM_UNDEF;
+ status = PAM_MUST_FAIL_CODE;
+ }
+
+ /* Loop through module logic stack */
+ for (depth=0 ; h != NULL ; h = h->next, ++depth) {
+ int retval, action;
+
+ /* skip leading modules if they have already returned */
+ if (depth < skip_depth) {
+ continue;
+ }
+
+ /* attempt to call the module */
+ if (h->func == NULL) {
+ D(("module function is not defined, indicating failure"));
+ retval = PAM_MODULE_UNKNOWN;
+ } else {
+ D(("passing control to module..."));
+ retval = h->func(pamh, flags, h->argc, h->argv);
+ D(("module returned: %s", pam_strerror(pamh, retval)));
+ if (h->must_fail) {
+ D(("module poorly listed in pam.conf; forcing failure"));
+ retval = PAM_MUST_FAIL_CODE;
+ }
+ }
+
+ /*
+ * PAM_INCOMPLETE return is special. It indicates that the
+ * module wants to wait for the application before continuing.
+ * In order to return this, the module will have saved its
+ * state so it can resume from an equivalent position when it
+ * is called next time. (This was added as of 0.65)
+ */
+ if (retval == PAM_INCOMPLETE) {
+ pamh->former.impression = impression;
+ pamh->former.status = status;
+ pamh->former.depth = depth;
+
+ D(("module %d returned PAM_INCOMPLETE", depth));
+ return retval;
+ }
+
+ /* verify that the return value is a valid one */
+ if (retval < PAM_SUCCESS || retval >= _PAM_RETURN_VALUES) {
+ retval = PAM_MUST_FAIL_CODE;
+ action = _PAM_ACTION_BAD;
+ } else {
+ action = h->actions[retval];
+ }
+
+ /* decide what to do */
+ switch (action) {
+ case _PAM_ACTION_RESET:
+ impression = _PAM_UNDEF;
+ status = PAM_MUST_FAIL_CODE;
+ break;
+
+ case _PAM_ACTION_OK:
+ case _PAM_ACTION_DONE:
+ if ( impression == _PAM_UNDEF
+ || (impression == _PAM_POSITIVE && status == PAM_SUCCESS) ) {
+ impression = _PAM_POSITIVE;
+ status = retval;
+ }
+ if ( impression == _PAM_POSITIVE && action == _PAM_ACTION_DONE ) {
+ goto decision_made;
+ }
+ break;
+
+ case _PAM_ACTION_BAD:
+ case _PAM_ACTION_DIE:
+#ifdef PAM_FAIL_NOW_ON
+ if ( retval == PAM_ABORT ) {
+ impression = _PAM_NEGATIVE;
+ status = PAM_PERM_DENIED;
+ goto decision_made;
+ }
+#endif /* PAM_FAIL_NOW_ON */
+ if ( impression != _PAM_NEGATIVE ) {
+ impression = _PAM_NEGATIVE;
+ status = retval;
+ }
+ if ( action == _PAM_ACTION_DIE ) {
+ goto decision_made;
+ }
+ break;
+
+ case _PAM_ACTION_IGNORE:
+ break;
+
+ /* if we get here, we expect action is a positive number --
+ this is what the ...JUMP macro checks. */
+
+ default:
+ if ( _PAM_ACTION_IS_JUMP(action) ) {
+ /* this means that we need to skip #action stacked modules */
+ do {
+ h = h->next;
+ } while ( --action > 0 && h != NULL );
+
+ /* note if we try to skip too many modules action is
+ still non-zero and we snag the next if. */
+ }
+
+ /* this case is a syntax error: we can't succeed */
+ if (action) {
+ D(("action syntax error"));
+ impression = _PAM_NEGATIVE;
+ status = PAM_MUST_FAIL_CODE;
+ }
+ }
+ }
+
+decision_made: /* by getting here we have made a decision */
+
+ /* Sanity check */
+ if ( status == PAM_SUCCESS && impression != _PAM_POSITIVE ) {
+ D(("caught on sanity check -- this is probably a config error!"));
+ status = PAM_MUST_FAIL_CODE;
+ }
+
+ /* We have made a decision about the modules executed */
+ return status;
+}
+
+/*
+ * This function translates the module dispatch request into a pointer
+ * to the stack of modules that will actually be run. the
+ * _pam_dispatch_aux() function (above) is responsible for walking the
+ * module stack.
+ */
+
+int _pam_dispatch(pam_handle_t *pamh, int flags, int choice)
+{
+ struct handler *h = NULL;
+ int retval;
+ _pam_boolean resumed;
+
+ IF_NO_PAMH("_pam_dispatch",pamh,PAM_SYSTEM_ERR);
+
+ /* Load all modules, resolve all symbols */
+
+ if ((retval = _pam_init_handlers(pamh)) != PAM_SUCCESS) {
+ _pam_system_log(LOG_ERR, "unable to dispatch function");
+ return retval;
+ }
+
+ switch (choice) {
+ case PAM_AUTHENTICATE:
+ h = pamh->handlers.conf.authenticate;
+ break;
+ case PAM_SETCRED:
+ h = pamh->handlers.conf.setcred;
+ break;
+ case PAM_ACCOUNT:
+ h = pamh->handlers.conf.acct_mgmt;
+ break;
+ case PAM_OPEN_SESSION:
+ h = pamh->handlers.conf.open_session;
+ break;
+ case PAM_CLOSE_SESSION:
+ h = pamh->handlers.conf.close_session;
+ break;
+ case PAM_CHAUTHTOK:
+ h = pamh->handlers.conf.chauthtok;
+ break;
+ default:
+ _pam_system_log(LOG_ERR, "undefined fn choice; %d", choice);
+ return PAM_ABORT;
+ }
+
+ if (h == NULL) { /* there was no handlers.conf... entry; will use
+ * handlers.other... */
+ switch (choice) {
+ case PAM_AUTHENTICATE:
+ h = pamh->handlers.other.authenticate;
+ break;
+ case PAM_SETCRED:
+ h = pamh->handlers.other.setcred;
+ break;
+ case PAM_ACCOUNT:
+ h = pamh->handlers.other.acct_mgmt;
+ break;
+ case PAM_OPEN_SESSION:
+ h = pamh->handlers.other.open_session;
+ break;
+ case PAM_CLOSE_SESSION:
+ h = pamh->handlers.other.close_session;
+ break;
+ case PAM_CHAUTHTOK:
+ h = pamh->handlers.other.chauthtok;
+ break;
+ }
+ }
+
+ /* Did a module return an "incomplete state" last time? */
+ if (pamh->former.choice != PAM_NOT_STACKED) {
+ if (pamh->former.choice != choice) {
+ _pam_system_log(LOG_ERR,
+ "application failed to re-exec stack [%d:%d]",
+ pamh->former.choice, choice);
+ return PAM_ABORT;
+ }
+ resumed = PAM_TRUE;
+ } else {
+ resumed = PAM_FALSE;
+ }
+
+ /* call the list of module functions */
+ retval = _pam_dispatch_aux(pamh, flags, h, resumed);
+ resumed = PAM_FALSE;
+
+ /* Should we recall where to resume next time? */
+ if (retval == PAM_INCOMPLETE) {
+ D(("module [%d] returned PAM_INCOMPLETE"));
+ pamh->former.choice = choice;
+ } else {
+ pamh->former.choice = PAM_NOT_STACKED;
+ }
+
+ return retval;
+}
+
diff --git a/libpam/pam_end.c b/libpam/pam_end.c
new file mode 100644
index 00000000..b389038f
--- /dev/null
+++ b/libpam/pam_end.c
@@ -0,0 +1,72 @@
+/* pam_end.c */
+
+/*
+ * $Id$
+ */
+
+#include <stdlib.h>
+
+#include "pam_private.h"
+
+int pam_end(pam_handle_t *pamh, int pam_status)
+{
+ int ret;
+
+ IF_NO_PAMH("pam_end", pamh, PAM_SYSTEM_ERR);
+
+ D(("entering pam_end()"));
+
+ /* first liberate the modules (it is not inconcevible that the
+ modules may need to use the service_name etc. to clean up) */
+
+ _pam_free_data(pamh, pam_status);
+
+ /* now drop all modules */
+
+ if ((ret = _pam_free_handlers(pamh)) != PAM_SUCCESS) {
+ return ret; /* error occurred */
+ }
+
+ /* from this point we cannot call the modules any more. Free the remaining
+ memory used by the Linux-PAM interface */
+
+ _pam_drop_env(pamh); /* purge the environment */
+
+ _pam_overwrite(pamh->authtok); /* blank out old token */
+ _pam_drop(pamh->authtok);
+
+ _pam_overwrite(pamh->oldauthtok); /* blank out old token */
+ _pam_drop(pamh->oldauthtok);
+
+ _pam_overwrite(pamh->former.prompt);
+ _pam_drop(pamh->former.prompt); /* drop saved prompt */
+
+ _pam_overwrite(pamh->service_name);
+ _pam_drop(pamh->service_name);
+
+ _pam_overwrite(pamh->user);
+ _pam_drop(pamh->user);
+
+ _pam_overwrite(pamh->prompt);
+ _pam_drop(pamh->prompt); /* prompt for pam_get_user() */
+
+ _pam_overwrite(pamh->tty);
+ _pam_drop(pamh->tty);
+
+ _pam_overwrite(pamh->rhost);
+ _pam_drop(pamh->rhost);
+
+ _pam_overwrite(pamh->ruser);
+ _pam_drop(pamh->ruser);
+
+ _pam_drop(pamh->pam_conversation);
+ pamh->fail_delay.delay_fn_ptr = NULL;
+
+ /* and finally liberate the memory for the pam_handle structure */
+
+ _pam_drop(pamh);
+
+ D(("exiting pam_end() successfully"));
+
+ return PAM_SUCCESS;
+}
diff --git a/libpam/pam_env.c b/libpam/pam_env.c
new file mode 100644
index 00000000..a1e744b7
--- /dev/null
+++ b/libpam/pam_env.c
@@ -0,0 +1,389 @@
+/*
+ * pam_env.c
+ *
+ * Copyright (c) Andrew G. Morgan <morgan@parc.power.net> 1996,1997
+ * All rights reserved.
+ *
+ * This file was written from a "hint" provided by the people at SUN.
+ * and the X/Open XSSO draft of March 1997.
+ *
+ * $Id$
+ */
+
+#include <string.h>
+#include <stdlib.h>
+#ifdef sunos
+#define memmove(x,y,z) bcopy(y,x,z)
+#endif
+
+#include "pam_private.h"
+
+/* helper functions */
+
+#ifdef DEBUG
+static void _pam_dump_env(pam_handle_t *pamh)
+{
+ int i;
+
+ D(("Listing environment of pamh=%p", pamh));
+ D(("pamh->env = %p", pamh->env));
+ D(("environment entries used = %d [of %d allocated]"
+ , pamh->env->requested, pamh->env->entries));
+
+ for (i=0; i<pamh->env->requested; ++i) {
+ _pam_output_debug(">%-3d [%9p]:[%s]"
+ , i, pamh->env->list[i], pamh->env->list[i]);
+ }
+ _pam_output_debug("*NOTE* the last item should be (nil)");
+}
+#else
+#define _pam_dump_env(x)
+#endif
+
+/*
+ * Create the environment
+ */
+
+int _pam_make_env(pam_handle_t *pamh)
+{
+ D(("called."));
+ IF_NO_PAMH("_pam_make_env", pamh, PAM_ABORT);
+
+ /*
+ * get structure memory
+ */
+
+ pamh->env = (struct pam_environ *) malloc(sizeof(struct pam_environ));
+ if (pamh->env == NULL) {
+ _pam_system_log(LOG_CRIT, "_pam_make_env: out of memory");
+ return PAM_BUF_ERR;
+ }
+
+ /*
+ * get list memory
+ */
+
+ pamh->env->list = (char **)calloc( PAM_ENV_CHUNK, sizeof(char *) );
+ if (pamh->env->list == NULL) {
+ _pam_system_log(LOG_CRIT, "_pam_make_env: no memory for list");
+ _pam_drop(pamh->env);
+ return PAM_BUF_ERR;
+ }
+
+ /*
+ * fill entries in pamh->env
+ */
+
+ pamh->env->entries = PAM_ENV_CHUNK;
+ pamh->env->requested = 1;
+ pamh->env->list[0] = NULL;
+
+ _pam_dump_env(pamh); /* only active when debugging */
+
+ return PAM_SUCCESS;
+}
+
+/*
+ * purge the environment
+ */
+
+void _pam_drop_env(pam_handle_t *pamh)
+{
+ D(("called."));
+ IF_NO_PAMH("_pam_make_env", pamh, /* nothing to return */);
+
+ if (pamh->env != NULL) {
+ int i;
+ /* we will only purge the pamh->env->requested number of elements */
+
+ for (i=pamh->env->requested-1; i-- > 0; ) {
+ D(("dropping #%3d>%s<", i, pamh->env->list[i]));
+ _pam_overwrite(pamh->env->list[i]); /* clean */
+ _pam_drop(pamh->env->list[i]); /* forget */
+ }
+ pamh->env->requested = 0;
+ pamh->env->entries = 0;
+ _pam_drop(pamh->env->list); /* forget */
+ _pam_drop(pamh->env); /* forget */
+ } else {
+ D(("no environment present in pamh?"));
+ }
+}
+
+/*
+ * Return the item number of the given variable = first 'length' chars
+ * of 'name_value'. Since this is a static function, it is safe to
+ * assume its supplied arguments are well defined.
+ */
+
+static int _pam_search_env(const struct pam_environ *env
+ , const char *name_value, int length)
+{
+ int i;
+
+ for (i=env->requested-1; i-- > 0; ) {
+ if (strncmp(name_value,env->list[i],length) == 0
+ && env->list[i][length] == '=') {
+
+ return i; /* Got it! */
+
+ }
+ }
+
+ return -1; /* no luck */
+}
+
+/*
+ * externally visible functions
+ */
+
+/*
+ * pam_putenv(): Add/replace/delete a PAM-environment variable.
+ *
+ * Add/replace:
+ * name_value = "NAME=VALUE" or "NAME=" (for empty value="\0")
+ *
+ * delete:
+ * name_value = "NAME"
+ */
+
+int pam_putenv(pam_handle_t *pamh, const char *name_value)
+{
+ int l2eq, item, retval;
+
+ D(("called."));
+ IF_NO_PAMH("pam_putenv", pamh, PAM_ABORT);
+
+ if (name_value == NULL) {
+ _pam_system_log(LOG_ERR, "pam_putenv: no variable indicated");
+ return PAM_PERM_DENIED;
+ }
+
+ /*
+ * establish if we are setting or deleting; scan for '='
+ */
+
+ for (l2eq=0; name_value[l2eq] && name_value[l2eq] != '='; ++l2eq);
+ if (l2eq <= 0) {
+ _pam_system_log(LOG_ERR, "pam_putenv: bad variable");
+ return PAM_BAD_ITEM;
+ }
+
+ /*
+ * Look first for environment.
+ */
+
+ if (pamh->env == NULL || pamh->env->list == NULL) {
+ _pam_system_log(LOG_ERR, "pam_putenv: no env%s found",
+ pamh->env == NULL ? "":"-list");
+ return PAM_ABORT;
+ }
+
+ /* find the item to replace */
+
+ item = _pam_search_env(pamh->env, name_value, l2eq);
+
+ if (name_value[l2eq]) { /* (re)setting */
+
+ if (item == -1) { /* new variable */
+ D(("adding item: %s", name_value));
+ /* enough space? */
+ if (pamh->env->entries <= pamh->env->requested) {
+ register int i;
+ register char **tmp;
+
+ /* get some new space */
+ tmp = calloc( pamh->env->entries + PAM_ENV_CHUNK
+ , sizeof(char *) );
+ if (tmp == NULL) {
+ /* nothing has changed - old env intact */
+ _pam_system_log(LOG_CRIT,
+ "pam_putenv: cannot grow environment");
+ return PAM_BUF_ERR;
+ }
+
+ /* copy old env-item pointers/forget old */
+ for (i=0; i<pamh->env->requested; ++i) {
+ tmp[i] = pamh->env->list[i];
+ pamh->env->list[i] = NULL;
+ }
+
+ /* drop old list and replace with new */
+ _pam_drop(pamh->env->list);
+ pamh->env->list = tmp;
+ pamh->env->entries += PAM_ENV_CHUNK;
+
+ D(("resized env list"));
+ _pam_dump_env(pamh); /* only when debugging */
+ }
+
+ item = pamh->env->requested-1; /* old last item (NULL) */
+
+ /* add a new NULL entry at end; increase counter */
+ pamh->env->list[pamh->env->requested++] = NULL;
+
+ } else { /* replace old */
+ D(("replacing item: %s\n with: %s"
+ , pamh->env->list[item], name_value));
+ _pam_overwrite(pamh->env->list[item]);
+ _pam_drop(pamh->env->list[item]);
+ }
+
+ /*
+ * now we have a place to put the new env-item, insert at 'item'
+ */
+
+ pamh->env->list[item] = _pam_strdup(name_value);
+ if (pamh->env->list[item] != NULL) {
+ _pam_dump_env(pamh); /* only when debugging */
+ return PAM_SUCCESS;
+ }
+
+ /* something went wrong; we should delete the item - fall through */
+
+ retval = PAM_BUF_ERR; /* an error occurred */
+ } else {
+ retval = PAM_SUCCESS; /* we requested delete */
+ }
+
+ /* getting to here implies we are deleting an item */
+
+ if (item < 0) {
+ _pam_system_log(LOG_ERR, "pam_putenv: delete non-existent entry; %s",
+ name_value);
+ return PAM_BAD_ITEM;
+ }
+
+ /*
+ * remove item: purge memory; reset counter; resize [; display-env]
+ */
+
+ D(("deleting: env#%3d:[%s]", item, pamh->env->list[item]));
+ _pam_overwrite(pamh->env->list[item]);
+ _pam_drop(pamh->env->list[item]);
+ --(pamh->env->requested);
+ D(("mmove: item[%d]+%d -> item[%d]"
+ , item+1, ( pamh->env->requested - item ), item));
+ (void) memmove(&pamh->env->list[item], &pamh->env->list[item+1]
+ , ( pamh->env->requested - item )*sizeof(char *) );
+
+ _pam_dump_env(pamh); /* only when debugging */
+
+ /*
+ * deleted.
+ */
+
+ return retval;
+}
+
+/*
+ * Return the value of the requested environment variable
+ */
+
+const char *pam_getenv(pam_handle_t *pamh, const char *name)
+{
+ int item;
+
+ D(("called."));
+ IF_NO_PAMH("pam_getenv", pamh, NULL);
+
+ if (name == NULL) {
+ _pam_system_log(LOG_ERR, "pam_getenv: no variable indicated");
+ return NULL;
+ }
+
+ if (pamh->env == NULL || pamh->env->list == NULL) {
+ _pam_system_log(LOG_ERR, "pam_getenv: no env%s found",
+ pamh->env == NULL ? "":"-list" );
+ return NULL;
+ }
+
+ /* find the requested item */
+
+ item = _pam_search_env(pamh->env, name, strlen(name));
+ if (item != -1) {
+
+ D(("env-item: %s, found!", name));
+ return (pamh->env->list[item] + 1 + strlen(name));
+
+ } else {
+
+ D(("env-item: %s, not found", name));
+ return NULL;
+
+ }
+}
+
+static char **_copy_env(pam_handle_t *pamh)
+{
+ char **dump;
+ int i = pamh->env->requested; /* reckon size of environment */
+ char *const *env = pamh->env->list;
+
+ D(("now get some memory for dump"));
+
+ /* allocate some memory for this (plus the null tail-pointer) */
+ dump = (char **) calloc(i, sizeof(char *));
+ D(("dump = %p", dump));
+ if (dump == NULL) {
+ return NULL;
+ }
+
+ /* now run through entries and copy the variables over */
+ dump[--i] = NULL;
+ while (i-- > 0) {
+ D(("env[%d]=`%s'", i,env[i]));
+ dump[i] = _pam_strdup(env[i]);
+ D(("->dump[%d]=`%s'", i,dump[i]));
+ if (dump[i] == NULL) {
+ /* out of memory */
+
+ while (dump[++i]) {
+ _pam_overwrite(dump[i]);
+ _pam_drop(dump[i]);
+ }
+ return NULL;
+ }
+ }
+
+ env = NULL; /* forget now */
+
+ /* return transcribed environment */
+ return dump;
+}
+
+char **pam_getenvlist(pam_handle_t *pamh)
+{
+ int i;
+
+ D(("called."));
+ IF_NO_PAMH("pam_getenvlist", pamh, NULL);
+
+ if (pamh->env == NULL || pamh->env->list == NULL) {
+ _pam_system_log(LOG_ERR, "pam_getenvlist: no env%s found",
+ pamh->env == NULL ? "":"-list" );
+ return NULL;
+ }
+
+ /* some quick checks */
+
+ if (pamh->env->requested > pamh->env->entries) {
+ _pam_system_log(LOG_ERR, "pam_getenvlist: environment corruption");
+ _pam_dump_env(pamh); /* only active when debugging */
+ return NULL;
+ }
+
+ for (i=pamh->env->requested-1; i-- > 0; ) {
+ if (pamh->env->list[i] == NULL) {
+ _pam_system_log(LOG_ERR, "pam_getenvlist: environment broken");
+ _pam_dump_env(pamh); /* only active when debugging */
+ return NULL; /* somehow we've broken the environment!? */
+ }
+ }
+
+ /* Seems fine; copy environment */
+
+ _pam_dump_env(pamh); /* only active when debugging */
+
+ return _copy_env(pamh);
+}
diff --git a/libpam/pam_handlers.c b/libpam/pam_handlers.c
new file mode 100644
index 00000000..569335e6
--- /dev/null
+++ b/libpam/pam_handlers.c
@@ -0,0 +1,896 @@
+/* pam_handlers.c -- pam config file parsing and module loading */
+
+/*
+ * created by Marc Ewing.
+ * Currently maintained by Andrew G. Morgan <morgan@linux.kernel.org>
+ *
+ * $Id$
+ *
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#ifdef PAM_DYNAMIC
+# ifdef PAM_SHL
+# include <dl.h>
+# else /* PAM_SHL */
+# include <dlfcn.h>
+# endif /* PAM_SHL */
+#endif /* PAM_DYNAMIC */
+#include <fcntl.h>
+#include <unistd.h>
+
+#include "pam_private.h"
+
+/* FreeBSD doesn't define this */
+#ifndef RTLD_NOW
+# define RTLD_NOW 1
+#endif
+
+/* If not required, define as nothing - FreeBSD needs it to be "_"... */
+#ifndef SHLIB_SYM_PREFIX
+# define SHLIB_SYM_PREFIX ""
+#endif
+
+#define BUF_SIZE 1024
+#define MODULE_CHUNK 4
+#define UNKNOWN_MODULE_PATH "<*unknown module path*>"
+
+static int _pam_assemble_line(FILE *f, char *buf, int buf_len);
+
+static void _pam_free_handlers_aux(struct handler **hp);
+
+static int _pam_add_handler(pam_handle_t *pamh
+ , int must_fail, int other, int type
+ , int *actions, const char *mod_path
+ , int argc, char **argv, int argvlen);
+
+/* Values for module type */
+
+#define PAM_T_AUTH 1
+#define PAM_T_SESS 2
+#define PAM_T_ACCT 4
+#define PAM_T_PASS 8
+
+static int _pam_parse_conf_file(pam_handle_t *pamh, FILE *f
+ , const char *known_service /* specific file */
+#ifdef PAM_READ_BOTH_CONFS
+ , int not_other
+#endif /* PAM_READ_BOTH_CONFS */
+ )
+{
+ char buf[BUF_SIZE];
+ int x; /* read a line from the FILE *f ? */
+ /*
+ * read a line from the configuration (FILE *) f
+ */
+ while ((x = _pam_assemble_line(f, buf, BUF_SIZE)) > 0) {
+ char *tok, *nexttok=NULL;
+ const char *this_service;
+ const char *mod_path;
+ int module_type, actions[_PAM_RETURN_VALUES];
+ int other; /* set if module is for PAM_DEFAULT_SERVICE */
+ int res; /* module added successfully? */
+ int must_fail=0; /* a badly formatted line must fail when used */
+ int argc;
+ char **argv;
+ int argvlen;
+
+ D(("_pam_init_handler: LINE: %s", buf));
+ if (known_service != NULL) {
+ nexttok = buf;
+ /* No service field: all lines are for the known service. */
+ this_service = known_service;
+ } else {
+ this_service = tok = _pam_StrTok(buf, " \n\t", &nexttok);
+ }
+
+#ifdef PAM_READ_BOTH_CONFS
+ if (not_other)
+ other = 0;
+ else
+#endif /* PAM_READ_BOTH_CONFS */
+ other = !_pam_strCMP(this_service, PAM_DEFAULT_SERVICE);
+
+ /* accept "service name" or PAM_DEFAULT_SERVICE modules */
+ if (!_pam_strCMP(this_service, pamh->service_name) || other) {
+ /* This is a service we are looking for */
+ D(("_pam_init_handlers: Found PAM config entry for: %s"
+ , this_service));
+
+ tok = _pam_StrTok(NULL, " \n\t", &nexttok);
+ if (!_pam_strCMP("auth", tok)) {
+ module_type = PAM_T_AUTH;
+ } else if (!_pam_strCMP("session", tok)) {
+ module_type = PAM_T_SESS;
+ } else if (!_pam_strCMP("account", tok)) {
+ module_type = PAM_T_ACCT;
+ } else if (!_pam_strCMP("password", tok)) {
+ module_type = PAM_T_PASS;
+ } else {
+ /* Illegal module type */
+ D(("_pam_init_handlers: bad module type: %s", tok));
+ _pam_system_log(LOG_ERR, "(%s) illegal module type: %s",
+ this_service, tok);
+ module_type = PAM_T_AUTH; /* most sensitive */
+ must_fail = 1; /* install as normal but fail when dispatched */
+ }
+ D(("Using %s config entry: %s", must_fail?"BAD ":"", tok));
+
+ /* reset the actions to .._UNDEF's -- this is so that
+ we can work out which entries are not yet set (for default). */
+ {
+ int i;
+ for (i=0; i<_PAM_RETURN_VALUES;
+ actions[i++] = _PAM_ACTION_UNDEF);
+ }
+ tok = _pam_StrTok(NULL, " \n\t", &nexttok);
+ if (!_pam_strCMP("required", tok)) {
+ D(("*PAM_F_REQUIRED*"));
+ actions[PAM_SUCCESS] = _PAM_ACTION_OK;
+ actions[PAM_NEW_AUTHTOK_REQD] = _PAM_ACTION_OK;
+ actions[PAM_IGNORE] = _PAM_ACTION_IGNORE;
+ _pam_set_default_control(actions, _PAM_ACTION_BAD);
+ } else if (!_pam_strCMP("requisite", tok)) {
+ D(("*PAM_F_REQUISITE*"));
+ actions[PAM_SUCCESS] = _PAM_ACTION_OK;
+ actions[PAM_NEW_AUTHTOK_REQD] = _PAM_ACTION_OK;
+ actions[PAM_IGNORE] = _PAM_ACTION_IGNORE;
+ _pam_set_default_control(actions, _PAM_ACTION_DIE);
+ } else if (!_pam_strCMP("optional", tok)) {
+ D(("*PAM_F_OPTIONAL*"));
+ actions[PAM_SUCCESS] = _PAM_ACTION_OK;
+ actions[PAM_NEW_AUTHTOK_REQD] = _PAM_ACTION_OK;
+ _pam_set_default_control(actions, _PAM_ACTION_IGNORE);
+ } else if (!_pam_strCMP("sufficient", tok)) {
+ D(("*PAM_F_SUFFICIENT*"));
+ actions[PAM_SUCCESS] = _PAM_ACTION_DONE;
+ actions[PAM_NEW_AUTHTOK_REQD] = _PAM_ACTION_DONE;
+ _pam_set_default_control(actions, _PAM_ACTION_IGNORE);
+ } else {
+ D(("will need to parse %s", tok));
+ _pam_parse_control(actions, tok);
+ /* by default the default is to treat as failure */
+ _pam_set_default_control(actions, _PAM_ACTION_BAD);
+ }
+
+ tok = _pam_StrTok(NULL, " \n\t", &nexttok);
+ if (tok != NULL) {
+ mod_path = tok;
+ D(("mod_path = %s",mod_path));
+ } else {
+ /* no module name given */
+ D(("_pam_init_handlers: no module name supplied"));
+ _pam_system_log(LOG_ERR,
+ "(%s) no module name supplied", this_service);
+ mod_path = NULL;
+ must_fail = 1;
+ }
+
+ /* nexttok points to remaining arguments... */
+
+ if (nexttok != NULL) {
+ D(("list: %s",nexttok));
+ argvlen = _pam_mkargv(nexttok, &argv, &argc);
+ D(("argvlen = %d",argvlen));
+ } else { /* there are no arguments so fix by hand */
+ D(("_pam_init_handlers: empty argument list"));
+ argvlen = argc = 0;
+ argv = NULL;
+ }
+
+#ifdef DEBUG
+ {
+ int y;
+
+ D(("CONF%s: %s%s %d %s %d"
+ , must_fail?"<*will fail*>":""
+ , this_service, other ? "(backup)":""
+ , module_type
+ , mod_path, argc));
+ for (y = 0; y < argc; y++) {
+ D(("CONF: %s", argv[y]));
+ }
+ for (y = 0; y<_PAM_RETURN_VALUES; ++y) {
+ D(("RETURN %s(%d) -> %d %s",
+ _pam_token_returns[y], y, actions[y],
+ actions[y]>0 ? "jump":
+ _pam_token_actions[-actions[y]]));
+ }
+ }
+#endif
+
+ res = _pam_add_handler(pamh, must_fail, other
+ , module_type, actions, mod_path
+ , argc, argv, argvlen);
+ if (res != PAM_SUCCESS) {
+ _pam_system_log(LOG_ERR, "error loading %s", mod_path);
+ D(("failed to load module - aborting"));
+ return PAM_ABORT;
+ }
+ }
+ }
+
+ return ( (x < 0) ? PAM_ABORT:PAM_SUCCESS );
+}
+
+/* Parse config file, allocate handler structures, dlopen() */
+int _pam_init_handlers(pam_handle_t *pamh)
+{
+ FILE *f;
+ int retval;
+
+ D(("_pam_init_handlers called"));
+ IF_NO_PAMH("_pam_init_handlers",pamh,PAM_SYSTEM_ERR);
+
+ /* Return immediately if everything is already loaded */
+ if (pamh->handlers.handlers_loaded) {
+ return PAM_SUCCESS;
+ }
+
+ D(("_pam_init_handlers: initializing"));
+
+ /* First clean the service structure */
+
+ _pam_free_handlers(pamh);
+ if (! pamh->handlers.module) {
+ if ((pamh->handlers.module =
+ malloc(MODULE_CHUNK * sizeof(struct loaded_module))) == NULL) {
+ _pam_system_log(LOG_CRIT,
+ "_pam_init_handlers: no memory loading module");
+ return PAM_BUF_ERR;
+ }
+ pamh->handlers.modules_allocated = MODULE_CHUNK;
+ pamh->handlers.modules_used = 0;
+ }
+
+ if (pamh->service_name == NULL) {
+ return PAM_BAD_ITEM; /* XXX - better error? */
+ }
+
+#ifdef PAM_LOCKING
+ /* Is the PAM subsystem locked? */
+ {
+ int fd_tmp;
+
+ if ((fd_tmp = open( PAM_LOCK_FILE, O_RDONLY )) != -1) {
+ _pam_system_log(LOG_ERR, "_pam_init_handlers: PAM lockfile ("
+ PAM_LOCK_FILE ") exists - aborting");
+ (void) close(fd_tmp);
+ /*
+ * to avoid swamping the system with requests
+ */
+ _pam_start_timer(pamh);
+ pam_fail_delay(pamh, 5000000);
+ _pam_await_timer(pamh, PAM_ABORT);
+
+ return PAM_ABORT;
+ }
+ }
+#endif /* PAM_LOCKING */
+
+ /*
+ * Now parse the config file(s) and add handlers
+ */
+ {
+ struct stat test_d;
+
+ /* Is there a PAM_CONFIG_D directory? */
+ if ( stat(PAM_CONFIG_D, &test_d) == 0 && S_ISDIR(test_d.st_mode) ) {
+ char *filename;
+ int read_something=0;
+
+ D(("searching " PAM_CONFIG_D " for config files"));
+ filename = malloc(sizeof(PAM_CONFIG_DF)
+ +strlen(pamh->service_name));
+ if (filename == NULL) {
+ _pam_system_log(LOG_ERR,
+ "_pam_init_handlers: no memory; service %s",
+ pamh->service_name);
+ return PAM_BUF_ERR;
+ }
+ sprintf(filename, PAM_CONFIG_DF, pamh->service_name);
+ D(("opening %s", filename));
+ f = fopen(filename, "r");
+ if (f != NULL) {
+ /* would test magic here? */
+ retval = _pam_parse_conf_file(pamh, f, pamh->service_name
+#ifdef PAM_READ_BOTH_CONFS
+ , 0
+#endif /* PAM_READ_BOTH_CONFS */
+ );
+ fclose(f);
+ if (retval != PAM_SUCCESS) {
+ _pam_system_log(LOG_ERR,
+ "_pam_init_handlers: error reading %s",
+ filename);
+ _pam_system_log(LOG_ERR, "_pam_init_handlers: [%s]",
+ pam_strerror(pamh, retval));
+ } else {
+ read_something = 1;
+ }
+ } else {
+ D(("unable to open %s", filename));
+#ifdef PAM_READ_BOTH_CONFS
+ D(("checking %s", PAM_CONFIG));
+
+ if ((f = fopen(PAM_CONFIG,"r")) != NULL) {
+ retval = _pam_parse_conf_file(pamh, f, NULL, 1);
+ fclose(f);
+ } else
+#endif /* PAM_READ_BOTH_CONFS */
+ retval = PAM_SUCCESS;
+ /*
+ * XXX - should we log an error? Some people want to always
+ * use "other"
+ */
+ }
+ _pam_drop(filename);
+
+ if (retval == PAM_SUCCESS) {
+ /* now parse the PAM_DEFAULT_SERVICE_FILE */
+
+ D(("opening %s", PAM_DEFAULT_SERVICE_FILE));
+ f = fopen(PAM_DEFAULT_SERVICE_FILE, "r");
+ if (f != NULL) {
+ /* would test magic here? */
+ retval = _pam_parse_conf_file(pamh, f
+ , PAM_DEFAULT_SERVICE
+#ifdef PAM_READ_BOTH_CONFS
+ , 0
+#endif /* PAM_READ_BOTH_CONFS */
+ );
+ fclose(f);
+ if (retval != PAM_SUCCESS) {
+ _pam_system_log(LOG_ERR,
+ "_pam_init_handlers: error reading %s",
+ PAM_DEFAULT_SERVICE_FILE);
+ _pam_system_log(LOG_ERR,
+ "_pam_init_handlers: [%s]",
+ pam_strerror(pamh, retval));
+ } else {
+ read_something = 1;
+ }
+ } else {
+ D(("unable to open %s", PAM_DEFAULT_SERVICE_FILE));
+ _pam_system_log(LOG_ERR,
+ "_pam_init_handlers: no default config %s",
+ PAM_DEFAULT_SERVICE_FILE);
+ }
+ if (!read_something) { /* nothing read successfully */
+ retval = PAM_ABORT;
+ }
+ }
+ } else {
+ if ((f = fopen(PAM_CONFIG, "r")) == NULL) {
+ _pam_system_log(LOG_ERR, "_pam_init_handlers: could not open "
+ PAM_CONFIG );
+ return PAM_ABORT;
+ }
+
+ retval = _pam_parse_conf_file(pamh, f, NULL
+#ifdef PAM_READ_BOTH_CONFS
+ , 0
+#endif /* PAM_READ_BOTH_CONFS */
+ );
+
+ D(("closing configuration file"));
+ fclose(f);
+ }
+ }
+
+ if (retval != PAM_SUCCESS) {
+ /* Read error */
+ _pam_system_log(LOG_ERR, "error reading PAM configuration file");
+ return PAM_ABORT;
+ }
+
+ pamh->handlers.handlers_loaded = 1;
+
+ D(("_pam_init_handlers exiting"));
+ return PAM_SUCCESS;
+}
+
+/*
+ * This is where we read a line of the PAM config file. The line may be
+ * preceeded by lines of comments and also extended with "\\\n"
+ */
+
+int _pam_assemble_line(FILE *f, char *buffer, int buf_len)
+{
+ char *p = buffer;
+ char *s, *os;
+ int used = 0;
+
+ /* loop broken with a 'break' when a non-'\\n' ended line is read */
+
+ D(("called."));
+ for (;;) {
+ if (used >= buf_len) {
+ /* Overflow */
+ D(("_pam_assemble_line: overflow"));
+ return -1;
+ }
+ if (fgets(p, buf_len - used, f) == NULL) {
+ if (used) {
+ /* Incomplete read */
+ return -1;
+ } else {
+ /* EOF */
+ return 0;
+ }
+ }
+
+ /* skip leading spaces --- line may be blank */
+
+ s = p + strspn(p, " \n\t");
+ if (*s && (*s != '#')) {
+ os = s;
+
+ /*
+ * we are only interested in characters before the first '#'
+ * character
+ */
+
+ while (*s && *s != '#')
+ ++s;
+ if (*s == '#') {
+ *s = '\0';
+ used += strlen(os);
+ break; /* the line has been read */
+ }
+
+ s = os;
+
+ /*
+ * Check for backslash by scanning back from the end of
+ * the entered line, the '\n' has been included since
+ * normally a line is terminated with this
+ * character. fgets() should only return one though!
+ */
+
+ s += strlen(s);
+ while (s > os && ((*--s == ' ') || (*s == '\t')
+ || (*s == '\n')));
+
+ /* check if it ends with a backslash */
+ if (*s == '\\') {
+ *s++ = ' '; /* replace backslash with ' ' */
+ *s = '\0'; /* truncate the line here */
+ used += strlen(os);
+ p = s; /* there is more ... */
+ } else {
+ /* End of the line! */
+ used += strlen(os);
+ break; /* this is the complete line */
+ }
+
+ } else {
+ /* Nothing in this line */
+ /* Don't move p */
+ }
+ }
+
+ return used;
+}
+
+typedef int (*servicefn)(pam_handle_t *, int, int, char **);
+
+int _pam_add_handler(pam_handle_t *pamh
+ , int must_fail, int other, int type
+ , int *actions, const char *mod_path
+ , int argc, char **argv, int argvlen)
+{
+ struct loaded_module *mod;
+ int x = 0;
+ struct handler **handler_p;
+ struct handler **handler_p2;
+ struct handlers *the_handlers;
+ const char *sym, *sym2;
+#ifdef PAM_SHL
+ const char *_sym, *_sym2;
+#endif
+ char *mod_full_path=NULL;
+ servicefn func, func2;
+ int success;
+
+ D(("called."));
+ IF_NO_PAMH("_pam_add_handler",pamh,PAM_SYSTEM_ERR);
+
+ /* if NULL set to something that can be searched for */
+ switch (mod_path != NULL) {
+ default:
+ if (mod_path[0] == '/') {
+ break;
+ }
+ mod_full_path = malloc(sizeof(DEFAULT_MODULE_PATH)+strlen(mod_path));
+ if (mod_full_path) {
+ sprintf(mod_full_path, DEFAULT_MODULE_PATH "%s", mod_path);
+ mod_path = mod_full_path;
+ break;
+ }
+ _pam_system_log(LOG_CRIT, "cannot malloc full mod path");
+ case 0:
+ mod_path = UNKNOWN_MODULE_PATH;
+ }
+
+ D(("_pam_add_handler: adding type %d, module `%s'",type,mod_path));
+ mod = pamh->handlers.module;
+
+ /* First, ensure the module is loaded */
+ while (x < pamh->handlers.modules_used) {
+ if (!strcmp(mod[x].name, mod_path)) { /* case sensitive ! */
+ break;
+ }
+ x++;
+ }
+ if (x == pamh->handlers.modules_used) {
+ /* Not found */
+ if (pamh->handlers.modules_allocated == pamh->handlers.modules_used) {
+ /* will need more memory */
+ void *tmp = realloc(pamh->handlers.module,
+ (pamh->handlers.modules_allocated+MODULE_CHUNK)
+ *sizeof(struct loaded_module));
+ if (tmp == NULL) {
+ D(("cannot enlarge module pointer memory"));
+ _pam_system_log(LOG_ERR,
+ "realloc returned NULL in _pam_add_handler");
+ _pam_drop(mod_full_path);
+ return PAM_ABORT;
+ }
+ pamh->handlers.module = tmp;
+ pamh->handlers.modules_allocated += MODULE_CHUNK;
+ }
+ mod = &(pamh->handlers.module[x]);
+ /* Be pessimistic... */
+ success = PAM_ABORT;
+
+#ifdef PAM_DYNAMIC
+ D(("_pam_add_handler: dlopen(%s) -> %lx", mod_path, &mod->dl_handle));
+ mod->dl_handle =
+# ifdef PAM_SHL
+ shl_load(mod_path, BIND_IMMEDIATE, 0L);
+# else /* PAM_SHL */
+ dlopen(mod_path, RTLD_NOW);
+# endif /* PAM_SHL */
+ D(("_pam_add_handler: dlopen'ed"));
+ if (mod->dl_handle == NULL) {
+ D(("_pam_add_handler: dlopen(%s) failed", mod_path));
+ _pam_system_log(LOG_ERR, "unable to dlopen(%s)", mod_path);
+# ifndef PAM_SHL
+ _pam_system_log(LOG_ERR, "[dlerror: %s]", dlerror());
+# endif /* PAM_SHL */
+ /* Don't abort yet; static code may be able to find function.
+ * But defaults to abort if nothing found below... */
+ } else {
+ D(("module added successfully"));
+ success = PAM_SUCCESS;
+ mod->type = PAM_MT_DYNAMIC_MOD;
+ pamh->handlers.modules_used++;
+ }
+#endif
+#ifdef PAM_STATIC
+ /* Only load static function if function was not found dynamically.
+ * This code should work even if no dynamic loading is available. */
+ if (success != PAM_SUCCESS) {
+ D(("_pam_add_handler: open static handler %s", mod_path));
+ mod->dl_handle = _pam_open_static_handler(mod_path);
+ if (mod->dl_handle == NULL) {
+ D(("_pam_add_handler: unable to find static handler %s",
+ mod_path));
+ _pam_system_log(LOG_ERR,
+ "unable to open static handler %s", mod_path);
+ /* Didn't find module in dynamic or static..will mark bad */
+ } else {
+ D(("static module added successfully"));
+ success = PAM_SUCCESS;
+ mod->type = PAM_MT_STATIC_MOD;
+ pamh->handlers.modules_used++;
+ }
+ }
+#endif
+
+ if (success != PAM_SUCCESS) { /* add a malformed module */
+ mod->dl_handle = NULL;
+ mod->type = PAM_MT_FAULTY_MOD;
+ pamh->handlers.modules_used++;
+ _pam_system_log(LOG_ERR, "adding faulty module: %s", mod_path);
+ success = PAM_SUCCESS; /* We have successfully added a module */
+ }
+
+ /* indicate its name - later we will search for it by this */
+ if ((mod->name = _pam_strdup(mod_path)) == NULL) {
+ D(("_pam_handler: couldn't get memory for mod_path"));
+ _pam_system_log(LOG_ERR, "no memory for module path", mod_path);
+ success = PAM_ABORT;
+ }
+
+ } else { /* x != pamh->handlers.modules_used */
+ mod += x; /* the located module */
+ success = PAM_SUCCESS;
+ }
+
+ _pam_drop(mod_full_path);
+ mod_path = NULL; /* no longer needed or trusted */
+
+ /* Now return error if necessary after trying all possible ways... */
+ if (success != PAM_SUCCESS)
+ return(success);
+
+ /*
+ * At this point 'mod' points to the stored/loaded module. If its
+ * dl_handle is unknown, then we must be able to indicate dispatch
+ * failure with 'must_fail'
+ */
+
+ /* Now define the handler(s) based on mod->dlhandle and type */
+
+ /* decide which list of handlers to use */
+ the_handlers = (other) ? &pamh->handlers.other : &pamh->handlers.conf;
+
+ handler_p = handler_p2 = NULL;
+ func = func2 = NULL;
+#ifdef PAM_SHL
+ _sym2 =
+#endif /* PAM_SHL */
+ sym2 = NULL;
+
+ /* point handler_p's at the root addresses of the function stacks */
+ switch (type) {
+ case PAM_T_AUTH:
+ handler_p = &the_handlers->authenticate;
+ sym = SHLIB_SYM_PREFIX "pam_sm_authenticate";
+ handler_p2 = &the_handlers->setcred;
+ sym2 = SHLIB_SYM_PREFIX "pam_sm_setcred";
+#ifdef PAM_SHL
+ _sym = "_pam_sm_authenticate";
+ _sym2 = "_pam_sm_setcred";
+#endif
+ break;
+ case PAM_T_SESS:
+ handler_p = &the_handlers->open_session;
+ sym = SHLIB_SYM_PREFIX "pam_sm_open_session";
+ handler_p2 = &the_handlers->close_session;
+ sym2 = SHLIB_SYM_PREFIX "pam_sm_close_session";
+#ifdef PAM_SHL
+ _sym = "_pam_sm_open_session";
+ _sym2 = "_pam_sm_close_session";
+#endif
+ break;
+ case PAM_T_ACCT:
+ handler_p = &the_handlers->acct_mgmt;
+ sym = SHLIB_SYM_PREFIX "pam_sm_acct_mgmt";
+#ifdef PAM_SHL
+ _sym = "_pam_sm_acct_mgmt";
+#endif
+ break;
+ case PAM_T_PASS:
+ handler_p = &the_handlers->chauthtok;
+ sym = SHLIB_SYM_PREFIX "pam_sm_chauthtok";
+#ifdef PAM_SHL
+ _sym = "_pam_sm_chauthtok";
+#endif
+ break;
+ default:
+ /* Illegal module type */
+ D(("_pam_add_handler: illegal module type %d", type));
+ return PAM_ABORT;
+ }
+
+ /* are the modules reliable? */
+ if (
+#ifdef PAM_DYNAMIC
+ mod->type != PAM_MT_DYNAMIC_MOD
+ &&
+#endif /* PAM_DYNAMIC */
+#ifdef PAM_STATIC
+ mod->type != PAM_MT_STATIC_MOD
+ &&
+#endif /* PAM_STATIC */
+ mod->type != PAM_MT_FAULTY_MOD
+ ) {
+ D(("_pam_add_handlers: illegal module library type; %d", mod->type));
+ _pam_system_log(LOG_ERR,
+ "internal error: module library type not known: %s;%d",
+ sym, mod->type);
+ return PAM_ABORT;
+ }
+
+ /* now identify this module's functions - for non-faulty modules */
+
+#ifdef PAM_DYNAMIC
+ if ((mod->type == PAM_MT_DYNAMIC_MOD) &&
+# ifdef PAM_SHL
+ (shl_findsym(&mod->dl_handle, sym, (short) TYPE_PROCEDURE, &func) &&
+ shl_findsym(&mod->dl_handle, _sym, (short) TYPE_PROCEDURE, &func))
+# else /* PAM_SHL */
+ (func = (servicefn) dlsym(mod->dl_handle, sym)) == NULL
+# endif /* PAM_SHL */
+ ) {
+ _pam_system_log(LOG_ERR, "unable to resolve symbol: %s", sym);
+ }
+#endif
+#ifdef PAM_STATIC
+ if ((mod->type == PAM_MT_STATIC_MOD) &&
+ (func = (servicefn)_pam_get_static_sym(mod->dl_handle, sym)) == NULL) {
+ _pam_system_log(LOG_ERR, "unable to resolve static symbol: %s", sym);
+ }
+#endif
+ if (sym2) {
+#ifdef PAM_DYNAMIC
+ if ((mod->type == PAM_MT_DYNAMIC_MOD) &&
+# ifdef PAM_SHL
+ (shl_findsym(&mod->dl_handle,sym2,(short)TYPE_PROCEDURE, &func2)&&
+ shl_findsym(&mod->dl_handle,_sym2,(short)TYPE_PROCEDURE, &func2))
+# else /* PAM_SHL */
+ (func2 = (servicefn) dlsym(mod->dl_handle, sym2)) == NULL
+# endif /* PAM_SHL */
+ ) {
+ _pam_system_log(LOG_ERR, "unable to resolve symbol: %s", sym2);
+ }
+#endif
+#ifdef PAM_STATIC
+ if ((mod->type == PAM_MT_STATIC_MOD) &&
+ (func2 = (servicefn)_pam_get_static_sym(mod->dl_handle, sym2))
+ == NULL) {
+ _pam_system_log(LOG_ERR, "unable to resolve symbol: %s", sym2);
+ }
+#endif
+ }
+
+ /* here func (and perhaps func2) point to the appropriate functions */
+
+ /* add new handler to end of existing list */
+ while (*handler_p != NULL) {
+ handler_p = &((*handler_p)->next);
+ }
+
+ if ((*handler_p = malloc(sizeof(struct handler))) == NULL) {
+ _pam_system_log(LOG_CRIT, "cannot malloc struct handler #1");
+ return (PAM_ABORT);
+ }
+
+ (*handler_p)->must_fail = must_fail; /* failure forced? */
+ (*handler_p)->func = func;
+ memcpy((*handler_p)->actions,actions,sizeof((*handler_p)->actions));
+ (*handler_p)->argc = argc;
+ (*handler_p)->argv = argv; /* not a copy */
+ (*handler_p)->next = NULL;
+
+ /* some of the modules have a second calling function */
+ if (handler_p2) {
+ /* add new handler to end of existing list */
+ while (*handler_p2) {
+ handler_p2 = &((*handler_p2)->next);
+ }
+
+ if ((*handler_p2 = malloc(sizeof(struct handler))) == NULL) {
+ _pam_system_log(LOG_CRIT, "cannot malloc struct handler #2");
+ return (PAM_ABORT);
+ }
+
+ (*handler_p2)->must_fail = must_fail; /* failure forced? */
+ (*handler_p2)->func = func2;
+ memcpy((*handler_p2)->actions,actions,sizeof((*handler_p2)->actions));
+ (*handler_p2)->argc = argc;
+ if (argv) {
+ if (((*handler_p2)->argv = malloc(argvlen)) == NULL) {
+ _pam_system_log(LOG_CRIT, "cannot malloc argv for handler #2");
+ return (PAM_ABORT);
+ }
+ memcpy((*handler_p2)->argv, argv, argvlen);
+ } else {
+ (*handler_p2)->argv = NULL; /* no arguments */
+ }
+ (*handler_p2)->next = NULL;
+ }
+
+ D(("_pam_add_handler: returning successfully"));
+
+ return PAM_SUCCESS;
+}
+
+/* Free various allocated structures and dlclose() the libs */
+int _pam_free_handlers(pam_handle_t *pamh)
+{
+ struct loaded_module *mod;
+
+ D(("called."));
+ IF_NO_PAMH("_pam_free_handlers",pamh,PAM_SYSTEM_ERR);
+
+ mod = pamh->handlers.module;
+
+ /* Close all loaded modules */
+
+ while (pamh->handlers.modules_used) {
+ D(("_pam_free_handlers: dlclose(%s)", mod->name));
+ free(mod->name);
+#ifdef PAM_DYNAMIC
+ if (mod->type == PAM_MT_DYNAMIC_MOD) {
+# ifdef PAM_SHL
+ shl_unload(mod->dl_handle);
+# else
+ dlclose(mod->dl_handle);
+# endif
+ }
+#endif
+ mod++;
+ pamh->handlers.modules_used--;
+ }
+
+ /* Free all the handlers */
+
+ _pam_free_handlers_aux(&(pamh->handlers.conf.authenticate));
+ _pam_free_handlers_aux(&(pamh->handlers.conf.setcred));
+ _pam_free_handlers_aux(&(pamh->handlers.conf.acct_mgmt));
+ _pam_free_handlers_aux(&(pamh->handlers.conf.open_session));
+ _pam_free_handlers_aux(&(pamh->handlers.conf.close_session));
+ _pam_free_handlers_aux(&(pamh->handlers.conf.chauthtok));
+
+ _pam_free_handlers_aux(&(pamh->handlers.other.authenticate));
+ _pam_free_handlers_aux(&(pamh->handlers.other.setcred));
+ _pam_free_handlers_aux(&(pamh->handlers.other.acct_mgmt));
+ _pam_free_handlers_aux(&(pamh->handlers.other.open_session));
+ _pam_free_handlers_aux(&(pamh->handlers.other.close_session));
+ _pam_free_handlers_aux(&(pamh->handlers.other.chauthtok));
+
+ /* no more loaded modules */
+
+ _pam_drop(pamh->handlers.module);
+
+ /* Indicate that handlers are not initialized for this pamh */
+
+ pamh->handlers.handlers_loaded = 0;
+
+ return PAM_SUCCESS;
+}
+
+void _pam_start_handlers(pam_handle_t *pamh)
+{
+ D(("called."));
+ /* NB. There is no check for a NULL pamh here, since no return
+ * value to communicate the fact! */
+
+ /* Indicate that handlers are not initialized for this pamh */
+ pamh->handlers.handlers_loaded = 0;
+
+ pamh->handlers.modules_allocated = 0;
+ pamh->handlers.modules_used = 0;
+ pamh->handlers.module = NULL;
+
+ /* initialize the .conf and .other entries */
+
+ pamh->handlers.conf.authenticate = NULL;
+ pamh->handlers.conf.setcred = NULL;
+ pamh->handlers.conf.acct_mgmt = NULL;
+ pamh->handlers.conf.open_session = NULL;
+ pamh->handlers.conf.close_session = NULL;
+ pamh->handlers.conf.chauthtok = NULL;
+
+ pamh->handlers.other.authenticate = NULL;
+ pamh->handlers.other.setcred = NULL;
+ pamh->handlers.other.acct_mgmt = NULL;
+ pamh->handlers.other.open_session = NULL;
+ pamh->handlers.other.close_session = NULL;
+ pamh->handlers.other.chauthtok = NULL;
+}
+
+void _pam_free_handlers_aux(struct handler **hp)
+{
+ struct handler *h = *hp;
+ struct handler *last;
+
+ D(("called."));
+ while (h) {
+ last = h;
+ _pam_drop(h->argv); /* This is all alocated in a single chunk */
+ h = h->next;
+ memset(last, 0, sizeof(*last));
+ free(last);
+ }
+
+ *hp = NULL;
+}
diff --git a/libpam/pam_item.c b/libpam/pam_item.c
new file mode 100644
index 00000000..f595a0b4
--- /dev/null
+++ b/libpam/pam_item.c
@@ -0,0 +1,304 @@
+/* pam_item.c */
+
+/*
+ * $Id$
+ *
+ * $Log$
+ * Revision 1.1 2000/06/20 22:11:17 agmorgan
+ * Initial revision
+ *
+ * Revision 1.3 1999/11/08 05:41:05 morgan
+ * pam_log - extra paranoia
+ * otherwise debugging changes
+ *
+ * Revision 1.2 1998/12/27 04:34:22 morgan
+ * reverting logging functions within libpam. Gone are the externally
+ * advertised API replaced by a more simple (libpam internal) one.
+ *
+ * Revision 1.1.1.1 1998/07/12 05:17:15 morgan
+ * Linux PAM sources pre-0.66
+ *
+ */
+
+#include <ctype.h>
+#include <stdlib.h>
+#include <string.h>
+#include <syslog.h>
+
+#include "pam_private.h"
+
+#define RESET(X, Y) \
+{ \
+ char *_TMP_ = (X); \
+ if (_TMP_ != (Y)) { \
+ (X) = (Y) ? _pam_strdup(Y) : NULL; \
+ if (_TMP_) \
+ free(_TMP_); \
+ } \
+}
+
+/* functions */
+
+int pam_set_item (
+ pam_handle_t *pamh,
+ int item_type,
+ const void *item)
+{
+ int retval;
+
+ D(("called"));
+
+ IF_NO_PAMH("pam_set_item", pamh, PAM_SYSTEM_ERR);
+
+ retval = PAM_SUCCESS;
+
+ switch (item_type) {
+ case PAM_SERVICE:
+ /* Setting handlers_loaded to 0 will cause the handlers
+ * to be reloaded on the next call to a service module.
+ */
+ pamh->handlers.handlers_loaded = 0;
+ RESET(pamh->service_name, item);
+ {
+ char *tmp;
+ for (tmp=pamh->service_name; *tmp; ++tmp)
+ *tmp = tolower(*tmp); /* require lower case */
+ }
+ break;
+ case PAM_USER:
+ RESET(pamh->user, item);
+ break;
+ case PAM_USER_PROMPT:
+ RESET(pamh->prompt, item);
+ break;
+ case PAM_TTY:
+ D(("setting tty to %s", item));
+ RESET(pamh->tty, item);
+ break;
+ case PAM_RUSER:
+ RESET(pamh->ruser, item);
+ break;
+ case PAM_RHOST:
+ RESET(pamh->rhost, item);
+ break;
+ case PAM_AUTHTOK:
+ /*
+ * The man page says this is only supposed to be available to
+ * the module providers. In order to use this item the app
+ * has to #include <security/pam_modules.h>. This is something
+ * it is *not* supposed to do with "Linux-"PAM! - AGM.
+ */
+ {
+ char *_TMP_ = pamh->authtok;
+ if (_TMP_ == item) /* not changed so leave alone */
+ break;
+ pamh->authtok = (item) ? _pam_strdup(item) : NULL;
+ if (_TMP_) {
+ _pam_overwrite(_TMP_);
+ free(_TMP_);
+ }
+ break;
+ }
+ case PAM_OLDAUTHTOK:
+ /* See note above. */
+ {
+ char *_TMP_ = pamh->oldauthtok;
+ if (_TMP_ == item) /* not changed so leave alone */
+ break;
+ pamh->oldauthtok = (item) ? _pam_strdup(item) : NULL;
+ if (_TMP_) {
+ _pam_overwrite(_TMP_);
+ free(_TMP_);
+ }
+ break;
+ }
+ case PAM_CONV: /* want to change the conversation function */
+ if (item == NULL) {
+ _pam_system_log(LOG_ERR,
+ "pam_set_item: attempt to set conv() to NULL");
+ retval = PAM_PERM_DENIED;
+ } else {
+ struct pam_conv *tconv;
+
+ if ((tconv=
+ (struct pam_conv *) malloc(sizeof(struct pam_conv))
+ ) == NULL) {
+ _pam_system_log(LOG_CRIT,
+ "pam_set_item: malloc failed for pam_conv");
+ retval = PAM_BUF_ERR;
+ } else {
+ memcpy(tconv, item, sizeof(struct pam_conv));
+ _pam_drop(pamh->pam_conversation);
+ pamh->pam_conversation = tconv;
+ }
+ }
+ break;
+ case PAM_FAIL_DELAY:
+ pamh->fail_delay.delay_fn_ptr = item;
+ break;
+ default:
+ retval = PAM_BAD_ITEM;
+ }
+
+ return (retval);
+}
+
+int pam_get_item (
+ const pam_handle_t *pamh,
+ int item_type,
+ const void **item)
+{
+ D(("called."));
+ IF_NO_PAMH("pam_get_item",pamh,PAM_SYSTEM_ERR);
+
+ if (item == NULL) {
+ _pam_system_log(LOG_ERR,
+ "pam_get_item: nowhere to place requested item");
+ return PAM_PERM_DENIED;
+ }
+
+ switch (item_type) {
+ case PAM_SERVICE:
+ *item = pamh->service_name;
+ break;
+ case PAM_USER:
+ D(("returning user=%s", pamh->user));
+ *item = pamh->user;
+ break;
+ case PAM_USER_PROMPT:
+ D(("returning userprompt=%s", pamh->user));
+ *item = pamh->prompt;
+ break;
+ case PAM_TTY:
+ D(("returning tty=%s", pamh->tty));
+ *item = pamh->tty;
+ break;
+ case PAM_RUSER:
+ *item = pamh->ruser;
+ break;
+ case PAM_RHOST:
+ *item = pamh->rhost;
+ break;
+ case PAM_AUTHTOK:
+ *item = pamh->authtok;
+ break;
+ case PAM_OLDAUTHTOK:
+ *item = pamh->oldauthtok;
+ break;
+ case PAM_CONV:
+ *item = pamh->pam_conversation;
+ break;
+ case PAM_FAIL_DELAY:
+ *item = pamh->fail_delay.delay_fn_ptr;
+ break;
+ default:
+ /* XXX - I made this up */
+ return PAM_BAD_ITEM;
+ }
+
+ return PAM_SUCCESS;
+}
+
+/* added by AGM 1996/3/2 */
+
+int pam_get_user(pam_handle_t *pamh, const char **user, const char *prompt)
+{
+ const char *use_prompt;
+ int retval;
+ struct pam_message msg,*pmsg;
+ struct pam_response *resp;
+
+ D(("called."));
+ IF_NO_PAMH("pam_get_user", pamh, PAM_SYSTEM_ERR);
+
+ if (pamh->pam_conversation == NULL) {
+ _pam_system_log(LOG_ERR, "pam_get_user: no conv element in pamh");
+ return PAM_SERVICE_ERR;
+ }
+
+ if (user == NULL) { /* ensure the the module has suplied a destination */
+ _pam_system_log(LOG_ERR, "pam_get_user: nowhere to record username");
+ return PAM_PERM_DENIED;
+ } else
+ *user = NULL;
+
+ if (pamh->user) { /* have one so return it */
+ *user = pamh->user;
+ return PAM_SUCCESS;
+ }
+
+ /* will need a prompt */
+ use_prompt = prompt;
+ if (use_prompt == NULL) {
+ use_prompt = pamh->prompt;
+ if (use_prompt == NULL) {
+ use_prompt = PAM_DEFAULT_PROMPT;
+ }
+ }
+
+ /* If we are resuming an old conversation, we verify that the prompt
+ is the same. Anything else is an error. */
+ if (pamh->former.want_user) {
+ /* must have a prompt to resume with */
+ if (! pamh->former.prompt) {
+ _pam_system_log(LOG_ERR,
+ "pam_get_user: failed to resume with prompt"
+ );
+ return PAM_ABORT;
+ }
+
+ /* must be the same prompt as last time */
+ if (strcmp(pamh->former.prompt, use_prompt)) {
+ _pam_system_log(LOG_ERR,
+ "pam_get_user: resumed with different prompt");
+ return PAM_ABORT;
+ }
+
+ /* ok, we can resume where we left off last time */
+ pamh->former.want_user = PAM_FALSE;
+ _pam_overwrite(pamh->former.prompt);
+ _pam_drop(pamh->former.prompt);
+ }
+
+ /* converse with application -- prompt user for a username */
+ pmsg = &msg;
+ msg.msg_style = PAM_PROMPT_ECHO_ON;
+ msg.msg = use_prompt;
+ resp = NULL;
+
+ retval = pamh->pam_conversation->
+ conv(1, (const struct pam_message **) &pmsg, &resp,
+ pamh->pam_conversation->appdata_ptr);
+
+ if (retval == PAM_CONV_AGAIN) {
+ /* conversation function is waiting for an event - save state */
+ D(("conversation function is not ready yet"));
+ pamh->former.want_user = PAM_TRUE;
+ pamh->former.prompt = _pam_strdup(use_prompt);
+ } else if (resp == NULL) {
+ /*
+ * conversation should have given a response
+ */
+ D(("pam_get_user: no response provided"));
+ retval = PAM_CONV_ERR;
+ } else if (retval == PAM_SUCCESS) { /* copy the username */
+ /*
+ * now we set the PAM_USER item -- this was missing from pre.53
+ * releases. However, reading the Sun manual, it is part of
+ * the standard API.
+ */
+ RESET(pamh->user, resp->resp);
+ *user = pamh->user;
+ }
+
+ if (resp) {
+ /*
+ * note 'resp' is allocated by the application and is
+ * correctly free()'d here
+ */
+ _pam_drop_reply(resp, 1);
+ }
+
+ D(("completed"));
+ return retval; /* pass on any error from conversation */
+}
diff --git a/libpam/pam_log.c b/libpam/pam_log.c
new file mode 100644
index 00000000..d990c8c0
--- /dev/null
+++ b/libpam/pam_log.c
@@ -0,0 +1,382 @@
+/*
+ * pam_log.c -- PAM system logging
+ *
+ * $Id$
+ *
+ */
+
+#ifdef linux
+# define _GNU_SOURCE
+# include <features.h>
+#else
+# define _BSD_SOURCE
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+
+#include "pam_private.h"
+
+#ifdef __hpux
+# include <stdio.h>
+# include <syslog.h>
+# ifdef __STDC__
+# ifndef __P
+# define __P(p) p
+# endif /* __P */
+# include <stdarg.h>
+# define VA_LOCAL_DECL va_list ap;
+# define VA_START(f) va_start(ap, f)
+# define VA_END va_end(ap)
+# else /* __STDC__ */
+# ifndef __P
+# define __P(p) ()
+# endif /* __P */
+# include <varargs.h>
+# define VA_LOCAL_DECL va_list ap;
+# define VA_START(f) va_start(ap)
+# define VA_END va_end(ap)
+# endif /* __STDC__ */
+/**************************************************************
+ * Patrick Powell Tue Apr 11 09:48:21 PDT 1995
+ * A bombproof version of doprnt (dopr) included.
+ * Sigh. This sort of thing is always nasty do deal with. Note that
+ * the version here does not include floating point...
+ *
+ * snprintf() is used instead of sprintf() as it does limit checks
+ * for string length. This covers a nasty loophole.
+ *
+ * The other functions are there to prevent NULL pointers from
+ * causing nast effects.
+ **************************************************************/
+
+static void dopr();
+static char *end;
+# ifndef _SCO_DS
+/* VARARGS3 */
+int
+# ifdef __STDC__
+snprintf(char *str, size_t count, const char *fmt, ...)
+# else /* __STDC__ */
+snprintf(str, count, fmt, va_alist)
+ char *str;
+ size_t count;
+ const char *fmt;
+ va_dcl
+# endif /* __STDC__ */
+{
+ int len;
+ VA_LOCAL_DECL
+
+ VA_START(fmt);
+ len = vsnprintf(str, count, fmt, ap);
+ VA_END;
+ return len;
+}
+# endif /* _SCO_DS */
+
+int
+# ifdef __STDC__
+vsnprintf(char *str, size_t count, const char *fmt, va_list args)
+# else /* __STDC__ */
+vsnprintf(str, count, fmt, args)
+ char *str;
+ int count;
+ char *fmt;
+ va_list args;
+# endif /* __STDC__ */
+{
+ str[0] = 0;
+ end = str + count - 1;
+ dopr( str, fmt, args );
+ if (count > 0)
+ end[0] = 0;
+ return strlen(str);
+}
+
+/*
+ * dopr(): poor man's version of doprintf
+ */
+
+static void fmtstr __P((char *value, int ljust, int len, int zpad,
+ int maxwidth));
+static void fmtnum __P((long value, int base, int dosign, int ljust, int len,
+ int zpad));
+static void dostr __P(( char * , int ));
+static char *output;
+static void dopr_outch __P(( int c ));
+
+static void
+# ifdef __STDC__
+dopr(char * buffer, const char * format, va_list args )
+# else /* __STDC__ */
+dopr( buffer, format, args )
+ char *buffer;
+ char *format;
+ va_list args;
+# endif /* __STDC__ */
+{
+ int ch;
+ long value;
+ int longflag = 0;
+ int pointflag = 0;
+ int maxwidth = 0;
+ char *strvalue;
+ int ljust;
+ int len;
+ int zpad;
+
+ output = buffer;
+ while( (ch = *format++) ){
+ switch( ch ){
+ case '%':
+ ljust = len = zpad = maxwidth = 0;
+ longflag = pointflag = 0;
+ nextch:
+ ch = *format++;
+ switch( ch ){
+ case 0:
+ dostr( "**end of format**" , 0);
+ return;
+ case '-': ljust = 1; goto nextch;
+ case '0': /* set zero padding if len not set */
+ if(len==0 && !pointflag) zpad = '0';
+ case '1': case '2': case '3':
+ case '4': case '5': case '6':
+ case '7': case '8': case '9':
+ if (pointflag)
+ maxwidth = maxwidth*10 + ch - '0';
+ else
+ len = len*10 + ch - '0';
+ goto nextch;
+ case '*':
+ if (pointflag)
+ maxwidth = va_arg( args, int );
+ else
+ len = va_arg( args, int );
+ goto nextch;
+ case '.': pointflag = 1; goto nextch;
+ case 'l': longflag = 1; goto nextch;
+ case 'u': case 'U':
+ /*fmtnum(value,base,dosign,ljust,len,zpad) */
+ if( longflag ){
+ value = va_arg( args, long );
+ } else {
+ value = va_arg( args, int );
+ }
+ fmtnum( value, 10,0, ljust, len, zpad ); break;
+ case 'o': case 'O':
+ /*fmtnum(value,base,dosign,ljust,len,zpad) */
+ if( longflag ){
+ value = va_arg( args, long );
+ } else {
+ value = va_arg( args, int );
+ }
+ fmtnum( value, 8,0, ljust, len, zpad ); break;
+ case 'd': case 'D':
+ if( longflag ){
+ value = va_arg( args, long );
+ } else {
+ value = va_arg( args, int );
+ }
+ fmtnum( value, 10,1, ljust, len, zpad ); break;
+ case 'x':
+ if( longflag ){
+ value = va_arg( args, long );
+ } else {
+ value = va_arg( args, int );
+ }
+ fmtnum( value, 16,0, ljust, len, zpad ); break;
+ case 'X':
+ if( longflag ){
+ value = va_arg( args, long );
+ } else {
+ value = va_arg( args, int );
+ }
+ fmtnum( value,-16,0, ljust, len, zpad ); break;
+ case 's':
+ strvalue = va_arg( args, char *);
+ if (maxwidth > 0 || !pointflag) {
+ if (pointflag && len > maxwidth)
+ len = maxwidth; /* Adjust padding */
+ fmtstr( strvalue,ljust,len,zpad, maxwidth);
+ }
+ break;
+ case 'c':
+ ch = va_arg( args, int );
+ dopr_outch( ch ); break;
+ case '%': dopr_outch( ch ); continue;
+ default:
+ dostr( "???????" , 0);
+ }
+ break;
+ default:
+ dopr_outch( ch );
+ break;
+ }
+ }
+ *output = 0;
+}
+
+static void
+fmtstr( value, ljust, len, zpad, maxwidth )
+ char *value;
+ int ljust, len, zpad, maxwidth;
+{
+ int padlen, strlen; /* amount to pad */
+
+ if( value == 0 ){
+ value = "<NULL>";
+ }
+ for( strlen = 0; value[strlen]; ++ strlen ); /* strlen */
+ if (strlen > maxwidth && maxwidth)
+ strlen = maxwidth;
+ padlen = len - strlen;
+ if( padlen < 0 ) padlen = 0;
+ if( ljust ) padlen = -padlen;
+ while( padlen > 0 ) {
+ dopr_outch( ' ' );
+ --padlen;
+ }
+ dostr( value, maxwidth );
+ while( padlen < 0 ) {
+ dopr_outch( ' ' );
+ ++padlen;
+ }
+}
+
+static void
+fmtnum( value, base, dosign, ljust, len, zpad )
+ long value;
+ int base, dosign, ljust, len, zpad;
+{
+ int signvalue = 0;
+ unsigned long uvalue;
+ char convert[20];
+ int place = 0;
+ int padlen = 0; /* amount to pad */
+ int caps = 0;
+
+ /* DEBUGP(("value 0x%x, base %d, dosign %d, ljust %d, len %d, zpad %d\n",
+ value, base, dosign, ljust, len, zpad )); */
+ uvalue = value;
+ if( dosign ){
+ if( value < 0 ) {
+ signvalue = '-';
+ uvalue = -value;
+ }
+ }
+ if( base < 0 ){
+ caps = 1;
+ base = -base;
+ }
+ do{
+ convert[place++] =
+ (caps? "0123456789ABCDEF":"0123456789abcdef")
+ [uvalue % (unsigned)base ];
+ uvalue = (uvalue / (unsigned)base );
+ }while(uvalue);
+ convert[place] = 0;
+ padlen = len - place;
+ if( padlen < 0 ) padlen = 0;
+ if( ljust ) padlen = -padlen;
+ /* DEBUGP(( "str '%s', place %d, sign %c, padlen %d\n",
+ convert,place,signvalue,padlen)); */
+ if( zpad && padlen > 0 ){
+ if( signvalue ){
+ dopr_outch( signvalue );
+ --padlen;
+ signvalue = 0;
+ }
+ while( padlen > 0 ){
+ dopr_outch( zpad );
+ --padlen;
+ }
+ }
+ while( padlen > 0 ) {
+ dopr_outch( ' ' );
+ --padlen;
+ }
+ if( signvalue ) dopr_outch( signvalue );
+ while( place > 0 ) dopr_outch( convert[--place] );
+ while( padlen < 0 ){
+ dopr_outch( ' ' );
+ ++padlen;
+ }
+}
+
+static void
+dostr( str , cut)
+ char *str;
+ int cut;
+{
+ if (cut) {
+ while(*str && cut-- > 0) dopr_outch(*str++);
+ } else {
+ while(*str) dopr_outch(*str++);
+ }
+}
+
+static void
+dopr_outch( c )
+ int c;
+{
+ if( end == 0 || output < end )
+ *output++ = c;
+}
+
+int
+# ifdef __STDC__
+vsyslog(int priority, const char *fmt, ...)
+# else /* __STDC__ */
+vsyslog(priority, fmt, va_alist)
+ int priority;
+ const char *fmt;
+ va_dcl
+# endif /* __STDC__ */
+{
+ VA_LOCAL_DECL
+ char logbuf[BUFSIZ];
+
+ VA_START(fmt);
+
+ vsnprintf(logbuf, BUFSIZ, fmt, ap);
+ syslog(priority, "%s", logbuf);
+
+ VA_END;
+}
+#endif /* __hpux */
+
+/* internal logging function */
+
+void _pam_system_log(int priority, const char *format, ... )
+{
+ va_list args;
+ char *eformat;
+
+ D(("pam_system_log called"));
+
+ if (format == NULL) {
+ D(("NULL format to _pam_system_log() call"));
+ return;
+ }
+
+ va_start(args, format);
+
+ eformat = malloc(sizeof(_PAM_SYSTEM_LOG_PREFIX)+strlen(format));
+ if (eformat != NULL) {
+ strcpy(eformat, _PAM_SYSTEM_LOG_PREFIX);
+ strcpy(eformat + sizeof(_PAM_SYSTEM_LOG_PREFIX) - 1, format);
+ vsyslog(priority, eformat, args);
+ _pam_overwrite(eformat);
+ _pam_drop(eformat);
+ } else {
+ vsyslog(priority, format, args);
+ }
+
+ va_end(args);
+
+ D(("done."));
+}
+
diff --git a/libpam/pam_malloc.c b/libpam/pam_malloc.c
new file mode 100644
index 00000000..44d583e7
--- /dev/null
+++ b/libpam/pam_malloc.c
@@ -0,0 +1,404 @@
+/*
+ * $Id$
+ *
+ * $Log$
+ * Revision 1.1 2000/06/20 22:11:18 agmorgan
+ * Initial revision
+ *
+ * Revision 1.2 1998/12/27 04:34:23 morgan
+ * reverting logging functions within libpam. Gone are the externally
+ * advertised API replaced by a more simple (libpam internal) one.
+ *
+ * Revision 1.1.1.1 1998/07/12 05:17:15 morgan
+ * Linux PAM sources pre-0.66
+ *
+ * Revision 1.2 1996/12/01 03:14:13 morgan
+ * use _pam_macros.h
+ *
+ * Revision 1.1 1996/11/10 21:26:11 morgan
+ * Initial revision
+ *
+ */
+
+/*
+ * This pair of files helps to locate memory leaks. It is a wrapper for
+ * the malloc family of calls. (Actutally, it currently only deals
+ * with calloc, malloc, realloc, free and exit)
+ *
+ * To use these functions the header "pam_malloc.h" must be included
+ * in all parts of the code (that use the malloc functions) and this
+ * file must be linked with the result. The pam_malloc_flags can be
+ * set from another function and determine the level of logging.
+ *
+ * The output is via the macros defined in _pam_macros.h
+ *
+ * It is a debugging tool and should be turned off in released code.
+ *
+ * This suite was written by Andrew Morgan <morgan@parc.power.net> for
+ * Linux-PAM.
+ */
+
+#ifndef DEBUG
+#define DEBUG
+#endif
+
+#include "pam_private.h"
+
+#include <security/pam_malloc.h>
+#include <security/_pam_macros.h>
+
+/* this must be done to stop infinite recursion! */
+#undef malloc
+#undef calloc
+#undef free
+#undef realloc
+#undef exit
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+/*
+ * default debugging level
+ */
+
+int pam_malloc_flags = PAM_MALLOC_ALL;
+int pam_malloc_delay_length = 4;
+
+#define on(x) ((pam_malloc_flags&(x))==(x))
+
+/*
+ * the implementation
+ */
+
+static const char *last_fn=NULL;
+static const char *last_file=NULL;
+static const char *last_call=NULL;
+static int last_line = 1;
+
+#define err(x) { _pam_output_xdebug_info(); _pam_output_debug x ; }
+
+static void set_last_(const char *x, const char *f
+ , const char *fn, const int l)
+{
+ last_fn = x ? x : "error-in-pam_malloc..";
+ last_file = f ? f : "*bad-file*";
+ last_call = fn ? fn: "*bad-fn*";
+ last_line = l;
+}
+
+static void _pam_output_xdebug_info(void)
+{
+ FILE *logfile;
+ int must_close = 1;
+
+ if (!(logfile = fopen(_PAM_LOGFILE,"a"))) {
+ logfile = stderr;
+ must_close = 0;
+ }
+ fprintf(logfile, "[%s:%s(%d)->%s()] ",
+ last_file, last_call, last_line, last_fn);
+ if (must_close) {
+ fflush(logfile);
+ fclose(logfile);
+ }
+}
+
+static void hinder(void)
+{
+ if (on(PAM_MALLOC_PAUSE)) {
+ if (on(0)) err(("pause requested"));
+ sleep(pam_malloc_delay_length);
+ }
+
+ if (on(PAM_MALLOC_STOP)) {
+ if (on(0)) err(("stop requested"));
+ exit(1);
+ }
+}
+
+/*
+ * here are the memory pointer registering functions.. these actually
+ * use malloc(!) but that's ok! ;^)
+ */
+
+struct reference {
+ void *ptr; /* pointer */
+ int nelements; /* number of elements */
+ int size; /* - each of this size */
+ char *file; /* where it was requested - filename */
+ char *function; /* - function */
+ int line; /* - line number */
+/*
+ * linking info
+ */
+ struct reference *next;
+};
+
+static void _dump(const char *say, const struct reference *ref)
+{
+ _pam_output_debug(" <%s: %p (#%d of %d) req. by %s(); %s line %d>\n"
+ , say
+ , ref->ptr,ref->nelements,ref->size
+ , ref->function,ref->file,ref->line);
+}
+
+static struct reference *root=NULL;
+
+static char *_strdup(const char *x)
+{
+ char *s;
+
+ s = (char *)malloc(strlen(x)+1);
+ if (s == NULL) {
+ if (on(0)) err(("_strdup failed"));
+ exit(1);
+ }
+
+ strcpy(s,x);
+ return s;
+}
+
+static void add_new_ref(void *new, int n, int size)
+{
+ struct reference *ref=NULL;
+
+ ref = (struct reference *) malloc( sizeof(struct reference) );
+ if (new == NULL || ref == NULL) {
+ if (on(0)) err(("internal error {add_new_ref}"));
+ exit(1);
+ }
+
+ ref->ptr = new;
+ ref->nelements = n;
+ ref->size = size;
+
+ ref->file = _strdup(last_file);
+ ref->function = _strdup(last_call);
+ ref->line = last_line;
+
+ ref->next = root;
+
+ if (on(PAM_MALLOC_REQUEST)) {
+ _dump("new_ptr", ref);
+ }
+
+ root = ref;
+}
+
+static void del_old_ref(void *old)
+{
+ struct reference *this,*last;
+
+ if (old == NULL) {
+ if (on(0)) err(("internal error {del_old_ref}"));
+ exit(1);
+ }
+
+ /* locate old pointer */
+
+ last = NULL;
+ this = root;
+ while (this) {
+ if (this->ptr == old)
+ break;
+ last = this;
+ this = this->next;
+ }
+
+ /* Did we find a reference ? */
+
+ if (this) {
+ if (on(PAM_MALLOC_FREE)) {
+ _dump("free old_ptr", this);
+ }
+ if (last == NULL) {
+ root = this->next;
+ } else {
+ last->next = this->next;
+ }
+ free(this->file);
+ free(this->function);
+ free(this);
+ } else {
+ if (on(0)) err(("ERROR!: bad memory"));
+ hinder();
+ }
+}
+
+static void verify_old_ref(void *old)
+{
+ struct reference *this;
+
+ if (old == NULL) {
+ if (on(0)) err(("internal error {verify_old_ref}"));
+ exit(1);
+ }
+
+ /* locate old pointer */
+
+ this = root;
+ while (this) {
+ if (this->ptr == old)
+ break;
+ this = this->next;
+ }
+
+ /* Did we find a reference ? */
+
+ if (this) {
+ if (on(PAM_MALLOC_VERIFY)) {
+ _dump("verify_ptr", this);
+ }
+ } else {
+ if (on(0)) err(("ERROR!: bad request"));
+ hinder();
+ }
+}
+
+static void dump_memory_list(const char *dump)
+{
+ struct reference *this;
+
+ this = root;
+ if (this) {
+ if (on(0)) err(("un-free()'d memory"));
+ while (this) {
+ _dump(dump, this);
+ this = this->next;
+ }
+ } else {
+ if (on(0)) err(("no memory allocated"));
+ }
+}
+
+/* now for the wrappers */
+
+#define _fn(x) set_last_(x,file,fn,line)
+
+void *pam_malloc(size_t size, const char *file, const char *fn, const int line)
+{
+ void *new;
+
+ _fn("malloc");
+
+ if (on(PAM_MALLOC_FUNC)) err(("request for %d", size));
+
+ new = malloc(size);
+ if (new == NULL) {
+ if (on(PAM_MALLOC_FAIL)) err(("returned NULL"));
+ } else {
+ if (on(PAM_MALLOC_REQUEST)) err(("request new"));
+ add_new_ref(new, 1, size);
+ }
+
+ return new;
+}
+
+void *pam_calloc(size_t nelm, size_t size
+ , const char *file, const char *fn, const int line)
+{
+ void *new;
+
+ _fn("calloc");
+
+ if (on(PAM_MALLOC_FUNC)) err(("request for %d of %d", nelm, size));
+
+ new = calloc(nelm,size);
+ if (new == NULL) {
+ if (on(PAM_MALLOC_FAIL)) err(("returned NULL"));
+ } else {
+ if (on(PAM_MALLOC_REQUEST)) err(("request new"));
+ add_new_ref(new, nelm, size);
+ }
+
+ return new;
+}
+
+void pam_free(void *ptr
+ , const char *file, const char *fn, const int line)
+{
+ _fn("free");
+
+ if (on(PAM_MALLOC_FUNC)) err(("request to free %p", ptr));
+
+ if (ptr == NULL) {
+ if (on(PAM_MALLOC_NULL)) err(("passed NULL pointer"));
+ } else {
+ if (on(PAM_MALLOC_FREE)) err(("deleted old"));
+ del_old_ref(ptr);
+ free(ptr);
+ }
+}
+
+void *pam_memalign(size_t ali, size_t size
+ , const char *file, const char *fn, const int line)
+{
+ _fn("memalign");
+ if (on(0)) err(("not implemented currently (Sorry)"));
+ exit(1);
+}
+
+void *pam_realloc(void *ptr, size_t size
+ , const char *file, const char *fn, const int line)
+{
+ void *new;
+
+ _fn("realloc");
+
+ if (on(PAM_MALLOC_FUNC)) err(("resize %p to %d", ptr, size));
+
+ if (ptr == NULL) {
+ if (on(PAM_MALLOC_NULL)) err(("passed NULL pointer"));
+ } else {
+ verify_old_ref(ptr);
+ }
+
+ new = realloc(ptr, size);
+ if (new == NULL) {
+ if (on(PAM_MALLOC_FAIL)) err(("returned NULL"));
+ } else {
+ if (ptr) {
+ if (on(PAM_MALLOC_FREE)) err(("deleted old"));
+ del_old_ref(ptr);
+ } else {
+ if (on(PAM_MALLOC_NULL)) err(("old is NULL"));
+ }
+ if (on(PAM_MALLOC_REQUEST)) err(("request new"));
+ add_new_ref(new, 1, size);
+ }
+
+ return new;
+}
+
+void *pam_valloc(size_t size
+ , const char *file, const char *fn, const int line)
+{
+ _fn("valloc");
+ if (on(0)) err(("not implemented currently (Sorry)"));
+ exit(1);
+}
+
+#include <alloca.h>
+
+void *pam_alloca(size_t size
+ , const char *file, const char *fn, const int line)
+{
+ _fn("alloca");
+ if (on(0)) err(("not implemented currently (Sorry)"));
+ exit(1);
+}
+
+void pam_exit(int i
+ , const char *file, const char *fn, const int line)
+{
+ _fn("exit");
+
+ if (on(0)) err(("passed (%d)", i));
+ if (on(PAM_MALLOC_LEAKED)) {
+ dump_memory_list("leaked");
+ }
+ exit(i);
+}
+
+/* end of file */
diff --git a/libpam/pam_map.c b/libpam/pam_map.c
new file mode 100644
index 00000000..8b969123
--- /dev/null
+++ b/libpam/pam_map.c
@@ -0,0 +1,85 @@
+/* pam_map.c - PAM mapping interface
+ *
+ * $Id$
+ *
+ * This is based on the X/Open XSSO specification of March 1997.
+ * It is not implemented as it is going to change... after 1997/9/25.
+ *
+ * $Log$
+ * Revision 1.1 2000/06/20 22:11:19 agmorgan
+ * Initial revision
+ *
+ * Revision 1.1.1.1 1998/07/12 05:17:15 morgan
+ * Linux PAM sources pre-0.66
+ *
+ */
+
+#include <stdio.h>
+
+#include "pam_private.h"
+
+/* p 54 */
+
+int pam_get_mapped_authtok(pam_handle_t *pamh,
+ const char *target_module_username,
+ const char *target_module_type,
+ const char *target_authn_domain,
+ size_t *target_authtok_len
+ unsigned char **target_module_authtok);
+{
+ D(("called"));
+
+ IF_NO_PAMH("pam_get_mapped_authtok",pamh,PAM_SYSTEM_ERR);
+
+ return PAM_SYSTEM_ERROR;
+}
+
+/* p 68 */
+
+int pam_set_mapped_authtok(pam_handle_t *pamh,
+ char *target_module_username,
+ size_t *target_authtok_len,
+ unsigned char *target_module_authtok,
+ char *target_module_type,
+ char *target_authn_domain)
+{
+ D(("called"));
+
+ IF_NO_PAMH("pam_set_mapped_authtok",pamh,PAM_SYSTEM_ERR);
+
+ return PAM_SYSTEM_ERROR;
+}
+
+/* p 56 */
+
+int pam_get_mapped_username(pam_handle_t *pamh,
+ const char *src_username,
+ const char *src_module_type,
+ const char *src_authn_domain,
+ const char *target_module_type,
+ const char *target_authn_domain,
+ char **target_module_username)
+{
+ D(("called"));
+
+ IF_NO_PAMH("pam_get_mapped_username",pamh,PAM_SYSTEM_ERR);
+
+ return PAM_SYSTEM_ERROR;
+}
+
+/* p 70 */
+
+int pam_set_mapped_username(pam_handle_t *pamh,
+ char *src_username,
+ char *src_module_type,
+ char *src_authn_domain,
+ char *target_module_username,
+ char *target_module_type,
+ char *target_authn_domain)
+{
+ D(("called"));
+
+ IF_NO_PAMH("pam_set_mapped_username",pamh,PAM_SYSTEM_ERR);
+
+ return PAM_SYSTEM_ERROR;
+}
diff --git a/libpam/pam_misc.c b/libpam/pam_misc.c
new file mode 100644
index 00000000..9bd52bfa
--- /dev/null
+++ b/libpam/pam_misc.c
@@ -0,0 +1,305 @@
+/* pam_misc.c -- This is random stuff */
+
+/*
+ * $Id$
+ */
+
+#include <stdarg.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <syslog.h>
+#include <ctype.h>
+
+#include "pam_private.h"
+
+/* caseless string comparison: POSIX does not define this.. */
+int _pam_strCMP(const char *s, const char *t)
+{
+ int cf;
+
+ do {
+ cf = tolower(*s) - tolower(*t);
+ ++t;
+ } while (!cf && *s++);
+
+ return cf;
+}
+
+char *_pam_StrTok(char *from, const char *format, char **next)
+/*
+ * this function is a variant of the standard strtok, it differs in that
+ * it takes an additional argument and doesn't nul terminate tokens until
+ * they are actually reached.
+ */
+{
+ char table[256], *end;
+ int i;
+
+ if (from == NULL && (from = *next) == NULL)
+ return from;
+
+ /* initialize table */
+ for (i=1; i<256; table[i++] = '\0');
+ for (i=0; format[i] ; table[(int)format[i++]] = 'y');
+
+ /* look for first non-blank char */
+ while (*from && table[(int)*from]) {
+ ++from;
+ }
+
+ if (*from == '[') {
+ /*
+ * special case, "[...]" is considered to be a single
+ * object. Note, however, if one of the format[] chars is
+ * '[' this single string will not be read correctly.
+ */
+ for (end=++from; *end && *end != ']'; ++end) {
+ if (*end == '\\' && end[1] == ']')
+ ++end;
+ }
+ /* note, this string is stripped of its edges: "..." is what
+ remains */
+ } else if (*from) {
+ /* simply look for next blank char */
+ for (end=from; *end && !table[(int)*end]; ++end);
+ } else {
+ return (*next = NULL); /* no tokens left */
+ }
+
+ /* now terminate what we have */
+ if (*end)
+ *end++ = '\0';
+
+ /* indicate what it left */
+ if (*end) {
+ *next = end;
+ } else {
+ *next = NULL; /* have found last token */
+ }
+
+ /* return what we have */
+ return from;
+}
+
+/*
+ * Safe duplication of character strings. "Paranoid"; don't leave
+ * evidence of old token around for later stack analysis.
+ */
+
+char *_pam_strdup(const char *x)
+{
+ register char *new=NULL;
+
+ if (x != NULL) {
+ register int i;
+
+ for (i=0; x[i]; ++i); /* length of string */
+ if ((new = malloc(++i)) == NULL) {
+ i = 0;
+ _pam_system_log(LOG_CRIT, "_pam_strdup: failed to get memory");
+ } else {
+ while (i-- > 0) {
+ new[i] = x[i];
+ }
+ }
+ x = NULL;
+ }
+
+ return new; /* return the duplicate or NULL on error */
+}
+
+/* Generate argv, argc from s */
+/* caller must free(argv) */
+
+int _pam_mkargv(char *s, char ***argv, int *argc)
+{
+ int l;
+ int argvlen = 0;
+ char *sbuf, *sbuf_start;
+ char **our_argv = NULL;
+ char **argvbuf;
+ char *argvbufp;
+#ifdef DEBUG
+ int count=0;
+#endif
+
+ D(("_pam_mkargv called: %s",s));
+
+ *argc = 0;
+
+ l = strlen(s);
+ if (l) {
+ if ((sbuf = sbuf_start = _pam_strdup(s)) == NULL) {
+ _pam_system_log(LOG_CRIT,
+ "pam_mkargv: null returned by _pam_strdup");
+ D(("arg NULL"));
+ } else {
+ /* Overkill on the malloc, but not large */
+ argvlen = (l + 1) * ((sizeof(char)) + sizeof(char *));
+ if ((our_argv = argvbuf = malloc(argvlen)) == NULL) {
+ _pam_system_log(LOG_CRIT,
+ "pam_mkargv: null returned by malloc");
+ } else {
+ char *tmp=NULL;
+
+ argvbufp = (char *) argvbuf + (l * sizeof(char *));
+ D(("[%s]",sbuf));
+ while ((sbuf = _pam_StrTok(sbuf, " \n\t", &tmp))) {
+ D(("arg #%d",++count));
+ D(("->[%s]",sbuf));
+ strcpy(argvbufp, sbuf);
+ D(("copied token"));
+ *argvbuf = argvbufp;
+ argvbufp += strlen(argvbufp) + 1;
+ D(("stepped in argvbufp"));
+ (*argc)++;
+ argvbuf++;
+ sbuf = NULL;
+ D(("loop again?"));
+ }
+ _pam_drop(sbuf_start);
+ }
+ }
+ }
+
+ *argv = our_argv;
+
+ D(("_pam_mkargv returned"));
+
+ return(argvlen);
+}
+
+/*
+ * this function is used to protect the modules from accidental or
+ * semi-mallicious harm that an application may do to confuse the API.
+ */
+
+void _pam_sanitize(pam_handle_t *pamh)
+{
+ /*
+ * this is for security. We reset the auth-tokens here.
+ */
+ pam_set_item(pamh,PAM_AUTHTOK,NULL);
+ pam_set_item(pamh,PAM_OLDAUTHTOK,NULL);
+}
+
+/*
+ * This function scans the array and replaces the _PAM_ACTION_UNDEF
+ * entries with the default action.
+ */
+
+void _pam_set_default_control(int *control_array, int default_action)
+{
+ int i;
+
+ for (i=0; i<_PAM_RETURN_VALUES; ++i) {
+ if (control_array[i] == _PAM_ACTION_UNDEF) {
+ control_array[i] = default_action;
+ }
+ }
+}
+
+/*
+ * This function is used to parse a control string. This string is a
+ * series of tokens of the following form:
+ *
+ * "[ ]*return_code[ ]*=[ ]*action/[ ]".
+ */
+
+#include "pam_tokens.h"
+
+void _pam_parse_control(int *control_array, char *tok)
+{
+ const char *error;
+ int ret;
+
+ while (*tok) {
+ int act, len;
+
+ /* skip leading space */
+ while (isspace((int)*tok) && *++tok);
+ if (!*tok)
+ break;
+
+ /* identify return code */
+ for (ret=0; ret<=_PAM_RETURN_VALUES; ++ret) {
+ len = strlen(_pam_token_returns[ret]);
+ if (!strncmp(_pam_token_returns[ret], tok, len)) {
+ break;
+ }
+ }
+ if (ret > _PAM_RETURN_VALUES || !*(tok += len)) {
+ error = "expecting return value";
+ goto parse_error;
+ }
+
+ /* observe '=' */
+ while (isspace((int)*tok) && *++tok);
+ if (!*tok || *tok++ != '=') {
+ error = "expecting '='";
+ goto parse_error;
+ }
+
+ /* skip leading space */
+ while (isspace((int)*tok) && *++tok);
+ if (!*tok) {
+ error = "expecting action";
+ goto parse_error;
+ }
+
+ /* observe action type */
+ for (act=0; act < (-(_PAM_ACTION_UNDEF)); ++act) {
+ len = strlen(_pam_token_actions[act]);
+ if (!strncmp(_pam_token_actions[act], tok, len)) {
+ act *= -1;
+ tok += len;
+ break;
+ }
+ }
+ if (act > 0) {
+ /*
+ * Either we have a number or we have hit an error. In
+ * principle, there is nothing to stop us accepting
+ * negative offsets. (Although we would have to think of
+ * another way of encoding the tokens.) However, I really
+ * think this would be both hard to administer and easily
+ * cause looping problems. So, for now, we will just
+ * allow forward jumps. (AGM 1998/1/7)
+ */
+ if (!isdigit((int)*tok)) {
+ error = "expecting jump number";
+ goto parse_error;
+ }
+ /* parse a number */
+ act = 0;
+ do {
+ act *= 10;
+ act += *tok - '0'; /* XXX - this assumes ascii behavior */
+ } while (*++tok && isdigit((int)*tok));
+ if (! act) {
+ /* we do not allow 0 jumps. There is a token ('ignore')
+ for that */
+ error = "expecting non-zero";
+ goto parse_error;
+ }
+ }
+
+ /* set control_array element */
+ if (ret != _PAM_RETURN_VALUES) {
+ control_array[ret] = act;
+ } else {
+ /* set the default to 'act' */
+ _pam_set_default_control(control_array, act);
+ }
+ }
+
+ /* that was a success */
+ return;
+
+parse_error:
+ /* treat everything as bad */
+ _pam_system_log(LOG_ERR, "pam_parse: %s; [...%s]", error, tok);
+ for (ret=0; ret<_PAM_RETURN_VALUES; control_array[ret++]=_PAM_ACTION_BAD);
+
+}
diff --git a/libpam/pam_password.c b/libpam/pam_password.c
new file mode 100644
index 00000000..afbaa580
--- /dev/null
+++ b/libpam/pam_password.c
@@ -0,0 +1,52 @@
+/* pam_password.c - PAM Password Management */
+
+/*
+ * $Id$
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+/* #define DEBUG */
+
+#include "pam_private.h"
+
+int pam_chauthtok(pam_handle_t *pamh, int flags)
+{
+ int retval;
+
+ D(("called."));
+
+ IF_NO_PAMH("pam_chauthtok", pamh, PAM_SYSTEM_ERR);
+
+ if (pamh->former.choice == PAM_NOT_STACKED) {
+ _pam_start_timer(pamh); /* we try to make the time for a failure
+ independent of the time it takes to
+ fail */
+ _pam_sanitize(pamh);
+ pamh->former.update = PAM_FALSE;
+ }
+
+ /* first call to check if there will be a problem */
+ if (pamh->former.update ||
+ (retval = _pam_dispatch(pamh, flags|PAM_PRELIM_CHECK,
+ PAM_CHAUTHTOK)) == PAM_SUCCESS) {
+ D(("completed check ok: former=%d", pamh->former.update));
+ pamh->former.update = PAM_TRUE;
+ retval = _pam_dispatch(pamh, flags|PAM_UPDATE_AUTHTOK,
+ PAM_CHAUTHTOK);
+ }
+
+ /* if we completed we should clean up */
+ if (retval != PAM_INCOMPLETE) {
+ _pam_sanitize(pamh);
+ pamh->former.update = PAM_FALSE;
+ _pam_await_timer(pamh, retval); /* if unsuccessful then wait now */
+ D(("pam_chauthtok exit %d - %d", retval, pamh->former.choice));
+ } else {
+ D(("will resume when ready", retval));
+ }
+
+ return retval;
+}
+
diff --git a/libpam/pam_private.h b/libpam/pam_private.h
new file mode 100644
index 00000000..51660fd1
--- /dev/null
+++ b/libpam/pam_private.h
@@ -0,0 +1,312 @@
+/*
+ * pam_private.h
+ *
+ * $Id$
+ *
+ * This is the Linux-PAM Library Private Header. It contains things
+ * internal to the Linux-PAM library. Things not needed by either an
+ * application or module.
+ *
+ * Please see end of file for copyright.
+ *
+ * Creator: Marc Ewing.
+ * Maintained: AGM
+ */
+
+#ifndef _PAM_PRIVATE_H
+#define _PAM_PRIVATE_H
+
+/* this is not used at the moment --- AGM */
+#define LIBPAM_VERSION 67
+
+#include <security/pam_appl.h>
+#include <security/pam_modules.h>
+
+/* the Linux-PAM configuration file */
+
+#define PAM_CONFIG "/etc/pam.conf"
+#define PAM_CONFIG_D "/etc/pam.d"
+#define PAM_CONFIG_DF "/etc/pam.d/%s"
+
+#define PAM_DEFAULT_SERVICE "other" /* lower case */
+#define PAM_DEFAULT_SERVICE_FILE PAM_CONFIG_D "/" PAM_DEFAULT_SERVICE
+
+#ifdef PAM_LOCKING
+/*
+ * the Linux-PAM lock file. If it exists Linux-PAM will abort. Use it
+ * to block access to libpam
+ */
+#define PAM_LOCK_FILE "/var/lock/subsys/PAM"
+#endif
+
+/* components of the pam_handle structure */
+
+struct handler {
+ int must_fail;
+ int (*func)(pam_handle_t *pamh, int flags, int argc, char **argv);
+ int actions[_PAM_RETURN_VALUES];
+ int argc;
+ char **argv;
+ struct handler *next;
+};
+
+struct loaded_module {
+ char *name;
+ int type; /* PAM_STATIC_MOD or PAM_DYNAMIC_MOD */
+ void *dl_handle;
+};
+
+#define PAM_MT_DYNAMIC_MOD 0
+#define PAM_MT_STATIC_MOD 1
+#define PAM_MT_FAULTY_MOD 2
+
+struct handlers {
+ struct handler *authenticate;
+ struct handler *setcred;
+ struct handler *acct_mgmt;
+ struct handler *open_session;
+ struct handler *close_session;
+ struct handler *chauthtok;
+};
+
+struct service {
+ struct loaded_module *module; /* Only used for dynamic loading */
+ int modules_allocated;
+ int modules_used;
+ int handlers_loaded;
+
+ struct handlers conf; /* the configured handlers */
+ struct handlers other; /* the default handlers */
+};
+
+/*
+ * Environment helper functions
+ */
+
+#define PAM_ENV_CHUNK 10 /* chunks of memory calloc()'d *
+ * at once */
+
+struct pam_environ {
+ int entries; /* the number of pointers available */
+ int requested; /* the number of pointers used: *
+ * 1 <= requested <= entries */
+ char **list; /* the environment storage (a list *
+ * of pointers to malloc() memory) */
+};
+
+#include <sys/time.h>
+
+typedef enum { PAM_FALSE, PAM_TRUE } _pam_boolean;
+
+struct _pam_fail_delay {
+ _pam_boolean set;
+ unsigned int delay;
+ time_t begin;
+ const void *delay_fn_ptr;
+};
+
+struct _pam_former_state {
+/* this is known and set by _pam_dispatch() */
+ int choice; /* which flavor of module function did we call? */
+
+/* state info for the _pam_dispatch_aux() function */
+ int depth; /* how deep in the stack were we? */
+ int impression; /* the impression at that time */
+ int status; /* the status before returning incomplete */
+
+/* state info used by pam_get_user() function */
+ int want_user;
+ char *prompt; /* saved prompt information */
+
+/* state info for the pam_chauthtok() function */
+ _pam_boolean update;
+};
+
+struct pam_handle {
+ char *authtok;
+ struct pam_conv *pam_conversation;
+ char *oldauthtok;
+ char *prompt; /* for use by pam_get_user() */
+ char *service_name;
+ char *user;
+ char *rhost;
+ char *ruser;
+ char *tty;
+ struct pam_data *data;
+ struct pam_environ *env; /* structure to maintain environment list */
+ struct _pam_fail_delay fail_delay; /* helper function for easy delays */
+ struct service handlers;
+ struct _pam_former_state former; /* library state - support for
+ event driven applications */
+};
+
+/* Values for select arg to _pam_dispatch() */
+#define PAM_NOT_STACKED 0
+#define PAM_AUTHENTICATE 1
+#define PAM_SETCRED 2
+#define PAM_ACCOUNT 3
+#define PAM_OPEN_SESSION 4
+#define PAM_CLOSE_SESSION 5
+#define PAM_CHAUTHTOK 6
+
+#define _PAM_ACTION_IS_JUMP(x) ((x) > 0)
+#define _PAM_ACTION_IGNORE 0
+#define _PAM_ACTION_OK -1
+#define _PAM_ACTION_DONE -2
+#define _PAM_ACTION_BAD -3
+#define _PAM_ACTION_DIE -4
+#define _PAM_ACTION_RESET -5
+/* Add any new entries here. Will need to change ..._UNDEF and then
+ * need to change pam_tokens.h */
+#define _PAM_ACTION_UNDEF -6 /* this is treated as an error
+ ( = _PAM_ACTION_BAD) */
+
+/* character tables for parsing config files */
+extern const char * const _pam_token_actions[-_PAM_ACTION_UNDEF];
+extern const char * const _pam_token_returns[_PAM_RETURN_VALUES+1];
+
+/*
+ * internally defined functions --- these should not be directly
+ * called by applications or modules
+ */
+int _pam_dispatch(pam_handle_t *pamh, int flags, int choice);
+
+/* Free various allocated structures and dlclose() the libs */
+int _pam_free_handlers(pam_handle_t *pamh);
+
+/* Parse config file, allocate handler structures, dlopen() */
+int _pam_init_handlers(pam_handle_t *pamh);
+
+/* Set all hander stuff to 0/NULL - called once from pam_start() */
+void _pam_start_handlers(pam_handle_t *pamh);
+
+/* environment helper functions */
+
+/* create the environment structure */
+int _pam_make_env(pam_handle_t *pamh);
+
+/* delete the environment structure */
+void _pam_drop_env(pam_handle_t *pamh);
+
+#ifdef LINUX_PAM
+
+/* these functions deal with failure delays as required by the
+ authentication modules and application. Their *interface* is likely
+ to remain the same although their function is hopefully going to
+ improve */
+
+/* reset the timer to no-delay */
+void _pam_reset_timer(pam_handle_t *pamh);
+
+/* this sets the clock ticking */
+void _pam_start_timer(pam_handle_t *pamh);
+
+/* this waits for the clock to stop ticking if status != PAM_SUCCESS */
+void _pam_await_timer(pam_handle_t *pamh, int status);
+
+
+#endif /* LINUX_PAM */
+
+typedef void (*voidfunc(void))(void);
+#ifdef PAM_STATIC
+
+/* The next two in ../modules/_pam_static/pam_static.c */
+
+/* Return pointer to data structure used to define a static module */
+struct pam_module * _pam_open_static_handler(const char *path);
+
+/* Return pointer to function requested from static module */
+
+voidfunc *_pam_get_static_sym(struct pam_module *mod, const char *symname);
+
+#endif
+
+/* For now we just use a stack and linear search for module data. */
+/* If it becomes apparent that there is a lot of data, it should */
+/* changed to either a sorted list or a hash table. */
+
+struct pam_data {
+ char *name;
+ void *data;
+ void (*cleanup)(pam_handle_t *pamh, void *data, int error_status);
+ struct pam_data *next;
+};
+
+void _pam_free_data(pam_handle_t *pamh, int status);
+
+int _pam_strCMP(const char *s, const char *t);
+char *_pam_StrTok(char *from, const char *format, char **next);
+
+char *_pam_strdup(const char *s);
+
+int _pam_mkargv(char *s, char ***argv, int *argc);
+
+void _pam_sanitize(pam_handle_t *pamh);
+
+void _pam_set_default_control(int *control_array, int default_action);
+
+void _pam_parse_control(int *control_array, char *tok);
+
+void _pam_system_log(int priority, const char *format, ... );
+#define _PAM_SYSTEM_LOG_PREFIX "PAM "
+
+/*
+ * XXX - Take care with this. It could confuse the logic of a trailing
+ * else
+ */
+
+#define IF_NO_PAMH(X,pamh,ERR) \
+if ((pamh) == NULL) { \
+ _pam_system_log(LOG_ERR, X ": NULL pam handle passed"); \
+ return ERR; \
+}
+
+/* Definition for the default username prompt used by pam_get_user() */
+
+#define PAM_DEFAULT_PROMPT "Please enter username: "
+
+/*
+ * include some helpful macros
+ */
+
+#include <security/_pam_macros.h>
+
+/*
+ * Copyright (C) 1995 by Red Hat Software, Marc Ewing
+ * Copyright (c) 1996-8, Andrew G. Morgan <morgan@linux.kernel.org>
+ *
+ * All rights reserved
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, and the entire permission notice in its entirety,
+ * including the disclaimer of warranties.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote
+ * products derived from this software without specific prior
+ * written permission.
+ *
+ * ALTERNATIVELY, this product may be distributed under the terms of
+ * the GNU Public License, in which case the provisions of the GPL are
+ * required INSTEAD OF the above restrictions. (This clause is
+ * necessary due to a potential bad interaction between the GPL and
+ * the restrictions contained in a BSD-style copyright.)
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#endif /* _PAM_PRIVATE_H_ */
diff --git a/libpam/pam_second.c b/libpam/pam_second.c
new file mode 100644
index 00000000..614275af
--- /dev/null
+++ b/libpam/pam_second.c
@@ -0,0 +1,46 @@
+/*
+ * pam_second.c -- PAM secondary authentication
+ * (based on XSSO draft spec of March 1997)
+ *
+ * $Id$
+ *
+ * $Log$
+ * Revision 1.1 2000/06/20 22:11:20 agmorgan
+ * Initial revision
+ *
+ * Revision 1.1.1.1 1998/07/12 05:17:15 morgan
+ * Linux PAM sources pre-0.66
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "pam_private.h"
+
+/* p 42 */
+
+int pam_authenticate_secondary(pam_handle_t *pamh,
+ char *target_username,
+ char *target_module_type,
+ char *target_authn_domain,
+ char *target_supp_data,
+ unsigned char *target_module_authtok,
+ int flags)
+{
+ int retval=PAM_SYSTEM_ERR;
+
+ D(("called"));
+
+ _pam_start_timer(pamh); /* we try to make the time for a failure
+ independent of the time it takes to
+ fail */
+
+ IF_NO_PAMH("pam_authenticate_secondary",pamh,PAM_SYSTEM_ERR);
+
+ _pam_await_timer(pamh, retval); /* if unsuccessful then wait now */
+
+ D(("pam_authenticate_secondary exit"));
+
+ return retval;
+}
diff --git a/libpam/pam_session.c b/libpam/pam_session.c
new file mode 100644
index 00000000..eae464c8
--- /dev/null
+++ b/libpam/pam_session.c
@@ -0,0 +1,41 @@
+/* pam_session.c - PAM Session Management */
+
+/*
+ * $Id$
+ *
+ * $Log$
+ * Revision 1.1 2000/06/20 22:11:20 agmorgan
+ * Initial revision
+ *
+ * Revision 1.1.1.1 1998/07/12 05:17:15 morgan
+ * Linux PAM sources pre-0.66
+ *
+ * Revision 1.3 1996/12/01 03:14:13 morgan
+ * use _pam_macros.h
+ *
+ * Revision 1.2 1996/03/10 02:19:12 morgan
+ * some oversight meant that this wasn't being compiled. It needed a
+ * couple of changes.
+ *
+ *
+ */
+
+#include <stdio.h>
+
+#include "pam_private.h"
+
+int pam_open_session(pam_handle_t *pamh, int flags)
+{
+ D(("called"));
+
+ IF_NO_PAMH("pam_open_session",pamh,PAM_SYSTEM_ERR);
+ return _pam_dispatch(pamh, flags, PAM_OPEN_SESSION);
+}
+
+int pam_close_session(pam_handle_t *pamh, int flags)
+{
+ D(("called"));
+
+ IF_NO_PAMH("pam_close_session",pamh,PAM_SYSTEM_ERR);
+ return _pam_dispatch(pamh, flags, PAM_CLOSE_SESSION);
+}
diff --git a/libpam/pam_start.c b/libpam/pam_start.c
new file mode 100644
index 00000000..fb222d62
--- /dev/null
+++ b/libpam/pam_start.c
@@ -0,0 +1,112 @@
+/* pam_start.c */
+
+/* Creator Marc Ewing
+ * Maintained by AGM
+ *
+ * $Id$
+ *
+ */
+
+#include <ctype.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <syslog.h>
+
+#include "pam_private.h"
+
+int pam_start (
+ const char *service_name,
+ const char *user,
+ const struct pam_conv *pam_conversation,
+ pam_handle_t **pamh)
+{
+ D(("called pam_start: [%s] [%s] [%p] [%p]"
+ ,service_name, user, pam_conversation, pamh));
+
+ if ((*pamh = calloc(1, sizeof(**pamh))) == NULL) {
+ _pam_system_log(LOG_CRIT, "pam_start: calloc failed for *pamh");
+ return (PAM_BUF_ERR);
+ }
+
+ if (service_name) {
+ char *tmp;
+
+ if (((*pamh)->service_name = _pam_strdup(service_name)) == NULL) {
+ _pam_system_log(LOG_CRIT,
+ "pam_start: _pam_strdup failed for service name");
+ _pam_drop(*pamh);
+ return (PAM_BUF_ERR);
+ }
+ for (tmp=(*pamh)->service_name; *tmp; ++tmp)
+ *tmp = tolower(*tmp); /* require lower case */
+ } else
+ (*pamh)->service_name = NULL;
+
+ if (user) {
+ if (((*pamh)->user = _pam_strdup(user)) == NULL) {
+ _pam_system_log(LOG_CRIT,
+ "pam_start: _pam_strdup failed for user");
+ _pam_drop((*pamh)->service_name);
+ _pam_drop(*pamh);
+ return (PAM_BUF_ERR);
+ }
+ } else
+ (*pamh)->user = NULL;
+
+ (*pamh)->tty = NULL;
+ (*pamh)->prompt = NULL; /* prompt for pam_get_user() */
+ (*pamh)->ruser = NULL;
+ (*pamh)->rhost = NULL;
+ (*pamh)->authtok = NULL;
+ (*pamh)->oldauthtok = NULL;
+ (*pamh)->fail_delay.delay_fn_ptr = NULL;
+ (*pamh)->former.choice = PAM_NOT_STACKED;
+
+ if (pam_conversation == NULL
+ || ((*pamh)->pam_conversation = (struct pam_conv *)
+ malloc(sizeof(struct pam_conv))) == NULL) {
+ _pam_system_log(LOG_CRIT, "pam_start: malloc failed for pam_conv");
+ _pam_drop((*pamh)->service_name);
+ _pam_drop((*pamh)->user);
+ _pam_drop(*pamh);
+ return (PAM_BUF_ERR);
+ } else {
+ memcpy((*pamh)->pam_conversation, pam_conversation,
+ sizeof(struct pam_conv));
+ }
+
+ (*pamh)->data = NULL;
+ if ( _pam_make_env(*pamh) != PAM_SUCCESS ) {
+ _pam_system_log(LOG_ERR,"pam_start: failed to initialize environment");
+ _pam_drop((*pamh)->service_name);
+ _pam_drop((*pamh)->user);
+ _pam_drop(*pamh);
+ return PAM_ABORT;
+ }
+
+ _pam_reset_timer(*pamh); /* initialize timer support */
+
+ _pam_start_handlers(*pamh); /* cannot fail */
+
+ /* According to the SunOS man pages, loading modules and resolving
+ * symbols happens on the first call from the application. */
+
+ /*
+ * XXX - should we call _pam_init_handlers() here ? The following
+ * is new as of Linux-PAM 0.55
+ */
+
+ if ( _pam_init_handlers(*pamh) != PAM_SUCCESS ) {
+ _pam_system_log(LOG_ERR, "pam_start: failed to initialize handlers");
+ _pam_drop_env(*pamh); /* purge the environment */
+ _pam_drop((*pamh)->service_name);
+ _pam_drop((*pamh)->user);
+ _pam_drop(*pamh);
+ return PAM_ABORT;
+ }
+
+ D(("exiting pam_start successfully"));
+
+ return PAM_SUCCESS;
+}
diff --git a/libpam/pam_static.c b/libpam/pam_static.c
new file mode 100644
index 00000000..64a3dd31
--- /dev/null
+++ b/libpam/pam_static.c
@@ -0,0 +1,141 @@
+/* pam_static.c -- static module loading helper functions */
+
+/* created by Michael K. Johnson, johnsonm@redhat.com
+ *
+ * $Id$
+ */
+
+/* This whole file is only used for PAM_STATIC */
+
+#ifdef PAM_STATIC
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "pam_private.h"
+
+/*
+ * Need to include pointers to static modules; this was built by each
+ * of the modules that register...
+ */
+
+#include "../modules/_static_module_list"
+
+/*
+ * and here is a structure that connects libpam to the above static
+ * modules
+ */
+
+static struct pam_module *static_modules[] = {
+
+#include "../modules/_static_module_entry"
+
+ NULL
+};
+
+/*
+ * and now for the functions
+ */
+
+/* Return pointer to data structure used to define a static module */
+struct pam_module * _pam_open_static_handler(const char *path)
+{
+ int i;
+ const char *clpath = path;
+ char *lpath, *end;
+
+ if (strchr(clpath, '/')) {
+ /* ignore path and leading "/" */
+ clpath = strrchr(lpath, '/') + 1;
+ }
+ /* create copy to muck with (must free before return) */
+ lpath = _pam_strdup(clpath);
+ /* chop .so off copy if it exists (or other extension on other
+ platform...) */
+ end = strstr(lpath, ".so");
+ if (end) {
+ *end = '\0';
+ }
+
+ /* now go find the module */
+ for (i = 0; static_modules[i] != NULL; i++) {
+ D(("%s=?%s\n", lpath, static_modules[i]->name));
+ if (static_modules[i]->name &&
+ ! strcmp(static_modules[i]->name, lpath)) {
+ break;
+ }
+ }
+
+ if (static_modules[i] == NULL) {
+ _pam_system_log(NULL, NULL, LOG_ERR, "no static module named %s",
+ lpath);
+ }
+
+ free(lpath);
+ return (static_modules[i]);
+}
+
+/* Return pointer to function requested from static module
+ * Can't just return void *, because ANSI C disallows casting a
+ * pointer to a function to a void *...
+ * This definition means:
+ * _pam_get_static_sym is a function taking two arguments and
+ * returning a pointer to a function which takes no arguments
+ * and returns void... */
+voidfunc *_pam_get_static_sym(struct pam_module *mod, const char *symname) {
+
+ if (! strcmp(symname, "pam_sm_authenticate")) {
+ return ((voidfunc *)mod->pam_sm_authenticate);
+ } else if (! strcmp(symname, "pam_sm_setcred")) {
+ return ((voidfunc *)mod->pam_sm_setcred);
+ } else if (! strcmp(symname, "pam_sm_acct_mgmt")) {
+ return ((voidfunc *)mod->pam_sm_acct_mgmt);
+ } else if (! strcmp(symname, "pam_sm_open_session")) {
+ return ((voidfunc *)mod->pam_sm_open_session);
+ } else if (! strcmp(symname, "pam_sm_close_session")) {
+ return ((voidfunc *)mod->pam_sm_close_session);
+ } else if (! strcmp(symname, "pam_sm_chauthtok")) {
+ return ((voidfunc *)mod->pam_sm_chauthtok);
+ }
+ /* getting to this point is an error */
+ return ((voidfunc *)NULL);
+}
+
+#endif /* PAM_STATIC */
+
+/*
+ * Copyright (C) 1995 by Red Hat Software, Michael K. Johnson
+ * All rights reserved
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, and the entire permission notice in its entirety,
+ * including the disclaimer of warranties.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote
+ * products derived from this software without specific prior
+ * written permission.
+ *
+ * ALTERNATIVELY, this product may be distributed under the terms of
+ * the GNU Public License, in which case the provisions of the GPL are
+ * required INSTEAD OF the above restrictions. (This clause is
+ * necessary due to a potential bad interaction between the GPL and
+ * the restrictions contained in a BSD-style copyright.)
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
diff --git a/libpam/pam_strerror.c b/libpam/pam_strerror.c
new file mode 100644
index 00000000..ecf8c0bb
--- /dev/null
+++ b/libpam/pam_strerror.c
@@ -0,0 +1,112 @@
+/* pam_strerror.c */
+
+/* $Id$
+ *
+ * $Log$
+ * Revision 1.1 2000/06/20 22:11:21 agmorgan
+ * Initial revision
+ *
+ * Revision 1.1.1.1 1998/07/12 05:17:15 morgan
+ * Linux PAM sources pre-0.66
+ *
+ * Revision 1.6 1997/01/04 20:12:02 morgan
+ * replaced conditional FAIL_NOW with ABORT
+ *
+ * Revision 1.5 1996/07/07 23:58:56 morgan
+ * corrected "... " to "..."
+ *
+ * Revision 1.4 1996/06/02 08:03:29 morgan
+ * spelling correction
+ *
+ * Revision 1.3 1996/03/16 23:08:54 morgan
+ * PAM --> Linux-PAM ;)
+ *
+ */
+
+#include "pam_private.h"
+
+const char *pam_strerror(pam_handle_t *pamh, int errnum)
+{
+#ifdef UGLY_HACK_FOR_PRIOR_BEHAVIOR_SUPPORT /* will be removed from v 1.0 */
+
+ int possible_error;
+
+ possible_error = (int) pamh;
+ if (!(possible_error >= 0 && possible_error <= PAM_BAD_ITEM)) {
+ possible_error = errnum;
+ }
+
+/* mask standard behavior to use possible_error variable. */
+#define errnum possible_error
+
+#endif /* UGLY_HACK_FOR_PRIOR_BEHAVIOR_SUPPORT */
+
+ switch (errnum) {
+ case PAM_SUCCESS:
+ return "Success";
+ case PAM_ABORT:
+ return "Critical error - immediate abort";
+ case PAM_OPEN_ERR:
+ return "dlopen() failure";
+ case PAM_SYMBOL_ERR:
+ return "Symbol not found";
+ case PAM_SERVICE_ERR:
+ return "Error in service module";
+ case PAM_SYSTEM_ERR:
+ return "System error";
+ case PAM_BUF_ERR:
+ return "Memory buffer error";
+ case PAM_PERM_DENIED:
+ return "Permission denied";
+ case PAM_AUTH_ERR:
+ return "Authentication failure";
+ case PAM_CRED_INSUFFICIENT:
+ return "Insufficient credentials to access authentication data";
+ case PAM_AUTHINFO_UNAVAIL:
+ return "Authentication service cannot retrieve authentication info.";
+ case PAM_USER_UNKNOWN:
+ return "User not known to the underlying authentication module";
+ case PAM_MAXTRIES:
+ return "Have exhasted maximum number of retries for service.";
+ case PAM_NEW_AUTHTOK_REQD:
+ return "Authentication token is no longer valid; new one required.";
+ case PAM_ACCT_EXPIRED:
+ return "User account has expired";
+ case PAM_SESSION_ERR:
+ return "Cannot make/remove an entry for the specified session";
+ case PAM_CRED_UNAVAIL:
+ return "Authentication service cannot retrieve user credentials";
+ case PAM_CRED_EXPIRED:
+ return "User credentials expired";
+ case PAM_CRED_ERR:
+ return "Failure setting user credentials";
+ case PAM_NO_MODULE_DATA:
+ return "No module specific data is present";
+ case PAM_BAD_ITEM:
+ return "Bad item passed to pam_*_item()";
+ case PAM_CONV_ERR:
+ return "Conversation error";
+ case PAM_AUTHTOK_ERR:
+ return "Authentication token manipulation error";
+ case PAM_AUTHTOK_RECOVER_ERR:
+ return "Authentication information cannot be recovered";
+ case PAM_AUTHTOK_LOCK_BUSY:
+ return "Authentication token lock busy";
+ case PAM_AUTHTOK_DISABLE_AGING:
+ return "Authentication token aging disabled";
+ case PAM_TRY_AGAIN:
+ return "Failed preliminary check by password service";
+ case PAM_IGNORE:
+ return "Please ignore underlying account module";
+ case PAM_MODULE_UNKNOWN:
+ return "Module is unknown";
+ case PAM_AUTHTOK_EXPIRED:
+ return "Authentication token expired";
+ case PAM_CONV_AGAIN:
+ return "Conversation is waiting for event";
+ case PAM_INCOMPLETE:
+ return "Application needs to call libpam again";
+ }
+
+ return "Unknown Linux-PAM error (need to upgrde libpam?)";
+}
diff --git a/libpam/pam_tokens.h b/libpam/pam_tokens.h
new file mode 100644
index 00000000..1fd32641
--- /dev/null
+++ b/libpam/pam_tokens.h
@@ -0,0 +1,111 @@
+/*
+ * pam_tokens.h
+ *
+ * $Id$
+ *
+ * This is a Linux-PAM Library Private Header file. It contains tokens
+ * that are used when we parse the configuration file(s).
+ *
+ * Please see end of file for copyright.
+ *
+ * Creator: Andrew Morgan.
+ *
+ * $Log$
+ * Revision 1.1 2000/06/20 22:11:21 agmorgan
+ * Initial revision
+ *
+ * Revision 1.1.1.1 1998/07/12 05:17:15 morgan
+ * Linux PAM sources pre-0.66
+ *
+ */
+
+#ifndef _PAM_TOKENS_H
+#define _PAM_TOKENS_H
+
+/* an array of actions */
+
+const char * const _pam_token_actions[-_PAM_ACTION_UNDEF] = {
+ "ignore", /* 0 */
+ "ok", /* -1 */
+ "done", /* -2 */
+ "bad", /* -3 */
+ "die", /* -4 */
+ "reset", /* -5 */
+};
+
+/* an array of possible return values */
+
+const char * const _pam_token_returns[_PAM_RETURN_VALUES+1] = {
+ "success", /* 0 */
+ "open_err", /* 1 */
+ "symbol_err", /* 2 */
+ "service_err", /* 3 */
+ "system_err", /* 4 */
+ "buf_err", /* 5 */
+ "perm_denied", /* 6 */
+ "auth_err", /* 7 */
+ "cred_insufficient", /* 8 */
+ "authinfo_unavail", /* 9 */
+ "user_unknown", /* 10 */
+ "maxtries", /* 11 */
+ "new_authtok_reqd", /* 12 */
+ "acct_expired", /* 13 */
+ "session_err", /* 14 */
+ "cred_unavail", /* 15 */
+ "cred_expired", /* 16 */
+ "cred_err", /* 17 */
+ "no_module_data", /* 18 */
+ "conv_err", /* 19 */
+ "authtok_err", /* 20 */
+ "authtok_recover_err", /* 21 */
+ "authtok_lock_busy", /* 22 */
+ "authtok_disable_aging", /* 23 */
+ "try_again", /* 24 */
+ "ignore", /* 25 */
+ "abort", /* 26 */
+ "authtok_expired", /* 27 */
+ "module_unknown", /* 28 */
+ "bad_item", /* 29 */
+/* add new return codes here */
+ "default" /* this is _PAM_RETURN_VALUES and indicates
+ the default return action */
+};
+
+/*
+ * Copyright (C) 1998, Andrew G. Morgan <morgan@linux.kernel.org>
+ *
+ * All rights reserved
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, and the entire permission notice in its entirety,
+ * including the disclaimer of warranties.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote
+ * products derived from this software without specific prior
+ * written permission.
+ *
+ * ALTERNATIVELY, this product may be distributed under the terms of
+ * the GNU Public License, in which case the provisions of the GPL are
+ * required INSTEAD OF the above restrictions. (This clause is
+ * necessary due to a potential bad interaction between the GPL and
+ * the restrictions contained in a BSD-style copyright.)
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#endif /* _PAM_PRIVATE_H_ */