Blame SOURCES/krb5-1.12.1-pam.patch

db6389
From 02a10f4b9a8decc8d10f3e045282a0ae7ed1c00d Mon Sep 17 00:00:00 2001
db6389
From: Robbie Harwood <rharwood@redhat.com>
db6389
Date: Tue, 23 Aug 2016 16:29:58 -0400
db6389
Subject: [PATCH] krb5-1.12.1-pam.patch
db6389
db6389
Modify ksu so that it performs account and session management on behalf of
db6389
the target user account, mimicking the action of regular su.  The default
db6389
service name is "ksu", because on Fedora at least the configuration used
db6389
is determined by whether or not a login shell is being opened, and so
db6389
this may need to vary, too.  At run-time, ksu's behavior can be reset to
db6389
the earlier, non-PAM behavior by setting "use_pam" to false in the [ksu]
db6389
section of /etc/krb5.conf.
db6389
db6389
When enabled, ksu gains a dependency on libpam.
db6389
db6389
Originally RT#5939, though it's changed since then to perform the account
db6389
and session management before dropping privileges, and to apply on top of
db6389
changes we're proposing for how it handles cache collections.
db6389
---
db6389
 src/aclocal.m4              |  67 +++++++
db6389
 src/clients/ksu/Makefile.in |   8 +-
db6389
 src/clients/ksu/main.c      |  88 +++++++-
db6389
 src/clients/ksu/pam.c       | 389 ++++++++++++++++++++++++++++++++++++
db6389
 src/clients/ksu/pam.h       |  57 ++++++
db6389
 src/configure.in            |   2 +
db6389
 6 files changed, 608 insertions(+), 3 deletions(-)
db6389
 create mode 100644 src/clients/ksu/pam.c
db6389
 create mode 100644 src/clients/ksu/pam.h
db6389
db6389
diff --git a/src/aclocal.m4 b/src/aclocal.m4
db6389
index 3752d9bd5..340546d80 100644
db6389
--- a/src/aclocal.m4
db6389
+++ b/src/aclocal.m4
db6389
@@ -1697,3 +1697,70 @@ AC_DEFUN(KRB5_AC_PERSISTENT_KEYRING,[
db6389
       ]))
db6389
 ])dnl
db6389
 dnl
