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