Blame SOURCES/downstream-ksu-pam-integration.patch

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