db6389
+dnl
db6389
+dnl Use PAM instead of local crypt() compare for checking local passwords,
db6389
+dnl and perform PAM account, session management, and password-changing where
db6389
+dnl appropriate.
db6389
+dnl 
db6389
+AC_DEFUN(KRB5_WITH_PAM,[
db6389
+AC_ARG_WITH(pam,[AC_HELP_STRING(--with-pam,[compile with PAM support])],
db6389
+	    withpam="$withval",withpam=auto)
db6389
+AC_ARG_WITH(pam-ksu-service,[AC_HELP_STRING(--with-ksu-service,[PAM service name for ksu ["ksu"]])],
db6389
+	    withksupamservice="$withval",withksupamservice=ksu)
db6389
+old_LIBS="$LIBS"
db6389
+if test "$withpam" != no ; then
db6389
+	AC_MSG_RESULT([checking for PAM...])
db6389
+	PAM_LIBS=
db6389
+
db6389
+	AC_CHECK_HEADERS(security/pam_appl.h)
db6389
+	if test "x$ac_cv_header_security_pam_appl_h" != xyes ; then
db6389
+		if test "$withpam" = auto ; then
db6389
+			AC_MSG_RESULT([Unable to locate security/pam_appl.h.])
db6389
+			withpam=no
db6389
+		else
db6389
+			AC_MSG_ERROR([Unable to locate security/pam_appl.h.])
db6389
+		fi
db6389
+	fi
db6389
+
db6389
+	LIBS=
db6389
+	unset ac_cv_func_pam_start
db6389
+	AC_CHECK_FUNCS(putenv pam_start)
db6389
+	if test "x$ac_cv_func_pam_start" = xno ; then
db6389
+		unset ac_cv_func_pam_start
db6389
+		AC_CHECK_LIB(dl,dlopen)
db6389
+		AC_CHECK_FUNCS(pam_start)
db6389
+		if test "x$ac_cv_func_pam_start" = xno ; then
db6389
+			AC_CHECK_LIB(pam,pam_start)
db6389
+			unset ac_cv_func_pam_start
db6389
+			unset ac_cv_func_pam_getenvlist
db6389
+			AC_CHECK_FUNCS(pam_start pam_getenvlist)
db6389
+			if test "x$ac_cv_func_pam_start" = xyes ; then
db6389
+				PAM_LIBS="$LIBS"
db6389
+			else
db6389
+				if test "$withpam" = auto ; then
db6389
+					AC_MSG_RESULT([Unable to locate libpam.])
db6389
+					withpam=no
db6389
+				else
db6389
+					AC_MSG_ERROR([Unable to locate libpam.])
db6389
+				fi
db6389
+			fi
db6389
+		fi
db6389
+	fi
db6389
+	if test "$withpam" != no ; then
db6389
+		AC_MSG_NOTICE([building with PAM support])
db6389
+		AC_DEFINE(USE_PAM,1,[Define if Kerberos-aware tools should support PAM])
db6389
+		AC_DEFINE_UNQUOTED(KSU_PAM_SERVICE,"$withksupamservice",
db6389
+				   [Define to the name of the PAM service name to be used by ksu.])
db6389
+		PAM_LIBS="$LIBS"
db6389
+		NON_PAM_MAN=".\\\" "
db6389
+		PAM_MAN=
db6389
+	else
db6389
+		PAM_MAN=".\\\" "
db6389
+		NON_PAM_MAN=
db6389
+	fi
db6389
+fi
db6389
+LIBS="$old_LIBS"
db6389
+AC_SUBST(PAM_LIBS)
db6389
+AC_SUBST(PAM_MAN)
db6389
+AC_SUBST(NON_PAM_MAN)
db6389
+])dnl
db6389
diff --git a/src/clients/ksu/Makefile.in b/src/clients/ksu/Makefile.in
db6389
index b2fcbf240..5755bb58a 100644
db6389
--- a/src/clients/ksu/Makefile.in
db6389
+++ b/src/clients/ksu/Makefile.in
db6389
@@ -3,12 +3,14 @@ BUILDTOP=$(REL)..$(S)..
db6389
 DEFINES = -DGET_TGT_VIA_PASSWD -DPRINC_LOOK_AHEAD -DCMD_PATH='"/bin /local/bin"'
db6389
 
db6389
 KSU_LIBS=@KSU_LIBS@
db6389
+PAM_LIBS=@PAM_LIBS@
db6389
 
db6389
 SRCS = \
db6389
 	$(srcdir)/krb_auth_su.c \
db6389
 	$(srcdir)/ccache.c \
db6389
 	$(srcdir)/authorization.c \
db6389
 	$(srcdir)/main.c \
db6389
+	$(srcdir)/pam.c \
db6389
 	$(srcdir)/heuristic.c \
db6389
 	$(srcdir)/xmalloc.c \
db6389
 	$(srcdir)/setenv.c
db6389
@@ -17,13 +19,17 @@ OBJS = \
db6389
 	ccache.o \
db6389
 	authorization.o \
db6389
 	main.o \
db6389
+	pam.o \
db6389
 	heuristic.o \
db6389
 	xmalloc.o @SETENVOBJ@
db6389
 
db6389
 all: ksu
db6389
 
db6389
 ksu: $(OBJS) $(KRB5_BASE_DEPLIBS)
db6389
-	$(CC_LINK) -o $@ $(OBJS) $(KRB5_BASE_LIBS) $(KSU_LIBS)
db6389
+	$(CC_LINK) -o $@ $(OBJS) $(KRB5_BASE_LIBS) $(KSU_LIBS) $(PAM_LIBS)
db6389
+
db6389
+pam.o: pam.c
db6389
+	$(CC) $(ALL_CFLAGS) -c $<
db6389
 
db6389
 clean:
db6389
 	$(RM) ksu
db6389
diff --git a/src/clients/ksu/main.c b/src/clients/ksu/main.c
db6389
index d9596d948..ec06788bc 100644
db6389
--- a/src/clients/ksu/main.c
db6389
+++ b/src/clients/ksu/main.c
db6389
@@ -26,6 +26,7 @@
db6389
  * KSU was writen by:  Ari Medvinsky, ari@isi.edu
db6389
  */
db6389
 
db6389
+#include "autoconf.h"
db6389
 #include "ksu.h"
db6389
 #include "adm_proto.h"
db6389
 #include <sys/types.h>
db6389
@@ -33,6 +34,10 @@
db6389
 #include <signal.h>
