Blame SOURCES/krb5-1.12.1-pam.patch

5af5b2
Modify ksu so that it performs account and session management on behalf of
5af5b2
the target user account, mimicking the action of regular su.  The default
5af5b2
service name is "ksu", because on Fedora at least the configuration used
5af5b2
is determined by whether or not a login shell is being opened, and so
5af5b2
this may need to vary, too.  At run-time, ksu's behavior can be reset to
5af5b2
the earlier, non-PAM behavior by setting "use_pam" to false in the [ksu]
5af5b2
section of /etc/krb5.conf.
5af5b2
5af5b2
When enabled, ksu gains a dependency on libpam.
5af5b2
5af5b2
Originally RT#5939, though it's changed since then to perform the account
5af5b2
and session management before dropping privileges, and to apply on top of
5af5b2
changes we're proposing for how it handles cache collections.
5af5b2
4be148
diff -up krb5/src/aclocal.m4.pam krb5/src/aclocal.m4
4be148
--- krb5/src/aclocal.m4.pam	2009-11-22 12:00:45.000000000 -0500
4be148
+++ krb5/src/aclocal.m4	2010-03-05 10:48:08.000000000 -0500
5af5b2
@@ -1703,3 +1703,70 @@ AC_DEFUN(KRB5_AC_KEYRING_CCACHE,[
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
4be148
diff -up krb5/src/clients/ksu/main.c.pam krb5/src/clients/ksu/main.c
4be148
--- krb5/src/clients/ksu/main.c.pam	2009-11-02 22:27:56.000000000 -0500
4be148
+++ krb5/src/clients/ksu/main.c	2010-03-05 10:48:08.000000000 -0500
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"
4be148
@@ -586,6 +592,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 "
4be148
@@ -651,6 +676,24 @@
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){
4be148
@@ -720,6 +745,30 @@
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");
5af5b2
@@ -792,7 +817,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);
5af5b2
@@ -823,16 +875,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
     }
4be148
diff -up krb5/src/clients/ksu/Makefile.in.pam krb5/src/clients/ksu/Makefile.in
4be148
--- krb5/src/clients/ksu/Makefile.in.pam	2009-11-22 13:13:29.000000000 -0500
4be148
+++ krb5/src/clients/ksu/Makefile.in	2010-03-05 11:55:14.000000000 -0500
5af5b2
@@ -7,12 +7,14 @@
4be148
 DEFINES = -DGET_TGT_VIA_PASSWD -DPRINC_LOOK_AHEAD -DCMD_PATH='"/bin /local/bin"'
5af5b2
 
5af5b2
 KSU_LIBS=@KSU_LIBS@
5af5b2
+PAM_LIBS=@PAM_LIBS@
5af5b2
 
5af5b2
 SRCS = \
5af5b2
 	$(srcdir)/krb_auth_su.c \
5af5b2
 	$(srcdir)/ccache.c \
5af5b2
 	$(srcdir)/authorization.c \
5af5b2
 	$(srcdir)/main.c \
5af5b2
+	$(srcdir)/pam.c \
5af5b2
 	$(srcdir)/heuristic.c \
5af5b2
 	$(srcdir)/xmalloc.c \
5af5b2
 	$(srcdir)/setenv.c
5af5b2
@@ -21,13 +23,17 @@ OBJS = \
5af5b2
 	ccache.o \
5af5b2
 	authorization.o \
5af5b2
 	main.o \
5af5b2
+	pam.o \
5af5b2
 	heuristic.o \
5af5b2
 	xmalloc.o @SETENVOBJ@
5af5b2
 
5af5b2
 all:: ksu
5af5b2
 
5af5b2
 ksu: $(OBJS) $(KRB5_BASE_DEPLIBS)
5af5b2
-	$(CC_LINK) -o $@ $(OBJS) $(KRB5_BASE_LIBS) $(KSU_LIBS)
5af5b2
+	$(CC_LINK) -o $@ $(OBJS) $(KRB5_BASE_LIBS) $(KSU_LIBS) $(PAM_LIBS)
5af5b2
+
5af5b2
+pam.o: pam.c
5af5b2
+	$(CC) $(ALL_CFLAGS) -c $<
5af5b2
 
5af5b2
 clean::
5af5b2
 	$(RM) ksu
4be148
diff -up krb5/src/clients/ksu/pam.c.pam krb5/src/clients/ksu/pam.c
4be148
--- krb5/src/clients/ksu/pam.c.pam	2010-03-05 10:48:08.000000000 -0500
4be148
+++ krb5/src/clients/ksu/pam.c	2010-03-05 10:48:08.000000000 -0500
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
4be148
diff -up krb5/src/clients/ksu/pam.h.pam krb5/src/clients/ksu/pam.h
4be148
--- krb5/src/clients/ksu/pam.h.pam	2010-03-05 10:48:08.000000000 -0500
4be148
+++ krb5/src/clients/ksu/pam.h	2010-03-05 10:48:08.000000000 -0500
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
4be148
diff -up krb5/src/configure.in.pam krb5/src/configure.in
4be148
--- krb5/src/configure.in.pam	2009-12-31 18:13:56.000000000 -0500
4be148
+++ krb5/src/configure.in	2010-03-05 10:48:08.000000000 -0500
5af5b2
@@ -1051,6 +1051,8 @@ if test "$ac_cv_lib_socket" = "yes" -a "
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'