Sophie

Sophie

distrib > Mageia > 7 > i586 > media > core-updates-src > by-pkgid > efd2b5e02e2a1d5a5cf4680987a2f162 > files > 22

krb5-appl-1.0.3-10.1.mga7.src.rpm

diff -Naur -x '*~' -x '*.orig' -x '*.rej' krb5-appl-1.0.2/aclocal.m4 krb5-appl-1.0.2-pam//aclocal.m4
--- krb5-appl-1.0.2/aclocal.m4	2009-11-21 21:29:19.000000000 +0100
+++ krb5-appl-1.0.2-pam//aclocal.m4	2011-07-18 13:44:19.000000000 +0200
@@ -486,3 +486,82 @@
   UTIL_LIB=-lutil])dnl
 AC_SUBST(UTIL_LIB)
 ])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-login-service,[AC_HELP_STRING(--with-login-service,[PAM service name for login ["login"]])],
+	    withloginpamservice="$withval",withloginpamservice=login)
+AC_ARG_WITH(pam-kshell-service,[AC_HELP_STRING(--with-kshell-service,[PAM service name for unencrypted rsh ["kshell"]])],
+	    withkshellpamservice="$withval",withkshellpamservice=kshell)
+AC_ARG_WITH(pam-ekshell-service,[AC_HELP_STRING(--with-ekshell-service,[PAM service name for encrypted rsh ["ekshell"]])],
+	    withekshellpamservice="$withval",withekshellpamservice=ekshell)
+AC_ARG_WITH(pam-ftp-service,[AC_HELP_STRING(--with-ftp-service,[PAM service name for ftpd ["gssftp"]])],
+	    withftppamservice="$withval",withftppamservice=gssftp)
+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(LOGIN_PAM_SERVICE,"$withloginpamservice",
+				   [Define to the name of the PAM service name to be used by login.])
+		AC_DEFINE_UNQUOTED(KSHELL_PAM_SERVICE,"$withkshellpamservice",
+				   [Define to the name of the PAM service name to be used by rshd for unencrypted sessions.])
+		AC_DEFINE_UNQUOTED(EKSHELL_PAM_SERVICE,"$withekshellpamservice",
+				   [Define to the name of the PAM service name to be used by rshd for encrypted sessions.])
+		AC_DEFINE_UNQUOTED(FTP_PAM_SERVICE,"$withftppamservice",
+				   [Define to the name of the PAM service name to be used by ftpd.])
+		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 -Naur -x '*~' -x '*.orig' -x '*.rej' krb5-appl-1.0.2/bsd/krshd.c krb5-appl-1.0.2-pam//bsd/krshd.c
--- krb5-appl-1.0.2/bsd/krshd.c	2011-07-11 21:31:31.000000000 +0200
+++ krb5-appl-1.0.2-pam//bsd/krshd.c	2011-07-18 13:44:19.000000000 +0200
@@ -163,6 +163,10 @@
 #include <arpa/nameser.h>
 #endif
 
+#ifdef USE_PAM
+#include "pam.h"
+#endif
+
 #ifndef MAXDNAME
 #define MAXDNAME 256 /*per the rfc*/
 #endif
@@ -190,6 +194,7 @@
 
 int require_encrypt = 0;
 int do_encrypt = 0;
+int force_fork = 0;
 int anyport = 0;
 char *kprogdir = KPROGDIR;
 int netf;
@@ -1044,14 +1049,6 @@
     }
 #endif /*CRAY*/
     
-    if (chdir(pwd->pw_dir) < 0) {
-      if(chdir("/") < 0) {
-      	error("No remote directory.\n");
-	goto signout_please;
-      }
-	   pwd->pw_dir = "/";
-    }
-
 #ifdef KERBEROS
     /* krb5_kuserok returns 1 if OK */
     if (!krb5_kuserok(bsd_context, client, locuser)){
@@ -1081,11 +1078,51 @@
 	goto signout_please;
     }
     