db6389
 #include <grp.h>
db6389
 
db6389
+#ifdef USE_PAM
db6389
+#include "pam.h"
db6389
+#endif
db6389
+
db6389
 /* globals */
db6389
 char * prog_name;
db6389
 int auth_debug =0;
db6389
@@ -40,6 +45,7 @@ char k5login_path[MAXPATHLEN];
db6389
 char k5users_path[MAXPATHLEN];
db6389
 char * gb_err = NULL;
db6389
 int quiet = 0;
db6389
+int force_fork = 0;
db6389
 /***********/
db6389
 
db6389
 #define KS_TEMPORARY_CACHE "MEMORY:_ksu"
db6389
@@ -528,6 +534,23 @@ main (argc, argv)
db6389
                prog_name,target_user,client_name,
db6389
                source_user,ontty());
db6389
 
db6389
+#ifdef USE_PAM
db6389
+        if (appl_pam_enabled(ksu_context, "ksu")) {
db6389
+            if (appl_pam_acct_mgmt(KSU_PAM_SERVICE, 1, target_user, NULL,
db6389
+                                   NULL, source_user,
db6389
+                                   ttyname(STDERR_FILENO)) != 0) {
db6389
+                fprintf(stderr, "Access denied for %s.\n", target_user);
db6389
+                exit(1);
db6389
+            }
db6389
+            if (appl_pam_requires_chauthtok()) {
db6389
+                fprintf(stderr, "Password change required for %s.\n",
db6389
+                        target_user);
db6389
+                exit(1);
db6389
+            }
db6389
+            force_fork++;
db6389
+        }
db6389
+#endif
db6389
+
db6389
         /* Run authorization as target.*/
