summaryrefslogtreecommitdiff
path: root/modules/pam_stress
diff options
context:
space:
mode:
authorAndrew G. Morgan <morgan@kernel.org>2000-06-20 22:10:38 +0000
committerAndrew G. Morgan <morgan@kernel.org>2000-06-20 22:10:38 +0000
commitea488580c42e8918445a945484de3c8a5addc761 (patch)
treec992f3ba699caafedfadc16af38e6359c3c24698 /modules/pam_stress
Initial revision
Diffstat (limited to 'modules/pam_stress')
-rw-r--r--modules/pam_stress/.cvsignore1
-rw-r--r--modules/pam_stress/Makefile115
-rw-r--r--modules/pam_stress/README66
-rw-r--r--modules/pam_stress/pam_stress.c565
4 files changed, 747 insertions, 0 deletions
diff --git a/modules/pam_stress/.cvsignore b/modules/pam_stress/.cvsignore
new file mode 100644
index 00000000..380a834a
--- /dev/null
+++ b/modules/pam_stress/.cvsignore
@@ -0,0 +1 @@
+dynamic
diff --git a/modules/pam_stress/Makefile b/modules/pam_stress/Makefile
new file mode 100644
index 00000000..1bcfa502
--- /dev/null
+++ b/modules/pam_stress/Makefile
@@ -0,0 +1,115 @@
+#
+# $Id$
+#
+# Created by Andrew Morgan <morgan@parc.power.net> 1996/3/11
+#
+# This Makefile controls a build process of $(TITLE) module for
+# Linux-PAM. You should not modify this Makefile (unless you know
+# what you are doing!).
+#
+# $Log$
+# Revision 1.1 2000/06/20 22:11:57 agmorgan
+# Initial revision
+#
+# Revision 1.1.1.1 1998/07/12 05:17:16 morgan
+# Linux PAM sources pre-0.66
+#
+# Revision 1.7 1997/04/05 06:23:08 morgan
+# fakeroot
+#
+# Revision 1.6 1997/02/15 19:05:55 morgan
+# fixed email
+#
+# Revision 1.5 1996/11/10 20:17:55 morgan
+# cross platform support
+#
+# Revision 1.4 1996/09/05 06:31:09 morgan
+# ld --> gcc
+#
+# Revision 1.3 1996/05/26 15:50:43 morgan
+# make dynamic and static dirs
+#
+# Revision 1.2 1996/05/26 04:11:56 morgan
+# automated static support
+#
+#
+#
+
+TITLE=pam_stress
+
+#
+
+LIBSRC = $(TITLE).c
+LIBOBJ = $(TITLE).o
+LIBOBJD = $(addprefix dynamic/,$(LIBOBJ))
+LIBOBJS = $(addprefix static/,$(LIBOBJ))
+
+dynamic/%.o : %.c
+ $(CC) $(CFLAGS) $(DYNAMIC) $(CPPFLAGS) $(TARGET_ARCH) -c $< -o $@
+
+static/%.o : %.c
+ $(CC) $(CFLAGS) $(STATIC) $(CPPFLAGS) $(TARGET_ARCH) -c $< -o $@
+
+
+ifdef DYNAMIC
+LIBSHARED = $(TITLE).so
+endif
+
+ifdef STATIC
+LIBSTATIC = lib$(TITLE).o
+endif
+
+####################### don't edit below #######################
+
+dummy:
+
+ @echo "**** This is not a top-level Makefile "
+ exit
+
+all: dirs $(LIBSHARED) $(LIBSTATIC) register
+
+dirs:
+ifdef DYNAMIC
+ $(MKDIR) ./dynamic
+endif
+ifdef STATIC
+ $(MKDIR) ./static
+endif
+
+register:
+ifdef STATIC
+ ( cd .. ; ./register_static $(TITLE) $(TITLE)/$(LIBSTATIC) )
+endif
+
+ifdef DYNAMIC
+$(LIBOBJD): $(LIBSRC)
+
+$(LIBSHARED): $(LIBOBJD)
+ $(LD_D) -o $@ $(LIBOBJD)
+endif
+
+ifdef STATIC
+$(LIBOBJS): $(LIBSRC)
+
+$(LIBSTATIC): $(LIBOBJS)
+ $(LD) -r -o $@ $(LIBOBJS)
+endif
+
+install: all
+ $(MKDIR) $(FAKEROOT)$(SECUREDIR)
+ifdef DYNAMIC
+ $(INSTALL) -m $(SHLIBMODE) $(LIBSHARED) $(FAKEROOT)$(SECUREDIR)
+endif
+
+remove:
+ rm -f $(FAKEROOT)$(SECUREDIR)/$(TITLE).so
+
+clean:
+ rm -f $(LIBOBJD) $(LIBOBJS) core *~
+
+extraclean: clean
+ rm -f *.a *.o *.so *.bak
+
+.c.o:
+ $(CC) $(CFLAGS) -c $<
+
diff --git a/modules/pam_stress/README b/modules/pam_stress/README
new file mode 100644
index 00000000..74a297b2
--- /dev/null
+++ b/modules/pam_stress/README
@@ -0,0 +1,66 @@
+#
+# $Id$
+#
+# This describes the behavior of this module with respect to the
+# /etc/pam.conf file.
+#
+# writen by Andrew Morgan <morgan@parc.power.net>
+#
+
+This module recognizes the following arguments.
+
+debug put lots of information in syslog.
+ *NOTE* this option writes passwords to syslog, so
+ don't use anything sensitive when testing.
+
+no_warn don't give warnings about things (otherwise warnings are issued
+ via the conversation function)
+
+use_first_pass don't prompt for a password, for pam_sm_authentication
+ function just use item PAM_AUTHTOK.
+
+try_first_pass don't prompt for a password unless there has been no
+ previous authentication token (item PAM_AUTHTOK is NULL)
+
+rootok This is intended for the pam_sm_chauthtok function and
+ it instructs this function to permit root to change
+ the user's password without entering the old password.
+
+The following arguments are acted on by the module. They are intended
+to make the module give the impression of failing as a fully
+functioning module might.
+
+expired an argument intended for the account and chauthtok module
+ parts. It instructs the module to act as if the user's
+ password has expired
+
+fail_1 this instructs the module to make its first function fail.
+
+fail_2 this instructs the module to make its second function (if there
+ is one) fail.
+
+ The function break up is indicated in the Module
+ Developers' Guide. Listed here it is:
+
+ service function 1 function 2
+ ------- ---------- ----------
+ auth pam_sm_authenticate pam_sm_setcred
+ password pam_sm_chauthtok
+ session pam_sm_open_session pam_sm_close_session
+ account pam_sm_acct_mgmt
+
+prelim for pam_sm_chauthtok, means fail on PAM_PRELIM_CHECK.
+
+required for pam_sm_chauthtok, means fail if the user hasn't already
+ been authenticated by this module. (See stress_new_pwd data
+ item below.)
+
+#
+# data strings that this module uses are the following:
+#
+
+data name value(s) Comments
+--------- -------- --------
+stress_new_pwd yes tells pam_sm_chauthtok that
+ pam_sm_acct_mgmt says we need a new
+ password
diff --git a/modules/pam_stress/pam_stress.c b/modules/pam_stress/pam_stress.c
new file mode 100644
index 00000000..e5813579
--- /dev/null
+++ b/modules/pam_stress/pam_stress.c
@@ -0,0 +1,565 @@
+/* pam_stress module */
+
+/* $Id$
+ *
+ * created by Andrew Morgan <morgan@linux.kernel.org> 1996/3/12
+ */
+
+#ifdef linux
+# define _GNU_SOURCE
+# include <features.h>
+#endif
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <syslog.h>
+#include <stdarg.h>
+#include <string.h>
+#include <unistd.h>
+
+/*
+ * here, we make definitions for the externally accessible functions
+ * in this file (these definitions are required for static modules
+ * but strongly encouraged generally) they are used to instruct the
+ * modules include file to define their prototypes.
+ */
+
+#define PAM_SM_AUTH
+#define PAM_SM_ACCOUNT
+#define PAM_SM_SESSION
+#define PAM_SM_PASSWORD
+
+#include <security/pam_modules.h>
+#include <security/_pam_macros.h>
+
+static char *_strdup(const char *x)
+{
+ char *new;
+ new = malloc(strlen(x)+1);
+ strcpy(new,x);
+ return new;
+}
+
+/* log errors */
+
+static void _pam_log(int err, const char *format, ...)
+{
+ va_list args;
+
+ va_start(args, format);
+ openlog("PAM-stress", LOG_CONS|LOG_PID, LOG_AUTH);
+ vsyslog(err, format, args);
+ va_end(args);
+ closelog();
+}
+
+/* ---------- */
+
+/* an internal function to turn all possible test arguments into bits
+ of a ctrl number */
+
+/* generic options */
+
+#define PAM_ST_DEBUG 01
+#define PAM_ST_NO_WARN 02
+#define PAM_ST_USE_PASS1 04
+#define PAM_ST_TRY_PASS1 010
+#define PAM_ST_ROOTOK 020
+
+/* simulation options */
+
+#define PAM_ST_EXPIRED 040
+#define PAM_ST_FAIL_1 0100
+#define PAM_ST_FAIL_2 0200
+#define PAM_ST_PRELIM 0400
+#define PAM_ST_REQUIRE_PWD 01000
+
+/* some syslogging */
+
+static void _pam_report(int ctrl, const char *name, int flags,
+ int argc, const char **argv)
+{
+ if (ctrl & PAM_ST_DEBUG) {
+ _pam_log(LOG_DEBUG, "CALLED: %s", name);
+ _pam_log(LOG_DEBUG, "FLAGS : 0%o%s", flags,
+ (flags & PAM_SILENT) ? " (silent)":"");
+ _pam_log(LOG_DEBUG, "CTRL = 0%o",ctrl);
+ _pam_log(LOG_DEBUG, "ARGV :");
+ while (argc--) {
+ _pam_log(LOG_DEBUG, " \"%s\"", *argv++);
+ }
+ }
+}
+
+static int _pam_parse(int argc, const char **argv)
+{
+ int ctrl=0;
+
+ /* step through arguments */
+ for (ctrl=0; argc-- > 0; ++argv) {
+
+ /* generic options */
+
+ if (!strcmp(*argv,"debug"))
+ ctrl |= PAM_ST_DEBUG;
+ else if (!strcmp(*argv,"no_warn"))
+ ctrl |= PAM_ST_NO_WARN;
+ else if (!strcmp(*argv,"use_first_pass"))
+ ctrl |= PAM_ST_USE_PASS1;
+ else if (!strcmp(*argv,"try_first_pass"))
+ ctrl |= PAM_ST_TRY_PASS1;
+ else if (!strcmp(*argv,"rootok"))
+ ctrl |= PAM_ST_ROOTOK;
+
+ /* simulation options */
+
+ else if (!strcmp(*argv,"expired")) /* signal password needs
+ renewal */
+ ctrl |= PAM_ST_EXPIRED;
+ else if (!strcmp(*argv,"fail_1")) /* instruct fn 1 to fail */
+ ctrl |= PAM_ST_FAIL_1;
+ else if (!strcmp(*argv,"fail_2")) /* instruct fn 2 to fail */
+ ctrl |= PAM_ST_FAIL_2;
+ else if (!strcmp(*argv,"prelim")) /* instruct pam_sm_setcred
+ to fail on first call */
+ ctrl |= PAM_ST_PRELIM;
+ else if (!strcmp(*argv,"required")) /* module is fussy about the
+ user being authenticated */
+ ctrl |= PAM_ST_REQUIRE_PWD;
+
+ else {
+ _pam_log(LOG_ERR,"pam_parse: unknown option; %s",*argv);
+ }
+ }
+
+ return ctrl;
+}
+
+static int converse(pam_handle_t *pamh, int nargs
+ , struct pam_message **message
+ , struct pam_response **response)
+{
+ int retval;
+ struct pam_conv *conv;
+
+ if ((retval = pam_get_item(pamh,PAM_CONV,(const void **)&conv))
+ == PAM_SUCCESS) {
+ retval = conv->conv(nargs, (const struct pam_message **) message
+ , response, conv->appdata_ptr);
+ if (retval != PAM_SUCCESS) {
+ _pam_log(LOG_ERR,"(pam_stress) converse returned %d",retval);
+ _pam_log(LOG_ERR,"that is: %s",pam_strerror(pamh, retval));
+ }
+ } else {
+ _pam_log(LOG_ERR,"(pam_stress) converse failed to get pam_conv");
+ }
+
+ return retval;
+}
+
+/* authentication management functions */
+
+static int stress_get_password(pam_handle_t *pamh, int flags
+ , int ctrl, char **password)
+{
+ char *pass;
+
+ if ( (ctrl & (PAM_ST_TRY_PASS1|PAM_ST_USE_PASS1))
+ && (pam_get_item(pamh,PAM_AUTHTOK,(const void **)&pass)
+ == PAM_SUCCESS)
+ && (pass != NULL) ) {
+ pass = _strdup(pass);
+ } else if ((ctrl & PAM_ST_USE_PASS1)) {
+ _pam_log(LOG_WARNING, "pam_stress: no forwarded password");
+ return PAM_PERM_DENIED;
+ } else { /* we will have to get one */
+ struct pam_message msg[1],*pmsg[1];
+ struct pam_response *resp;
+ int retval;
+
+ /* set up conversation call */
+
+ pmsg[0] = &msg[0];
+ msg[0].msg_style = PAM_PROMPT_ECHO_OFF;
+ msg[0].msg = "STRESS Password: ";
+ resp = NULL;
+
+ if ((retval = converse(pamh,1,pmsg,&resp)) != PAM_SUCCESS) {
+ return retval;
+ }
+
+ if (resp) {
+ if ((resp[0].resp == NULL) && (ctrl & PAM_ST_DEBUG)) {
+ _pam_log(LOG_DEBUG,
+ "pam_sm_authenticate: NULL authtok given");
+ }
+ if ((flags & PAM_DISALLOW_NULL_AUTHTOK)
+ && resp[0].resp == NULL) {
+ free(resp);
+ return PAM_AUTH_ERR;
+ }
+
+ pass = resp[0].resp; /* remember this! */
+
+ resp[0].resp = NULL;
+ } else if (ctrl & PAM_ST_DEBUG) {
+ _pam_log(LOG_DEBUG,"pam_sm_authenticate: no error reported");
+ _pam_log(LOG_DEBUG,"getting password, but NULL returned!?");
+ return PAM_CONV_ERR;
+ }
+ free(resp);
+ }
+
+ *password = pass; /* this *MUST* be free()'d by this module */
+
+ return PAM_SUCCESS;
+}
+
+/* function to clean up data items */
+
+static void wipe_up(pam_handle_t *pamh, void *data, int error)
+{
+ free(data);
+}
+
+PAM_EXTERN
+int pam_sm_authenticate(pam_handle_t *pamh, int flags,
+ int argc, const char **argv)
+{
+ const char *username;
+ int retval=PAM_SUCCESS;
+ char *pass;
+ int ctrl;
+
+ D(("called."));
+
+ ctrl = _pam_parse(argc,argv);
+ _pam_report(ctrl, "pam_sm_authenticate", flags, argc, argv);
+
+ /* try to get the username */
+
+ retval = pam_get_user(pamh, &username, "username: ");
+ if ((ctrl & PAM_ST_DEBUG) && (retval == PAM_SUCCESS)) {
+ _pam_log(LOG_DEBUG, "pam_sm_authenticate: username = %s", username);
+ } else if (retval != PAM_SUCCESS) {
+ _pam_log(LOG_WARNING, "pam_sm_authenticate: failed to get username");
+ return retval;
+ }
+
+ /* now get the password */
+
+ retval = stress_get_password(pamh,flags,ctrl,&pass);
+ if (retval != PAM_SUCCESS) {
+ _pam_log(LOG_WARNING, "pam_sm_authenticate: "
+ "failed to get a password");
+ return retval;
+ }
+
+ /* try to set password item */
+
+ retval = pam_set_item(pamh,PAM_AUTHTOK,pass);
+ if (retval != PAM_SUCCESS) {
+ _pam_log(LOG_WARNING, "pam_sm_authenticate: "
+ "failed to store new password");
+ _pam_overwrite(pass);
+ free(pass);
+ return retval;
+ }
+
+ /* clean up local copy of password */
+
+ _pam_overwrite(pass);
+ free(pass);
+ pass = NULL;
+
+ /* if we are debugging then we print the password */
+
+ if (ctrl & PAM_ST_DEBUG) {
+ (void) pam_get_item(pamh,PAM_AUTHTOK,(const void **)&pass);
+ _pam_log(LOG_DEBUG,
+ "pam_st_authenticate: password entered is: [%s]\n",pass);
+ pass = NULL;
+ }
+
+ /* if we signal a fail for this function then fail */
+
+ if ((ctrl & PAM_ST_FAIL_1) && retval == PAM_SUCCESS)
+ return PAM_PERM_DENIED;
+
+ return retval;
+}
+
+PAM_EXTERN
+int pam_sm_setcred(pam_handle_t *pamh, int flags,
+ int argc, const char **argv)
+{
+ int ctrl = _pam_parse(argc,argv);
+
+ D(("called. [post parsing]"));
+
+ _pam_report(ctrl, "pam_sm_setcred", flags, argc, argv);
+
+ if (ctrl & PAM_ST_FAIL_2)
+ return PAM_CRED_ERR;
+
+ return PAM_SUCCESS;
+}
+
+/* account management functions */
+
+PAM_EXTERN
+int pam_sm_acct_mgmt(pam_handle_t *pamh, int flags,
+ int argc, const char **argv)
+{
+ int ctrl = _pam_parse(argc,argv);
+
+ D(("called. [post parsing]"));
+
+ _pam_report(ctrl,"pam_sm_acct_mgmt", flags, argc, argv);
+
+ if (ctrl & PAM_ST_FAIL_1)
+ return PAM_PERM_DENIED;
+ else if (ctrl & PAM_ST_EXPIRED) {
+ void *text = malloc(sizeof("yes")+1);
+ strcpy(text,"yes");
+ pam_set_data(pamh,"stress_new_pwd",text,wipe_up);
+ if (ctrl & PAM_ST_DEBUG) {
+ _pam_log(LOG_DEBUG,"pam_sm_acct_mgmt: need a new password");
+ }
+ return PAM_NEW_AUTHTOK_REQD;
+ }
+
+ return PAM_SUCCESS;
+}
+
+PAM_EXTERN
+int pam_sm_open_session(pam_handle_t *pamh, int flags,
+ int argc, const char **argv)
+{
+ char *username,*service;
+ int ctrl = _pam_parse(argc,argv);
+
+ D(("called. [post parsing]"));
+
+ _pam_report(ctrl,"pam_sm_open_session", flags, argc, argv);
+
+ if ((pam_get_item(pamh, PAM_USER, (const void **) &username)
+ != PAM_SUCCESS)
+ || (pam_get_item(pamh, PAM_SERVICE, (const void **) &service)
+ != PAM_SUCCESS)) {
+ _pam_log(LOG_WARNING,"pam_sm_open_session: for whom?");
+ return PAM_SESSION_ERR;
+ }
+
+ _pam_log(LOG_NOTICE,"pam_stress: opened [%s] session for user [%s]"
+ , service, username);
+
+ if (ctrl & PAM_ST_FAIL_1)
+ return PAM_SESSION_ERR;
+
+ return PAM_SUCCESS;
+}
+
+PAM_EXTERN
+int pam_sm_close_session(pam_handle_t *pamh, int flags,
+ int argc, const char **argv)
+{
+ const char *username,*service;
+ int ctrl = _pam_parse(argc,argv);
+
+ D(("called. [post parsing]"));
+
+ _pam_report(ctrl,"pam_sm_close_session", flags, argc, argv);
+
+ if ((pam_get_item(pamh, PAM_USER, (const void **)&username)
+ != PAM_SUCCESS)
+ || (pam_get_item(pamh, PAM_SERVICE, (const void **)&service)
+ != PAM_SUCCESS)) {
+ _pam_log(LOG_WARNING,"pam_sm_close_session: for whom?");
+ return PAM_SESSION_ERR;
+ }
+
+ _pam_log(LOG_NOTICE,"pam_stress: closed [%s] session for user [%s]"
+ , service, username);
+
+ if (ctrl & PAM_ST_FAIL_2)
+ return PAM_SESSION_ERR;
+
+ return PAM_SUCCESS;
+}
+
+PAM_EXTERN
+int pam_sm_chauthtok(pam_handle_t *pamh, int flags,
+ int argc, const char **argv)
+{
+ int retval;
+ int ctrl = _pam_parse(argc,argv);
+
+ D(("called. [post parsing]"));
+
+ _pam_report(ctrl,"pam_sm_chauthtok", flags, argc, argv);
+
+ /* this function should be called twice by the Linux-PAM library */
+
+ if (flags & PAM_PRELIM_CHECK) { /* first call */
+ if (ctrl & PAM_ST_DEBUG) {
+ _pam_log(LOG_DEBUG,"pam_sm_chauthtok: prelim check");
+ }
+ if (ctrl & PAM_ST_PRELIM)
+ return PAM_TRY_AGAIN;
+
+ return PAM_SUCCESS;
+ } else if (flags & PAM_UPDATE_AUTHTOK) { /* second call */
+ struct pam_message msg[3],*pmsg[3];
+ struct pam_response *resp;
+ const char *text;
+ char *txt=NULL;
+ int i;
+
+ if (ctrl & PAM_ST_DEBUG) {
+ _pam_log(LOG_DEBUG,"pam_sm_chauthtok: alter password");
+ }
+
+ if (ctrl & PAM_ST_FAIL_1)
+ return PAM_AUTHTOK_LOCK_BUSY;
+
+ if ( !(ctrl && PAM_ST_EXPIRED)
+ && (flags & PAM_CHANGE_EXPIRED_AUTHTOK)
+ && (pam_get_data(pamh,"stress_new_pwd",(const void **)&text)
+ != PAM_SUCCESS || strcmp(text,"yes"))) {
+ return PAM_SUCCESS; /* the token has not expired */
+ }
+
+ /* the password should be changed */
+
+ if ((ctrl & PAM_ST_REQUIRE_PWD)
+ && !(getuid() == 0 && (ctrl & PAM_ST_ROOTOK))
+ ) { /* first get old one? */
+ char *pass;
+
+ if (ctrl & PAM_ST_DEBUG) {
+ _pam_log(LOG_DEBUG
+ ,"pam_sm_chauthtok: getting old password");
+ }
+ retval = stress_get_password(pamh,flags,ctrl,&pass);
+ if (retval != PAM_SUCCESS) {
+ _pam_log(LOG_DEBUG
+ ,"pam_sm_chauthtok: no password obtained");
+ return retval;
+ }
+ retval = pam_set_item(pamh, PAM_OLDAUTHTOK, pass);
+ if (retval != PAM_SUCCESS) {
+ _pam_log(LOG_DEBUG
+ ,"pam_sm_chauthtok: could not set OLDAUTHTOK");
+ _pam_overwrite(pass);
+ free(pass);
+ return retval;
+ }
+ _pam_overwrite(pass);
+ free(pass);
+ }
+
+ /* set up for conversation */
+
+ if (!(flags & PAM_SILENT)) {
+ char *username;
+
+ if ( pam_get_item(pamh, PAM_USER, (const void **)&username)
+ || username == NULL ) {
+ _pam_log(LOG_ERR,"no username set");
+ return PAM_USER_UNKNOWN;
+ }
+ pmsg[0] = &msg[0];
+ msg[0].msg_style = PAM_TEXT_INFO;
+#define _LOCAL_STRESS_COMMENT "Changing STRESS password for "
+ txt = (char *) malloc(sizeof(_LOCAL_STRESS_COMMENT)
+ +strlen(username)+1);
+ strcpy(txt, _LOCAL_STRESS_COMMENT);
+#undef _LOCAL_STRESS_COMMENT
+ strcat(txt, username);
+ msg[0].msg = txt;
+ i = 1;
+ } else {
+ i = 0;
+ }
+
+ pmsg[i] = &msg[i];
+ msg[i].msg_style = PAM_PROMPT_ECHO_OFF;
+ msg[i++].msg = "Enter new STRESS password: ";
+ pmsg[i] = &msg[i];
+ msg[i].msg_style = PAM_PROMPT_ECHO_OFF;
+ msg[i++].msg = "Retype new STRESS password: ";
+ resp = NULL;
+
+ retval = converse(pamh,i,pmsg,&resp);
+ if (txt) {
+ free(txt);
+ txt = NULL; /* clean up */
+ }
+ if (retval != PAM_SUCCESS) {
+ return retval;
+ }
+
+ if (resp == NULL) {
+ _pam_log(LOG_ERR, "pam_sm_chauthtok: no response from conv");
+ return PAM_CONV_ERR;
+ }
+
+ /* store the password */
+
+ if (resp[i-2].resp && resp[i-1].resp) {
+ if (strcmp(resp[i-2].resp,resp[i-1].resp)) {
+ /* passwords are not the same; forget and return error */
+
+ _pam_drop_reply(resp, i);
+
+ if (!(flags & PAM_SILENT) && !(ctrl & PAM_ST_NO_WARN)) {
+ pmsg[0] = &msg[0];
+ msg[0].msg_style = PAM_ERROR_MSG;
+ msg[0].msg = "Verification mis-typed; "
+ "password unchaged";
+ resp = NULL;
+ (void) converse(pamh,1,pmsg,&resp);
+ if (resp) {
+ _pam_drop_reply(resp, 1);
+ }
+ }
+ return PAM_AUTHTOK_ERR;
+ }
+
+ if (pam_get_item(pamh,PAM_AUTHTOK,(const void **)&text)
+ == PAM_SUCCESS) {
+ (void) pam_set_item(pamh,PAM_OLDAUTHTOK,text);
+ text = NULL;
+ }
+ (void) pam_set_item(pamh,PAM_AUTHTOK,resp[0].resp);
+ } else {
+ _pam_log(LOG_DEBUG,"pam_sm_chauthtok: problem with resp");
+ retval = PAM_SYSTEM_ERR;
+ }
+
+ _pam_drop_reply(resp, i); /* clean up the passwords */
+ } else {
+ _pam_log(LOG_ERR,"pam_sm_chauthtok: this must be a Linux-PAM error");
+ return PAM_SYSTEM_ERR;
+ }
+
+ return retval;
+}
+
+
+#ifdef PAM_STATIC
+
+/* static module data */
+
+struct pam_module _pam_stress_modstruct = {
+ "pam_stress",
+ pam_sm_authenticate,
+ pam_sm_setcred,
+ pam_sm_acct_mgmt,
+ pam_sm_open_session,
+ pam_sm_close_session,
+ pam_sm_chauthtok
+};
+
+#endif