+#ifdef USE_PAM
+    if (appl_pam_enabled(bsd_context, "rshd")) {
+        if (appl_pam_acct_mgmt(do_encrypt ?
+			       EKSHELL_PAM_SERVICE :
+			       KSHELL_PAM_SERVICE,
+			       0,
+			       locuser,
+			       "",
+			       hostname,
+			       NULL,
+			       do_encrypt ?
+			       EKSHELL_PAM_SERVICE :
+			       KSHELL_PAM_SERVICE) != 0) {
+	    error("Login denied.\n");
+	    goto signout_please;
+        }
+        if (appl_pam_requires_chauthtok()) {
+	    error("Password change required, but not possible over rsh.\n");
+	    goto signout_please;
+        }
+        force_fork = 1;
+        appl_pam_set_forwarded_ccname(getenv("KRB5CCNAME"));
+        if (appl_pam_session_open() != 0) {
+	    error("Login failure.\n");
+	    goto signout_please;
+        }
+        if (appl_pam_cred_init()) {
+	    error("Login failure.\n");
+	    goto signout_please;
+        }
+    } else
+#endif
     if (pwd->pw_uid && !access(NOLOGIN, F_OK)) {
 	error("Logins currently disabled.\n");
 	goto signout_please;
     }
     
+    if (chdir(pwd->pw_dir) < 0) {
+	if (chdir("/") < 0) {
+	    error("No remote directory.\n");
+	    goto signout_please;
+	}
+	pwd->pw_dir = "/";
+    }
+
     /* Log access to account */
     pwd = (struct passwd *) getpwnam(locuser);
     if (pwd && (pwd->pw_uid == 0)) {
@@ -1125,7 +1162,7 @@
     
     (void) write(2, "", 1);
     
-    if (port||do_encrypt) {
+    if (port||do_encrypt||force_fork) {
 	if (port&&(pipe(pv) < 0)) {
 	    error("Can't make pipe.\n");
 	    goto signout_please;
@@ -1430,6 +1467,15 @@
 
     environ = envinit;
     
+#ifdef USE_PAM
+    if (appl_pam_enabled(bsd_context, "rshd")) {
+        if (appl_pam_setenv() != 0) {
+	    error("Login failure.\n");
+	    goto signout_please;
+        }
+    }
+#endif
+
 #ifdef KERBEROS
     /* To make Kerberos rcp work correctly, we must ensure that we
        invoke Kerberos rcp on this end, not normal rcp, even if the
diff -Naur -x '*~' -x '*.orig' -x '*.rej' krb5-appl-1.0.2/bsd/login.c krb5-appl-1.0.2-pam//bsd/login.c
--- krb5-appl-1.0.2/bsd/login.c	2011-07-11 21:30:25.000000000 +0200
+++ krb5-appl-1.0.2-pam//bsd/login.c	2011-07-18 13:44:19.000000000 +0200
@@ -156,6 +156,11 @@
 #define KRB5_ENV_CCNAME "KRB5CCNAME"
 #endif /* KRB5_GET_TICKETS */
 
+#ifdef USE_PAM
+#include "pam.h"
+int login_use_pam = 1;
+#endif
+
 #ifndef __STDC__
 #ifndef volatile
 #define volatile
@@ -301,6 +306,9 @@
     char *flagname;
     int *flag;
 } login_conf_set[] = {
+#ifdef USE_PAM
+    {USE_PAM_CONFIGURATION_KEYWORD, &login_use_pam},
+#endif
 #ifdef KRB5_GET_TICKETS
     {"krb5_get_tickets", &login_krb5_get_tickets},
     {"krb_run_aklog", &login_krb_run_aklog},
@@ -942,6 +950,21 @@
 	if (!unix_needs_passwd())
 	    break;
 
+#ifdef USE_PAM
+	if (login_use_pam) {
+	    if (appl_pam_authenticate(LOGIN_PAM_SERVICE, 1, username, "",
+				      hostname,
+				      NULL,
+				      ttyname(STDIN_FILENO)) == PAM_SUCCESS) {
+		break;
+	    } else {
+		/* the goto target label is in a different nesting scope, but
+		 * it's roughly where we want to land */
+		goto bad_login;
+	    }
+	}
+#endif
+
 #ifdef KRB5_GET_TICKETS
 	if (login_krb5_get_tickets) {
 	    /* rename these to something more verbose */
@@ -1029,6 +1052,24 @@
     /* committed to login -- turn off timeout */
     (void) alarm((u_int) 0);
 
+#ifdef USE_PAM
+    if (login_use_pam) {
+	if (appl_pam_acct_mgmt(LOGIN_PAM_SERVICE, 1, username, "",
+			       hostname, NULL, ttyname(STDIN_FILENO)) != 0) {
+	    printf("Login incorrect\n");
+	    sleepexit(1);
+	}
+	if (appl_pam_requires_chauthtok()) {
+	    if (appl_pam_chauthtok() != 0) {
+		printf("Failed to change password.\n");
+		sleepexit(1);
+	    }
+	}
+    } else {
+	/* the "else" here is the non-PAM behavior which continues until the
+	 * next ifdef USE_PAM block, as of this writing more or less
+	 * duplicating the work of pam_securetty and an OQUOTA check */
+#endif
     /*
      * If valid so far and root is logging in, see if root logins on
      * this terminal are permitted.
@@ -1069,6 +1110,21 @@
 	sleepexit(0);
     }
 #endif
+#ifdef USE_PAM
+    }
+#endif /* USE_PAM */
+
+#ifdef USE_PAM
+    if (login_use_pam) {
+	appl_pam_set_forwarded_ccname(getenv("KRB5CCNAME"));
+	if (appl_pam_session_open() != 0) {
+	    sleepexit(1);
+	}
+	if (appl_pam_cred_init() != 0) {
+	    sleepexit(1);
+	}
+    }
+#endif /* USE_PAM */
 
     if (chdir(pwd->pw_dir) < 0) {
 	printf("No directory %s!\n", pwd->pw_dir);
@@ -1351,6 +1407,11 @@
     }
 #endif /* KRB5_GET_TICKETS */
 
+#ifdef USE_PAM
+    if (login_use_pam)
+	appl_pam_setenv();
+#endif
+
     if (tty[sizeof("tty")-1] == 'd')
 	syslog(LOG_INFO, "DIALUP %s, %s", tty, pwd->pw_name);
     if (pwd->pw_uid == 0)
diff -Naur -x '*~' -x '*.orig' -x '*.rej' krb5-appl-1.0.2/bsd/Makefile.in krb5-appl-1.0.2-pam//bsd/Makefile.in
--- krb5-appl-1.0.2/bsd/Makefile.in	2009-11-05 21:10:37.000000000 +0100
+++ krb5-appl-1.0.2-pam//bsd/Makefile.in	2011-07-18 13:44:19.000000000 +0200
@@ -3,11 +3,14 @@
 
 LOGINLIBS=@LOGINLIBS@
 KRSHDLIBS=@KRSHDLIBS@
+PAMOBJS=pam.o
+PAM_LIBS=@PAM_LIBS@
 
 SRCS= $(srcdir)/krcp.c $(srcdir)/krlogin.c $(srcdir)/krsh.c $(srcdir)/kcmd.c \
 	$(srcdir)/forward.c $(srcdir)/login.c $(srcdir)/krshd.c \
 	$(srcdir)/krlogind.c
-OBJS= krcp.o krlogin.o krsh.o kcmd.o forward.o login.o krshd.o krlogind.o
+OBJS= krcp.o krlogin.o krsh.o kcmd.o forward.o login.o krshd.o krlogind.o \
+	$(PAMOBJS)
 
 UCB_RLOGIN = @UCB_RLOGIN@
 UCB_RSH = @UCB_RSH@
@@ -50,8 +53,8 @@
 	  ) || exit 1; \
 	done
 
-kshd: krshd.o kcmd.o forward.o $(PTY_DEPLIB) $(MISSING_DEPLIB)
-	$(CC_LINK) -o kshd krshd.o kcmd.o forward.o $(KRSHDLIBS) $(PTY_LIB) $(UTIL_LIB) $(MISSING_LIB) $(KRB5_BASE_LIBS) $(LIBS)
+kshd: krshd.o kcmd.o forward.o $(PAMOBJS) $(PTY_DEPLIB) $(MISSING_DEPLIB)
+	$(CC_LINK) -o kshd krshd.o kcmd.o forward.o $(PAMOBJS) $(KRSHDLIBS) $(PTY_LIB) $(UTIL_LIB) $(MISSING_LIB) $(KRB5_BASE_LIBS) $(PAM_LIBS) $(LIBS)
 
 klogind: krlogind.o kcmd.o forward.o $(PTY_DEPLIB) $(MISSING_DEPLIB)
 	$(CC_LINK) -o klogind krlogind.o kcmd.o forward.o $(PTY_LIB) $(UTIL_LIB) $(MISSING_LIB) $(KRB5_BASE_LIBS) $(LIBS)
@@ -68,8 +71,8 @@
 # No program name transformation is done with login.krb5 since it is directly
 # referenced by klogind.
 #
-login.krb5: login.o $(PTY_DEPLIB) $(MISSING_DEPLIB)
-	$(CC_LINK) -o login.krb5 login.o $(LOGINLIBS) $(PTY_LIB) $(KRB5_BASE_LIBS) $(MISSING_LIB) $(LIBS)
+login.krb5: login.o $(PAMOBJS) $(PTY_DEPLIB) $(MISSING_DEPLIB)
+	$(CC_LINK) -o login.krb5 login.o $(PAMOBJS) $(LOGINLIBS) $(PTY_LIB) $(KRB5_BASE_LIBS) $(MISSING_LIB) $(PAM_LIBS) $(LIBS)
 
 install::
 	$(INSTALL_PROGRAM) login.krb5 $(DESTDIR)$(SERVER_BINDIR)/login.krb5
diff -Naur -x '*~' -x '*.orig' -x '*.rej' krb5-appl-1.0.2/bsd/pam.c krb5-appl-1.0.2-pam//bsd/pam.c
--- krb5-appl-1.0.2/bsd/pam.c	1970-01-01 01:00:00.000000000 +0100
+++ krb5-appl-1.0.2-pam//bsd/pam.c	2011-07-18 13:44:19.000000000 +0200
@@ -0,0 +1,438 @@
+/*
+ * src/appl/bsd/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 <profile.h>
+#include "pam.h"
+
+#ifndef MAXPWSIZE
+#define MAXPWSIZE 128
+#endif
+
+#ifndef KRB5_ENV_CCNAME
+#define KRB5_ENV_CCNAME "KRB5CCNAME"
+#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;
+	profile_t profile = NULL;
+	if ((context != NULL) && (krb5_get_profile(context, &profile) == 0)) {
+		if (profile_get_boolean(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;
+}
+void
+appl_pam_set_forwarded_ccname(const char *ccname)
+{
+	char *ccname2;
+	if (appl_pam_started && (ccname != NULL) && (strlen(ccname) > 0)) {
+		ccname2 = malloc(strlen(KRB5_ENV_CCNAME) + strlen(ccname) + 2);
+		if (ccname2 != NULL) {
+#ifdef DEBUG
+			printf("Setting %s to \"%s\" in PAM environment.\n",
+			       KRB5_ENV_CCNAME, ccname);
+#endif
+			sprintf(ccname2, "%s=%s", KRB5_ENV_CCNAME, ccname);
+			pam_putenv(appl_pamh, ccname2);
+		}
+	}
+}
+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_authenticate(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;
+	ret = appl_pam_start(service, interactive, login_username,
+			     non_interactive_password, hostname, ruser, tty);
+	if (ret == 0) {
+		ret = pam_authenticate(appl_pamh, 0);
+	}
+	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_chauthtok(void)
+{
+	int ret = 0;
+	if (appl_pam_started) {
+#ifdef DEBUG
+		printf("Changing PAM expired authentication token.\n");
+#endif
+		ret = pam_chauthtok(appl_pamh, PAM_CHANGE_EXPIRED_AUTHTOK);
+	}
+	return ret;
+}
+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 -Naur -x '*~' -x '*.orig' -x '*.rej' krb5-appl-1.0.2/bsd/pam.h krb5-appl-1.0.2-pam//bsd/pam.h
--- krb5-appl-1.0.2/bsd/pam.h	1970-01-01 01:00:00.000000000 +0100
+++ krb5-appl-1.0.2-pam//bsd/pam.h	2011-07-18 13:44:19.000000000 +0200
@@ -0,0 +1,65 @@
+/*
+ * src/appl/bsd/pam.h
+ *
+ * Copyright 2007,2009 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_authenticate(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_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_chauthtok(void);
+void appl_pam_set_forwarded_ccname(const char *ccname);
+int appl_pam_session_open(void);
+int appl_pam_setenv(void);
+int appl_pam_cred_init(void);
+void appl_pam_cleanup(void);
+#endif
diff -Naur -x '*~' -x '*.orig' -x '*.rej' krb5-appl-1.0.2/configure.ac krb5-appl-1.0.2-pam//configure.ac
--- krb5-appl-1.0.2/configure.ac	2011-07-11 21:34:17.000000000 +0200
+++ krb5-appl-1.0.2-pam//configure.ac	2011-07-18 13:44:19.000000000 +0200
@@ -162,6 +162,8 @@
               [AC_MSG_ERROR([Could not find tgetent; are you missing a curses/ncurses library?])])
 LIBS="$old_LIBS"
 
+KRB5_WITH_PAM
+
 # Make our operating system-specific security checks and definitions
 # for libpty, login, and ftpd.  The following code decides what
 # streams modules will be pushed onto a pty.  In particular, if
diff -Naur -x '*~' -x '*.orig' -x '*.rej' krb5-appl-1.0.2/gssftp/ftpd/ftpd.c krb5-appl-1.0.2-pam//gssftp/ftpd/ftpd.c
--- krb5-appl-1.0.2/gssftp/ftpd/ftpd.c	2011-07-11 21:33:58.000000000 +0200
+++ krb5-appl-1.0.2-pam//gssftp/ftpd/ftpd.c	2011-07-18 13:44:19.000000000 +0200
@@ -69,6 +69,9 @@
 #ifdef HAVE_SHADOW
 #include <shadow.h>
 #endif
+#ifdef USE_PAM
+#include "../../bsd/pam.h"
+#endif
 #include <grp.h> 
 #include <setjmp.h>
 #ifndef POSIX_SETJMP
@@ -751,6 +754,22 @@
 				name);
 		}
 #endif /* GSSAPI */
+#ifdef USE_PAM
+		if (appl_pam_enabled(kcontext, "ftpd")) {
+			if (appl_pam_acct_mgmt(FTP_PAM_SERVICE, 0,
+					       name, "",
+					       hostname,
+					       NULL,
+					       FTP_PAM_SERVICE) != 0) {
+					       reply(530, "Login incorrect.");
+				return;
+			}
+			if (appl_pam_requires_chauthtok()) {
+				reply(530, "Password change required.");
+				return;
+			}
+		}
+#endif
 
 		if (!authorized && authlevel == AUTHLEVEL_AUTHORIZE) {
 			strncat(buf, "; Access denied.",
@@ -851,6 +870,10 @@
 	(void) krb5_seteuid((uid_t)0);
 	if (logged_in)
 		pty_logwtmp(ttyline, "", "");
+#ifdef USE_PAM
+	if (appl_pam_enabled(kcontext, "ftpd"))
+		appl_pam_cleanup();
+#endif
 	if (have_creds) {
 #ifdef GSSAPI
 		krb5_cc_destroy(kcontext, ccache);
@@ -959,9 +982,19 @@
 		 *   kpass fails and the user has no local password
 		 *   kpass fails and the provided password doesn't match pw
 		 */
-		if (pw == NULL || (!kpass(pw->pw_name, passwd) &&
-				   (want_creds || !*pw->pw_passwd ||
-				    strcmp(xpasswd, pw->pw_passwd)))) {
+		if ((pw == NULL) || (
+#ifdef USE_PAM
+		    appl_pam_enabled(kcontext, "ftpd") ?
+		    (appl_pam_authenticate(FTP_PAM_SERVICE, 0,
+					   pw->pw_name, passwd,
+					   hostname,
+					   NULL,
+					   FTP_PAM_SERVICE) != 0) :
+#endif
+		    (!kpass(pw->pw_name, passwd) &&
+		     (want_creds ||
+		      !*pw->pw_passwd ||
+		      strcmp(xpasswd, pw->pw_passwd))))) {
 			pw = NULL;
 			sleep(5);
 			if (++login_attempts >= 3) {
@@ -978,6 +1011,23 @@
 	}
 	login_attempts = 0;		/* this time successful */
 
+#ifdef USE_PAM
+	if (appl_pam_enabled(kcontext, "ftpd")) {
+		if (appl_pam_acct_mgmt(FTP_PAM_SERVICE, 0,
+				       pw->pw_name, passwd,
+				       hostname,
+				       NULL,
+				       FTP_PAM_SERVICE) != 0) {
+			reply(530, "Login incorrect.");
+			return;
+		}
+		if (appl_pam_requires_chauthtok()) {
+			reply(530, "Password change required.");
+			return;
+		}
+	}
+#endif
+
 	login(passwd, 0);
 	return;
 }
@@ -993,6 +1043,18 @@
 		chown(ccname, pw->pw_uid, pw->pw_gid);
 #endif
 	}
+#ifdef USE_PAM
+	if (appl_pam_enabled(kcontext, "ftpd")) {
+		if (appl_pam_session_open() != 0) {
+			reply(550, "Can't open PAM session.");
+			goto bad;
+		}
+		if (appl_pam_cred_init() != 0) {
+			reply(550, "Can't establish PAM credentials.");
+			goto bad;
+		}
+	}
+#endif
 
 	if (setgid((gid_t)pw->pw_gid) < 0) {
 		reply(550, "Can't set gid.");
@@ -1980,6 +2042,10 @@
 		krb5_cc_destroy(kcontext, ccache);
 #endif
 	}
+#ifdef USE_PAM
+	if (appl_pam_enabled(kcontext, "ftpd"))
+		appl_pam_cleanup();
+#endif
 	/* beware of flushing buffers after a SIGPIPE */
 	_exit(status);
 }
diff -Naur -x '*~' -x '*.orig' -x '*.rej' krb5-appl-1.0.2/gssftp/ftpd/Makefile.in krb5-appl-1.0.2-pam//gssftp/ftpd/Makefile.in
--- krb5-appl-1.0.2/gssftp/ftpd/Makefile.in	2009-07-20 19:21:24.000000000 +0200
+++ krb5-appl-1.0.2-pam//gssftp/ftpd/Makefile.in	2011-07-18 13:44:19.000000000 +0200
@@ -6,22 +6,24 @@
 PROG_RPATH=$(KRB5_LIBDIR)
 
 FTPD_LIBS=@FTPD_LIBS@
+PAM_LIBS=@PAM_LIBS@
 
 SRCS	= $(srcdir)/ftpd.c ftpcmd.c $(srcdir)/popen.c \
 	  $(srcdir)/vers.c \
 	  $(srcdir)/../ftp/glob.c \
 	  $(srcdir)/../ftp/radix.c \
-	  $(srcdir)/../ftp/secure.c
+	  $(srcdir)/../ftp/secure.c \
+	  $(srcdir)/../../bsd/pam.c
 
 OBJS	= ftpd.o ftpcmd.o glob.o popen.o vers.o radix.o \
-	  secure.o
+	  secure.o pam.o
 
 LOCALINCLUDES = -I$(srcdir)/.. -I$(srcdir)
 
 all::	ftpd
 
 ftpd:	$(OBJS) $(PTY_DEPLIB) $(MISSING_DEPLIB)
-	$(CC_LINK) -o $@ $(OBJS) $(FTPD_LIBS) $(PTY_LIB) $(UTIL_LIB) $(MISSING_LIB) $(GSS_LIBS) $(LIBS)
+	$(CC_LINK) -o $@ $(OBJS) $(FTPD_LIBS) $(PTY_LIB) $(UTIL_LIB) $(MISSING_LIB) $(GSS_LIBS) $(PAM_LIBS) $(LIBS)
 
 generate-files-mac: ftpcmd.c
 
@@ -61,4 +63,7 @@
 popen.o: $(srcdir)/popen.c
 vers.o: $(srcdir)/vers.c
 
+pam.o: $(srcdir)/../../bsd/pam.c
+	$(CC) -c $(ALL_CFLAGS) $(srcdir)/../../bsd/pam.c
+
 # NOPOSTFIX