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