db6389
         if (krb5_seteuid(target_uid)) {
db6389
             com_err(prog_name, errno, _("while switching to target for "
db6389
@@ -588,6 +611,24 @@ main (argc, argv)
db6389
 
db6389
             exit(1);
db6389
         }
db6389
+#ifdef USE_PAM
db6389
+    } else {
db6389
+        /* we always do PAM account management, even for root */
db6389
+        if (appl_pam_enabled(ksu_context, "ksu")) {
db6389
+            if (appl_pam_acct_mgmt(KSU_PAM_SERVICE, 1, target_user, NULL,
db6389
+                                   NULL, source_user,
db6389
+                                   ttyname(STDERR_FILENO)) != 0) {
db6389
+                fprintf(stderr, "Access denied for %s.\n", target_user);
db6389
+                exit(1);
db6389
+            }
db6389
+            if (appl_pam_requires_chauthtok()) {
db6389
+                fprintf(stderr, "Password change required for %s.\n",
db6389
+                        target_user);
db6389
+                exit(1);
db6389
+            }
db6389
+            force_fork++;
db6389
+        }
db6389
+#endif
db6389
     }
db6389
 
db6389
     if( some_rest_copy){
db6389
@@ -645,6 +686,30 @@ main (argc, argv)
db6389
         exit(1);
db6389
     }
db6389
 
db6389
+#ifdef USE_PAM
db6389
+    if (appl_pam_enabled(ksu_context, "ksu")) {
db6389
+        if (appl_pam_session_open() != 0) {
db6389
+            fprintf(stderr, "Error opening session for %s.\n", target_user);
db6389
+            exit(1);
db6389
+        }
db6389
+#ifdef DEBUG
db6389
+        if (auth_debug){
db6389
+            printf(" Opened PAM session.\n");
db6389
+        }
db6389
+#endif
db6389
+        if (appl_pam_cred_init()) {
db6389
+            fprintf(stderr, "Error initializing credentials for %s.\n",
db6389
+                    target_user);
db6389
+            exit(1);
db6389
+        }
db6389
+#ifdef DEBUG
db6389
+        if (auth_debug){
db6389
+            printf(" Initialized PAM credentials.\n");
db6389
+        }
db6389
+#endif
db6389
+    }
db6389
+#endif
db6389
+
db6389
     /* set permissions */
db6389
     if (setgid(target_pwd->pw_gid) < 0) {
db6389
         perror("ksu: setgid");
db6389
@@ -742,7 +807,7 @@ main (argc, argv)
db6389
         fprintf(stderr, "program to be execed %s\n",params[0]);
db6389
     }
db6389
 
db6389
-    if( keep_target_cache ) {
db6389
+    if( keep_target_cache && !force_fork ) {
db6389
         execv(params[0], params);
db6389
         com_err(prog_name, errno, _("while trying to execv %s"), params[0]);
db6389
         sweep_up(ksu_context, cc_target);
db6389
@@ -772,16 +837,35 @@ main (argc, argv)
db6389
             if (ret_pid == -1) {
db6389
                 com_err(prog_name, errno, _("while calling waitpid"));
db6389
             }
db6389
-            sweep_up(ksu_context, cc_target);
db6389
+            if( !keep_target_cache ) {
db6389
+                sweep_up(ksu_context, cc_target);
db6389
+            }
db6389
             exit (statusp);
db6389
         case -1:
db6389
             com_err(prog_name, errno, _("while trying to fork."));
db6389
             sweep_up(ksu_context, cc_target);
db6389
             exit (1);
db6389
         case 0:
db6389
+#ifdef USE_PAM
db6389
+            if (appl_pam_enabled(ksu_context, "ksu")) {
db6389
+                if (appl_pam_setenv() != 0) {
db6389
+                    fprintf(stderr, "Error setting up environment for %s.\n",
db6389
+                            target_user);
db6389
+                    exit (1);
db6389
+                }
db6389
+#ifdef DEBUG
db6389
+                if (auth_debug){
db6389
+                    printf(" Set up PAM environment.\n");
db6389
+                }
db6389
+#endif
db6389
+            }
db6389
+#endif
db6389
             execv(params[0], params);
db6389
             com_err(prog_name, errno, _("while trying to execv %s"),
db6389
                     params[0]);
db6389
+            if( keep_target_cache ) {
db6389
+                sweep_up(ksu_context, cc_target);
db6389
+            }
db6389
             exit (1);
db6389
         }
db6389
     }
db6389
diff --git a/src/clients/ksu/pam.c b/src/clients/ksu/pam.c
db6389
new file mode 100644
db6389
index 000000000..cbfe48704
db6389
--- /dev/null
db6389
+++ b/src/clients/ksu/pam.c
db6389
@@ -0,0 +1,389 @@
db6389
+/*
db6389
+ * src/clients/ksu/pam.c
db6389
+ *
db6389
+ * Copyright 2007,2009,2010 Red Hat, Inc.
db6389
+ *
db6389
+ * All Rights Reserved.
db6389
+ *
db6389
+ * Redistribution and use in source and binary forms, with or without
db6389
+ * modification, are permitted provided that the following conditions are met:
db6389
+ *
db6389
+ *  Redistributions of source code must retain the above copyright notice, this
db6389
+ *  list of conditions and the following disclaimer.
db6389
+ *
db6389
+ *  Redistributions in binary form must reproduce the above copyright notice,
db6389
+ *  this list of conditions and the following disclaimer in the documentation
db6389
+ *  and/or other materials provided with the distribution.
db6389
+ *
db6389
+ *  Neither the name of Red Hat, Inc. nor the names of its contributors may be
db6389
+ *  used to endorse or promote products derived from this software without
db6389
+ *  specific prior written permission.
db6389
+ *
db6389
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
db6389
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
db6389
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
db6389
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
db6389
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
db6389
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
db6389
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
db6389
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
db6389
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
db6389
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
db6389
+ * POSSIBILITY OF SUCH DAMAGE.
db6389
+ * 
db6389
+ * Convenience wrappers for using PAM.
db6389
+ */
db6389
+
db6389
+#include "autoconf.h"
db6389
+#ifdef USE_PAM
db6389
+#include <sys/types.h>
db6389
+#include <stdio.h>
db6389
+#include <stdlib.h>
db6389
+#include <string.h>
db6389
+#include <unistd.h>
db6389
+#include "k5-int.h"
db6389
+#include "pam.h"
db6389
+
db6389
+#ifndef MAXPWSIZE
db6389
+#define MAXPWSIZE 128
db6389
+#endif
db6389
+
db6389
+static int appl_pam_started;
db6389
+static pid_t appl_pam_starter = -1;
db6389
+static int appl_pam_session_opened;
db6389
+static int appl_pam_creds_initialized;
db6389
+static int appl_pam_pwchange_required;
db6389
+static pam_handle_t *appl_pamh;
db6389
+static struct pam_conv appl_pam_conv;
db6389
+static char *appl_pam_user;
db6389
+struct appl_pam_non_interactive_args {
db6389
+	const char *user;
db6389
+	const char *password;
db6389
+};
db6389
+
db6389
+int
db6389
+appl_pam_enabled(krb5_context context, const char *section)
db6389
+{
db6389
+	int enabled = 1;
db6389
+	if ((context != NULL) && (context->profile != NULL)) {
db6389
+		if (profile_get_boolean(context->profile,
db6389
+					section,
db6389
+					USE_PAM_CONFIGURATION_KEYWORD,
db6389
+					NULL,
db6389
+					enabled, &enabled) != 0) {
db6389
+			enabled = 1;
db6389
+		}
db6389
+	}
db6389
+	return enabled;
db6389
+}
db6389
+
db6389
+void
db6389
+appl_pam_cleanup(void)
db6389
+{
db6389
+	if (getpid() != appl_pam_starter) {
db6389
+		return;
db6389
+	}
db6389
+#ifdef DEBUG
db6389
+	printf("Called to clean up PAM.\n");
db6389
+#endif
db6389
+	if (appl_pam_creds_initialized) {
db6389
+#ifdef DEBUG
db6389
+		printf("Deleting PAM credentials.\n");
db6389
+#endif
db6389
+		pam_setcred(appl_pamh, PAM_DELETE_CRED);
db6389
+		appl_pam_creds_initialized = 0;
db6389
+	}
db6389
+	if (appl_pam_session_opened) {
db6389
+#ifdef DEBUG
db6389
+		printf("Closing PAM session.\n");
db6389
+#endif
db6389
+		pam_close_session(appl_pamh, 0);
db6389
+		appl_pam_session_opened = 0;
db6389
+	}
db6389
+	appl_pam_pwchange_required = 0;
db6389
+	if (appl_pam_started) {
db6389
+#ifdef DEBUG
db6389
+		printf("Shutting down PAM.\n");
db6389
+#endif
db6389
+		pam_end(appl_pamh, 0);
db6389
+		appl_pam_started = 0;
db6389
+		appl_pam_starter = -1;
db6389
+		free(appl_pam_user);
db6389
+		appl_pam_user = NULL;
db6389
+	}
db6389
+}
db6389
+static int
db6389
+appl_pam_interactive_converse(int num_msg, const struct pam_message **msg,
db6389
+			      struct pam_response **presp, void *appdata_ptr)
db6389
+{
db6389
+	const struct pam_message *message;
db6389
+	struct pam_response *resp;
db6389
+	int i, code;
db6389
+	char *pwstring, pwbuf[MAXPWSIZE];
db6389
+	unsigned int pwsize;
db6389
+	resp = malloc(sizeof(struct pam_response) * num_msg);
db6389
+	if (resp == NULL) {
db6389
+		return PAM_BUF_ERR;
db6389
+	}
db6389
+	memset(resp, 0, sizeof(struct pam_response) * num_msg);
db6389
+	code = PAM_SUCCESS;
db6389
+	for (i = 0; i < num_msg; i++) {
db6389
+		message = &(msg[0][i]); /* XXX */
db6389
+		message = msg[i]; /* XXX */
db6389
+		pwstring = NULL;
db6389
+		switch (message->msg_style) {
db6389
+		case PAM_TEXT_INFO:
db6389
+		case PAM_ERROR_MSG:
db6389
+			printf("[%s]\n", message->msg ? message->msg : "");
db6389
+			fflush(stdout);
db6389
+			resp[i].resp = NULL;
db6389
+			resp[i].resp_retcode = PAM_SUCCESS;
db6389
+			break;
db6389
+		case PAM_PROMPT_ECHO_ON:
db6389
+		case PAM_PROMPT_ECHO_OFF:
db6389
+			if (message->msg_style == PAM_PROMPT_ECHO_ON) {
db6389
+				if (fgets(pwbuf, sizeof(pwbuf),
db6389
+					  stdin) != NULL) {
db6389
+					pwbuf[strcspn(pwbuf, "\r\n")] = '\0';
db6389
+					pwstring = pwbuf;
db6389
+				}
db6389
+			} else {
db6389
+				pwstring = getpass(message->msg ?
db6389
+						   message->msg :
db6389
+						   "");
db6389
+			}
db6389
+			if ((pwstring != NULL) && (pwstring[0] != '\0')) {
db6389
+				pwsize = strlen(pwstring);
db6389
+				resp[i].resp = malloc(pwsize + 1);
db6389
+				if (resp[i].resp == NULL) {
db6389
+					resp[i].resp_retcode = PAM_BUF_ERR;
db6389
+				} else {
db6389
+					memcpy(resp[i].resp, pwstring, pwsize);
db6389
+					resp[i].resp[pwsize] = '\0';
db6389
+					resp[i].resp_retcode = PAM_SUCCESS;
db6389
+				}
db6389
+			} else {
db6389
+				resp[i].resp_retcode = PAM_CONV_ERR;
db6389
+				code = PAM_CONV_ERR;
db6389
+			}
db6389
+			break;
db6389
+		default:
db6389
+			break;
db6389
+		}
db6389
+	}
db6389
+	*presp = resp;
db6389
+	return code;
db6389
+}
db6389
+static int
db6389
+appl_pam_non_interactive_converse(int num_msg,
db6389
+				  const struct pam_message **msg,
db6389
+				  struct pam_response **presp,
db6389
+				  void *appdata_ptr)
db6389
+{
db6389
+	const struct pam_message *message;
db6389
+	struct pam_response *resp;
db6389
+	int i, code;
db6389
+	unsigned int pwsize;
db6389
+	struct appl_pam_non_interactive_args *args;
db6389
+	const char *pwstring;
db6389
+	resp = malloc(sizeof(struct pam_response) * num_msg);
db6389
+	if (resp == NULL) {
db6389
+		return PAM_BUF_ERR;
db6389
+	}
db6389
+	args = appdata_ptr;
db6389
+	memset(resp, 0, sizeof(struct pam_response) * num_msg);
db6389
+	code = PAM_SUCCESS;
db6389
+	for (i = 0; i < num_msg; i++) {
db6389
+		message = &((*msg)[i]);
db6389
+		message = msg[i];
db6389
+		pwstring = NULL;
db6389
+		switch (message->msg_style) {
db6389
+		case PAM_TEXT_INFO:
db6389
+		case PAM_ERROR_MSG:
db6389
+			break;
db6389
+		case PAM_PROMPT_ECHO_ON:
db6389
+		case PAM_PROMPT_ECHO_OFF:
db6389
+			if (message->msg_style == PAM_PROMPT_ECHO_ON) {
db6389
+				/* assume "user" */
db6389
+				pwstring = args->user;
db6389
+			} else {
db6389
+				/* assume "password" */
db6389
+				pwstring = args->password;
db6389
+			}
db6389
+			if ((pwstring != NULL) && (pwstring[0] != '\0')) {
db6389
+				pwsize = strlen(pwstring);
db6389
+				resp[i].resp = malloc(pwsize + 1);
db6389
+				if (resp[i].resp == NULL) {
db6389
+					resp[i].resp_retcode = PAM_BUF_ERR;
db6389
+				} else {
db6389
+					memcpy(resp[i].resp, pwstring, pwsize);
db6389
+					resp[i].resp[pwsize] = '\0';
db6389
+					resp[i].resp_retcode = PAM_SUCCESS;
db6389
+				}
db6389
+			} else {
db6389
+				resp[i].resp_retcode = PAM_CONV_ERR;
db6389
+				code = PAM_CONV_ERR;
db6389
+			}
db6389
+			break;
db6389
+		default:
db6389
+			break;
db6389
+		}
db6389
+	}
db6389
+	*presp = resp;
db6389
+	return code;
db6389
+}
db6389
+static int
db6389
+appl_pam_start(const char *service, int interactive,
db6389
+	       const char *login_username,
db6389
+	       const char *non_interactive_password,
db6389
+	       const char *hostname,
db6389
+	       const char *ruser,
db6389
+	       const char *tty)
db6389
+{
db6389
+	static int exit_handler_registered;
db6389
+	static struct appl_pam_non_interactive_args args;
db6389
+	int ret = 0;
db6389
+	if (appl_pam_started &&
db6389
+	    (strcmp(login_username, appl_pam_user) != 0)) {
db6389
+		appl_pam_cleanup();
db6389
+		appl_pam_user = NULL;
db6389
+	}
db6389
+	if (!appl_pam_started) {
db6389
+#ifdef DEBUG
db6389
+		printf("Starting PAM up (service=\"%s\",user=\"%s\").\n",
db6389
+		       service, login_username);
db6389
+#endif
db6389
+		memset(&appl_pam_conv, 0, sizeof(appl_pam_conv));
db6389
+		appl_pam_conv.conv = interactive ?
db6389
+				     &appl_pam_interactive_converse :
db6389
+				     &appl_pam_non_interactive_converse;
db6389
+		memset(&args, 0, sizeof(args));
db6389
+		args.user = strdup(login_username);
db6389
+		args.password = non_interactive_password ?
db6389
+				strdup(non_interactive_password) :
db6389
+				NULL;
db6389
+		appl_pam_conv.appdata_ptr = &arg;;
db6389
+		ret = pam_start(service, login_username,
db6389
+				&appl_pam_conv, &appl_pamh);
db6389
+		if (ret == 0) {
db6389
+			if (hostname != NULL) {
db6389
+#ifdef DEBUG
db6389
+				printf("Setting PAM_RHOST to \"%s\".\n", hostname);
db6389
+#endif
db6389
+				pam_set_item(appl_pamh, PAM_RHOST, hostname);
db6389
+			}
db6389
+			if (ruser != NULL) {
db6389
+#ifdef DEBUG
db6389
+				printf("Setting PAM_RUSER to \"%s\".\n", ruser);
db6389
+#endif
db6389
+				pam_set_item(appl_pamh, PAM_RUSER, ruser);
db6389
+			}
db6389
+			if (tty != NULL) {
db6389
+#ifdef DEBUG
db6389
+				printf("Setting PAM_TTY to \"%s\".\n", tty);
db6389
+#endif
db6389
+				pam_set_item(appl_pamh, PAM_TTY, tty);
db6389
+			}
db6389
+			if (!exit_handler_registered &&
db6389
+			    (atexit(appl_pam_cleanup) != 0)) {
db6389
+				pam_end(appl_pamh, 0);
db6389
+				appl_pamh = NULL;
db6389
+				ret = -1;
db6389
+			} else {
db6389
+				appl_pam_started = 1;
db6389
+				appl_pam_starter = getpid();
db6389
+				appl_pam_user = strdup(login_username);
db6389
+				exit_handler_registered = 1;
db6389
+			}
db6389
+		}
db6389
+	}
db6389
+	return ret;
db6389
+}
db6389
+int
db6389
+appl_pam_acct_mgmt(const char *service, int interactive,
db6389
+		   const char *login_username,
db6389
+		   const char *non_interactive_password,
db6389
+		   const char *hostname,
db6389
+		   const char *ruser,
db6389
+		   const char *tty)
db6389
+{
db6389
+	int ret;
db6389
+	appl_pam_pwchange_required = 0;
db6389
+	ret = appl_pam_start(service, interactive, login_username,
db6389
+			     non_interactive_password, hostname, ruser, tty);
db6389
+	if (ret == 0) {
db6389
+#ifdef DEBUG
db6389
+		printf("Calling pam_acct_mgmt().\n");
db6389
+#endif
db6389
+		ret = pam_acct_mgmt(appl_pamh, 0);
db6389
+		switch (ret) {
db6389
+		case PAM_IGNORE:
db6389
+			ret = 0;
db6389
+			break;
db6389
+		case PAM_NEW_AUTHTOK_REQD:
db6389
+			appl_pam_pwchange_required = 1;
db6389
+			ret = 0;
db6389
+			break;
db6389
+		default:
db6389
+			break;
db6389
+		}
db6389
+	}
db6389
+	return ret;
db6389
+}
db6389
+int
db6389
+appl_pam_requires_chauthtok(void)
db6389
+{
db6389
+	return appl_pam_pwchange_required;
db6389
+}
db6389
+int
db6389
+appl_pam_session_open(void)
db6389
+{
db6389
+	int ret = 0;
db6389
+	if (appl_pam_started) {
db6389
+#ifdef DEBUG
db6389
+		printf("Opening PAM session.\n");
db6389
+#endif
db6389
+		ret = pam_open_session(appl_pamh, 0);
db6389
+		if (ret == 0) {
db6389
+			appl_pam_session_opened = 1;
db6389
+		}
db6389
+	}
db6389
+	return ret;
db6389
+}
db6389
+int
db6389
+appl_pam_setenv(void)
db6389
+{
db6389
+	int ret = 0;
db6389
+#ifdef HAVE_PAM_GETENVLIST
db6389
+#ifdef HAVE_PUTENV
db6389
+	int i;
db6389
+	char **list;
db6389
+	if (appl_pam_started) {
db6389
+		list = pam_getenvlist(appl_pamh);
db6389
+		for (i = 0; ((list != NULL) && (list[i] != NULL)); i++) {
db6389
+#ifdef DEBUG
db6389
+			printf("Setting \"%s\" in environment.\n", list[i]);
db6389
+#endif
db6389
+			putenv(list[i]);
db6389
+		}
db6389
+	}
db6389
+#endif
db6389
+#endif
db6389
+	return ret;
db6389
+}
db6389
+int
db6389
+appl_pam_cred_init(void)
db6389
+{
db6389
+	int ret = 0;
db6389
+	if (appl_pam_started) {
db6389
+#ifdef DEBUG
db6389
+		printf("Initializing PAM credentials.\n");
db6389
+#endif
db6389
+		ret = pam_setcred(appl_pamh, PAM_ESTABLISH_CRED);
db6389
+		if (ret == 0) {
db6389
+			appl_pam_creds_initialized = 1;
db6389
+		}
db6389
+	}
db6389
+	return ret;
db6389
+}
db6389
+#endif
db6389
diff --git a/src/clients/ksu/pam.h b/src/clients/ksu/pam.h
db6389
new file mode 100644
db6389
index 000000000..0ab76569c
db6389
--- /dev/null
db6389
+++ b/src/clients/ksu/pam.h
db6389
@@ -0,0 +1,57 @@
db6389
+/*
db6389
+ * src/clients/ksu/pam.h
db6389
+ *
db6389
+ * Copyright 2007,2009,2010 Red Hat, Inc.
db6389
+ *
db6389
+ * All Rights Reserved.
db6389
+ *
db6389
+ * Redistribution and use in source and binary forms, with or without
db6389
+ * modification, are permitted provided that the following conditions are met:
db6389
+ *
db6389
+ *  Redistributions of source code must retain the above copyright notice, this
db6389
+ *  list of conditions and the following disclaimer.
db6389
+ *
db6389
+ *  Redistributions in binary form must reproduce the above copyright notice,
db6389
+ *  this list of conditions and the following disclaimer in the documentation
db6389
+ *  and/or other materials provided with the distribution.
db6389
+ *
db6389
+ *  Neither the name of Red Hat, Inc. nor the names of its contributors may be
db6389
+ *  used to endorse or promote products derived from this software without
db6389
+ *  specific prior written permission.
db6389
+ *
db6389
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
db6389
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
db6389
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
db6389
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
db6389
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
db6389
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
db6389
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
db6389
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
db6389
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
db6389
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
db6389
+ * POSSIBILITY OF SUCH DAMAGE.
db6389
+ * 
db6389
+ * Convenience wrappers for using PAM.
db6389
+ */
db6389
+
db6389
+#include <krb5.h>
db6389
+#ifdef HAVE_SECURITY_PAM_APPL_H
db6389
+#include <security/pam_appl.h>
db6389
+#endif
db6389
+
db6389
+#define USE_PAM_CONFIGURATION_KEYWORD "use_pam"
db6389
+
db6389
+#ifdef USE_PAM
db6389
+int appl_pam_enabled(krb5_context context, const char *section);
db6389
+int appl_pam_acct_mgmt(const char *service, int interactive,
db6389
+		       const char *local_username,
db6389
+		       const char *non_interactive_password,
db6389
+		       const char *hostname,
db6389
+		       const char *ruser,
db6389
+		       const char *tty);
db6389
+int appl_pam_requires_chauthtok(void);
db6389
+int appl_pam_session_open(void);
db6389
+int appl_pam_setenv(void);
db6389
+int appl_pam_cred_init(void);
db6389
+void appl_pam_cleanup(void);
db6389
+#endif
db6389
diff --git a/src/configure.in b/src/configure.in
db6389
index 61ef738dc..e9a12ac16 100644
db6389
--- a/src/configure.in
db6389
+++ b/src/configure.in
db6389
@@ -1352,6 +1352,8 @@ AC_SUBST([VERTO_VERSION])
db6389
 
db6389
 AC_PATH_PROG(GROFF, groff)
db6389
 
db6389
+KRB5_WITH_PAM
db6389
+
db6389
 # Make localedir work in autoconf 2.5x.
db6389
 if test "${localedir+set}" != set; then
db6389
     localedir='$(datadir)/locale'