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

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