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