Ondřej Vašík 917089
From ea2d050b1952feb99f86c98255280beb6e589d8c Mon Sep 17 00:00:00 2001
Ondřej Vašík 917089
From: Ludwig Nussel <ludwig.nussel@suse.de>
Ondřej Vašík 917089
Date: Tue, 17 Aug 2010 13:21:44 +0200
Ondřej Vašík 917089
Subject: [PATCH 1/7] pam support for su
Ondřej Vašík 917089
Ondřej Vašík 917089
---
Ondřej Vašík 917089
 configure.ac    |   14 +++
Ondřej Vašík 917089
 src/Makefile.am |    4 +-
Ondřej Vašík 917089
 src/su.c        |  266 ++++++++++++++++++++++++++++++++++++++++++++++++++++++-
Ondřej Vašík 917089
 3 files changed, 278 insertions(+), 6 deletions(-)
Ondřej Vašík 917089
Ondřej Vašík 917089
diff --git a/configure.ac b/configure.ac
Ondřej Vašík 917089
index b07a52b..1fb5839 100644
Ondřej Vašík 917089
--- a/configure.ac
Ondřej Vašík 917089
+++ b/configure.ac
Ondřej Vašík 917089
@@ -128,6 +128,20 @@ fi
Ondřej Vašík 917089
 
Ondřej Vašík 917089
 AC_FUNC_FORK
Ondřej Vašík 917089
 
Ondřej Vašík 917089
+AC_ARG_ENABLE(pam, AS_HELP_STRING([--disable-pam],
Ondřej Vašík 917089
+	[Disable PAM support in su (default=auto)]), , [enable_pam=yes])
Ondřej Vašík 917089
+if test "x$enable_pam" != xno; then
Ondřej Vašík 917089
+  AC_CHECK_LIB([pam], [pam_start], [enable_pam=yes], [enable_pam=no])
Ondřej Vašík 917089
+  AC_CHECK_LIB([pam_misc], [misc_conv], [:], [enable_pam=no])
Ondřej Vašík 917089
+  if test "x$enable_pam" != xno; then
Ondřej Vašík 917089
+    AC_DEFINE(USE_PAM, 1, [Define if you want to use PAM])
Ondřej Vašík 917089
+    PAM_LIBS="-lpam -lpam_misc"
Ondřej Vašík 917089
+    AC_SUBST(PAM_LIBS)
Ondřej Vašík 917089
+  fi
Ondřej Vašík 917089
+fi
Ondřej Vašík 917089
+AC_MSG_CHECKING([whether to enable PAM support in su])
Ondřej Vašík 917089
+AC_MSG_RESULT([$enable_pam])
Ondřej Vašík 917089
+
Ondřej Vašík 917089
 optional_bin_progs=
Ondřej Vašík 917089
 AC_CHECK_FUNCS([chroot],
Ondřej Vašík 917089
         gl_ADD_PROG([optional_bin_progs], [chroot]))
Ondřej Vašík 917089
diff --git a/src/Makefile.am b/src/Makefile.am
Ondřej Vašík 917089
index db5359b..154a5ed 100644
Ondřej Vašík 917089
--- a/src/Makefile.am
Ondřej Vašík 917089
+++ b/src/Makefile.am
Ondřej Vašík 917089
@@ -363,8 +363,8 @@ factor_LDADD += $(LIB_GMP)
Ondřej Vašík 917089
 # for getloadavg
Ondřej Vašík 917089
 uptime_LDADD += $(GETLOADAVG_LIBS)
Ondřej Vašík 917089
 
Ondřej Vašík 917089
-# for crypt
Ondřej Vašík 917089
-su_LDADD += $(LIB_CRYPT)
Ondřej Vašík 917089
+# for crypt and pam
Ondřej Vašík 917089
+su_LDADD += $(LIB_CRYPT) $(PAM_LIBS)
Ondřej Vašík 917089
 
Ondřej Vašík 917089
 # for various ACL functions
Ondřej Vašík 917089
 copy_LDADD += $(LIB_ACL)
Ondřej Vašík 917089
diff --git a/src/su.c b/src/su.c
Ondřej Vašík 917089
index f8f5b61..811aad7 100644
Ondřej Vašík 917089
--- a/src/su.c
Ondřej Vašík 917089
+++ b/src/su.c
Ondřej Vašík 917089
@@ -37,6 +37,16 @@
Ondřej Vašík 917089
    restricts who can su to UID 0 accounts.  RMS considers that to
Ondřej Vašík 917089
    be fascist.
Ondřej Vašík 917089
 
Ondřej Vašík 917089
+#ifdef USE_PAM
Ondřej Vašík 917089
+
Ondřej Vašík 917089
+   Actually, with PAM, su has nothing to do with whether or not a
Ondřej Vašík 917089
+   wheel group is enforced by su.  RMS tries to restrict your access
Ondřej Vašík 917089
+   to a su which implements the wheel group, but PAM considers that
Ondřej Vašík 917089
+   to be fascist, and gives the user/sysadmin the opportunity to
Ondřej Vašík 917089
+   enforce a wheel group by proper editing of /etc/pam.d/su
Ondřej Vašík 917089
+
Ondřej Vašík 917089
+#endif
Ondřej Vašík 917089
+
Ondřej Vašík 917089
    Compile-time options:
Ondřej Vašík 917089
    -DSYSLOG_SUCCESS	Log successful su's (by default, to root) with syslog.
Ondřej Vašík 917089
    -DSYSLOG_FAILURE	Log failed su's (by default, to root) with syslog.
Ondřej Vašík 917089
@@ -52,6 +62,13 @@
Ondřej Vašík 917089
 #include <sys/types.h>
Ondřej Vašík 917089
 #include <pwd.h>
Ondřej Vašík 917089
 #include <grp.h>
Ondřej Vašík 917089
+#ifdef USE_PAM
Ondřej Vašík 917089
+#include <security/pam_appl.h>
Ondřej Vašík 917089
+#include <security/pam_misc.h>
Ondřej Vašík 917089
+#include <signal.h>
Ondřej Vašík 917089
+#include <sys/wait.h>
Ondřej Vašík 917089
+#include <sys/fsuid.h>
Ondřej Vašík 917089
+#endif
Ondřej Vašík 917089
 
Ondřej Vašík 917089
 #include "system.h"
Ondřej Vašík 917089
 #include "getpass.h"
Ondřej Vašík 917089
@@ -111,7 +128,9 @@
Ondřej Vašík 917089
 /* The user to become if none is specified.  */
Ondřej Vašík 917089
 #define DEFAULT_USER "root"
Ondřej Vašík 917089
 
Ondřej Vašík 917089
+#ifndef USE_PAM
Ondřej Vašík 917089
 char *crypt (char const *key, char const *salt);
Ondřej Vašík 917089
+#endif
Ondřej Vašík 917089
 
Ondřej Vašík 917089
 static void run_shell (char const *, char const *, char **, size_t)
Ondřej Vašík 917089
      ATTRIBUTE_NORETURN;
Ondřej Vašík 917089
@@ -125,6 +144,11 @@ static bool simulate_login;
Ondřej Vašík 917089
 /* If true, change some environment vars to indicate the user su'd to.  */
Ondřej Vašík 917089
 static bool change_environment;
Ondřej Vašík 917089
 
Ondřej Vašík 917089
+#ifdef USE_PAM
Ondřej Vašík 917089
+static bool _pam_session_opened;
Ondřej Vašík 917089
+static bool _pam_cred_established;
Ondřej Vašík 917089
+#endif
Ondřej Vašík 917089
+
Ondřej Vašík 917089
 static struct option const longopts[] =
Ondřej Vašík 917089
 {
Ondřej Vašík 917089
   {"command", required_argument, NULL, 'c'},
Ondřej Vašík 917089
@@ -200,7 +224,164 @@ log_su (struct passwd const *pw, bool successful)
Ondřej Vašík 917089
 }
Ondřej Vašík 917089
 #endif
Ondřej Vašík 917089
 
Ondřej Vašík 917089
+#ifdef USE_PAM
Ondřej Vašík 917089
+#define PAM_SERVICE_NAME PROGRAM_NAME
Ondřej Vašík 917089
+#define PAM_SERVICE_NAME_L PROGRAM_NAME "-l"
Ondřej Vašík 917089
+static sig_atomic_t volatile caught_signal = false;
Ondřej Vašík 917089
+static pam_handle_t *pamh = NULL;
Ondřej Vašík 917089
+static int retval;
Ondřej Vašík 917089
+static struct pam_conv conv =
Ondřej Vašík 917089
+{
Ondřej Vašík 917089
+  misc_conv,
Ondřej Vašík 917089
+  NULL
Ondřej Vašík 917089
+};
Ondřej Vašík 917089
+
Ondřej Vašík 917089
+#define PAM_BAIL_P(a) \
Ondřej Vašík 917089
+  if (retval) \
Ondřej Vašík 917089
+    { \
Ondřej Vašík 917089
+      pam_end (pamh, retval); \
Ondřej Vašík 917089
+      a; \
Ondřej Vašík 917089
+    }
Ondřej Vašík 917089
+
Ondřej Vašík 917089
+static void
Ondřej Vašík 917089
+cleanup_pam (int retcode)
Ondřej Vašík 917089
+{
Ondřej Vašík 917089
+  if (_pam_session_opened)
Ondřej Vašík 917089
+    pam_close_session (pamh, 0);
Ondřej Vašík 917089
+
Ondřej Vašík 917089
+  if (_pam_cred_established)
Ondřej Vašík 917089
+    pam_setcred (pamh, PAM_DELETE_CRED | PAM_SILENT);
Ondřej Vašík 917089
+
Ondřej Vašík 917089
+  pam_end(pamh, retcode);
Ondřej Vašík 917089
+}
Ondřej Vašík 917089
+
Ondřej Vašík 917089
+/* Signal handler for parent process.  */
Ondřej Vašík 917089
+static void
Ondřej Vašík 917089
+su_catch_sig (int sig)
Ondřej Vašík 917089
+{
Ondřej Vašík 917089
+  caught_signal = true;
Ondřej Vašík 917089
+}
Ondřej Vašík 917089
+
Ondřej Vašík 917089
+/* Export env variables declared by PAM modules.  */
Ondřej Vašík 917089
+static void
Ondřej Vašík 917089
+export_pamenv (void)
Ondřej Vašík 917089
+{
Ondřej Vašík 917089
+  char **env;
Ondřej Vašík 917089
+
Ondřej Vašík 917089
+  /* This is a copy but don't care to free as we exec later anyways.  */
Ondřej Vašík 917089
+  env = pam_getenvlist (pamh);
Ondřej Vašík 917089
+  while (env && *env)
Ondřej Vašík 917089
+    {
Ondřej Vašík 917089
+      if (putenv (*env) != 0)
Ondřej Vašík 917089
+	xalloc_die ();
Ondřej Vašík 917089
+      env++;
Ondřej Vašík 917089
+    }
Ondřej Vašík 917089
+}
Ondřej Vašík 917089
+
Ondřej Vašík 917089
+static void
Ondřej Vašík 917089
+create_watching_parent (void)
Ondřej Vašík 917089
+{
Ondřej Vašík 917089
+  pid_t child;
Ondřej Vašík 917089
+  sigset_t ourset;
Ondřej Vašík 917089
+  int status = 0;
Ondřej Vašík 917089
+
Ondřej Vašík 917089
+  retval = pam_open_session (pamh, 0);
Ondřej Vašík 917089
+  if (retval != PAM_SUCCESS)
Ondřej Vašík 917089
+    {
Ondřej Vašík 917089
+      cleanup_pam (retval);
Ondřej Vašík 917089
+      error (EXIT_FAILURE, 0, _("cannot not open session: %s"),
Ondřej Vašík 917089
+	     pam_strerror (pamh, retval));
Ondřej Vašík 917089
+    }
Ondřej Vašík 917089
+  else
Ondřej Vašík 917089
+    _pam_session_opened = 1;
Ondřej Vašík 917089
+
Ondřej Vašík 917089
+  child = fork ();
Ondřej Vašík 917089
+  if (child == (pid_t) -1)
Ondřej Vašík 917089
+    {
Ondřej Vašík 917089
+      cleanup_pam (PAM_ABORT);
Ondřej Vašík 917089
+      error (EXIT_FAILURE, errno, _("cannot create child process"));
Ondřej Vašík 917089
+    }
Ondřej Vašík 917089
+
Ondřej Vašík 917089
+  /* the child proceeds to run the shell */
Ondřej Vašík 917089
+  if (child == 0)
Ondřej Vašík 917089
+    return;
Ondřej Vašík 917089
+
Ondřej Vašík 917089
+  /* In the parent watch the child.  */
Ondřej Vašík 917089
+
Ondřej Vašík 917089
+  /* su without pam support does not have a helper that keeps
Ondřej Vašík 917089
+     sitting on any directory so let's go to /.  */
Ondřej Vašík 917089
+  if (chdir ("/") != 0)
Ondřej Vašík 917089
+    error (0, errno, _("warning: cannot change directory to %s"), "/");
Ondřej Vašík 917089
+
Ondřej Vašík 917089
+  sigfillset (&ourset);
Ondřej Vašík 917089
+  if (sigprocmask (SIG_BLOCK, &ourset, NULL))
Ondřej Vašík 917089
+    {
Ondřej Vašík 917089
+      error (0, errno, _("cannot block signals"));
Ondřej Vašík 917089
+      caught_signal = true;
Ondřej Vašík 917089
+    }
Ondřej Vašík 917089
+  if (!caught_signal)
Ondřej Vašík 917089
+    {
Ondřej Vašík 917089
+      struct sigaction action;
Ondřej Vašík 917089
+      action.sa_handler = su_catch_sig;
Ondřej Vašík 917089
+      sigemptyset (&action.sa_mask);
Ondřej Vašík 917089
+      action.sa_flags = 0;
Ondřej Vašík 917089
+      sigemptyset (&ourset);
Ondřej Vašík 917089
+      if (sigaddset (&ourset, SIGTERM)
Ondřej Vašík 917089
+	  || sigaddset (&ourset, SIGALRM)
Ondřej Vašík 917089
+	  || sigaction (SIGTERM, &action, NULL)
Ondřej Vašík 917089
+	  || sigprocmask (SIG_UNBLOCK, &ourset, NULL))
Ondřej Vašík 917089
+	{
Ondřej Vašík 917089
+	  error (0, errno, _("cannot set signal handler"));
Ondřej Vašík 917089
+	  caught_signal = true;
Ondřej Vašík 917089
+	}
Ondřej Vašík 917089
+    }
Ondřej Vašík 917089
+  if (!caught_signal)
Ondřej Vašík 917089
+    {
Ondřej Vašík 917089
+      pid_t pid;
Ondřej Vašík 917089
+      for (;;)
Ondřej Vašík 917089
+	{
Ondřej Vašík 917089
+	  pid = waitpid (child, &status, WUNTRACED);
Ondřej Vašík 917089
+
Ondřej Vašík 917089
+	  if (pid != (pid_t)-1 && WIFSTOPPED (status))
Ondřej Vašík 917089
+	    {
Ondřej Vašík 917089
+	      kill (getpid (), SIGSTOP);
Ondřej Vašík 917089
+	      /* once we get here, we must have resumed */
Ondřej Vašík 917089
+	      kill (pid, SIGCONT);
Ondřej Vašík 917089
+	    }
Ondřej Vašík 917089
+	  else
Ondřej Vašík 917089
+	    break;
Ondřej Vašík 917089
+	}
Ondřej Vašík 917089
+      if (pid != (pid_t)-1)
Ondřej Vašík 917089
+	if (WIFSIGNALED (status))
Ondřej Vašík 917089
+	  status = WTERMSIG (status) + 128;
Ondřej Vašík 917089
+	else
Ondřej Vašík 917089
+	  status = WEXITSTATUS (status);
Ondřej Vašík 917089
+      else
Ondřej Vašík 917089
+	status = 1;
Ondřej Vašík 917089
+    }
Ondřej Vašík 917089
+  else
Ondřej Vašík 917089
+    status = 1;
Ondřej Vašík 917089
+
Ondřej Vašík 917089
+  if (caught_signal)
Ondřej Vašík 917089
+    {
Ondřej Vašík 917089
+      fprintf (stderr, _("\nSession terminated, killing shell..."));
Ondřej Vašík 917089
+      kill (child, SIGTERM);
Ondřej Vašík 917089
+    }
Ondřej Vašík 917089
+
Ondřej Vašík 917089
+  cleanup_pam (PAM_SUCCESS);
Ondřej Vašík 917089
+
Ondřej Vašík 917089
+  if (caught_signal)
Ondřej Vašík 917089
+    {
Ondřej Vašík 917089
+      sleep (2);
Ondřej Vašík 917089
+      kill (child, SIGKILL);
Ondřej Vašík 917089
+      fprintf (stderr, _(" ...killed.\n"));
Ondřej Vašík 917089
+    }
Ondřej Vašík 917089
+  exit (status);
Ondřej Vašík 917089
+}
Ondřej Vašík 917089
+#endif
Ondřej Vašík 917089
+
Ondřej Vašík 917089
 /* Ask the user for a password.
Ondřej Vašík 917089
+   If PAM is in use, let PAM ask for the password if necessary.
Ondřej Vašík 917089
    Return true if the user gives the correct password for entry PW,
Ondřej Vašík 917089
    false if not.  Return true without asking for a password if run by UID 0
Ondřej Vašík 917089
    or if PW has an empty password.  */
Ondřej Vašík 917089
@@ -208,10 +389,52 @@ log_su (struct passwd const *pw, bool successful)
Ondřej Vašík 917089
 static bool
Ondřej Vašík 917089
 correct_password (const struct passwd *pw)
Ondřej Vašík 917089
 {
Ondřej Vašík 917089
+#ifdef USE_PAM
Ondřej Vašík 917089
+  const struct passwd *lpw;
Ondřej Vašík 917089
+  const char *cp;
Ondřej Vašík 917089
+
Ondřej Vašík 917089
+  retval = pam_start (simulate_login ? PAM_SERVICE_NAME_L : PAM_SERVICE_NAME,
Ondřej Vašík 917089
+		      pw->pw_name, &conv, &pamh);
Ondřej Vašík 917089
+  PAM_BAIL_P (return false);
Ondřej Vašík 917089
+
Ondřej Vašík 917089
+  if (isatty (0) && (cp = ttyname (0)) != NULL)
Ondřej Vašík 917089
+    {
Ondřej Vašík 917089
+      const char *tty;
Ondřej Vašík 917089
+
Ondřej Vašík 917089
+      if (strncmp (cp, "/dev/", 5) == 0)
Ondřej Vašík 917089
+	tty = cp + 5;
Ondřej Vašík 917089
+      else
Ondřej Vašík 917089
+	tty = cp;
Ondřej Vašík 917089
+      retval = pam_set_item (pamh, PAM_TTY, tty);
Ondřej Vašík 917089
+      PAM_BAIL_P (return false);
Ondřej Vašík 917089
+    }
Ondřej Vašík 917089
+#if 0 /* Manpage discourages use of getlogin.  */
Ondřej Vašík 917089
+  cp = getlogin ();
Ondřej Vašík 917089
+  if (!(cp && *cp && (lpw = getpwnam (cp)) != NULL && lpw->pw_uid == getuid ()))
Ondřej Vašík 917089
+#endif
Ondřej Vašík 917089
+  lpw = getpwuid (getuid ());
Ondřej Vašík 917089
+  if (lpw && lpw->pw_name)
Ondřej Vašík 917089
+    {
Ondřej Vašík 917089
+      retval = pam_set_item (pamh, PAM_RUSER, (const void *) lpw->pw_name);
Ondřej Vašík 917089
+      PAM_BAIL_P (return false);
Ondřej Vašík 917089
+    }
Ondřej Vašík 917089
+  retval = pam_authenticate (pamh, 0);
Ondřej Vašík 917089
+  PAM_BAIL_P (return false);
Ondřej Vašík 917089
+  retval = pam_acct_mgmt (pamh, 0);
Ondřej Vašík 917089
+  if (retval == PAM_NEW_AUTHTOK_REQD)
Ondřej Vašík 917089
+    {
Ondřej Vašík 917089
+      /* Password has expired.  Offer option to change it.  */
Ondřej Vašík 917089
+      retval = pam_chauthtok (pamh, PAM_CHANGE_EXPIRED_AUTHTOK);
Ondřej Vašík 917089
+      PAM_BAIL_P (return false);
Ondřej Vašík 917089
+    }
Ondřej Vašík 917089
+  PAM_BAIL_P (return false);
Ondřej Vašík 917089
+  /* Must be authenticated if this point was reached.  */
Ondřej Vašík 917089
+  return true;
Ondřej Vašík 917089
+#else /* !USE_PAM */
Ondřej Vašík 917089
   char *unencrypted, *encrypted, *correct;
Ondřej Vašík 917089
 #if HAVE_GETSPNAM && HAVE_STRUCT_SPWD_SP_PWDP
Ondřej Vašík 917089
   /* Shadow passwd stuff for SVR3 and maybe other systems.  */
Ondřej Vašík 917089
-  struct spwd *sp = getspnam (pw->pw_name);
Ondřej Vašík 917089
+  const struct spwd *sp = getspnam (pw->pw_name);
Ondřej Vašík 917089
 
Ondřej Vašík 917089
   endspent ();
Ondřej Vašík 917089
   if (sp)
Ondřej Vašík 917089
@@ -232,6 +455,7 @@ correct_password (const struct passwd *pw)
Ondřej Vašík 917089
   encrypted = crypt (unencrypted, correct);
Ondřej Vašík 917089
   memset (unencrypted, 0, strlen (unencrypted));
Ondřej Vašík 917089
   return STREQ (encrypted, correct);
Ondřej Vašík 917089
+#endif /* !USE_PAM */
Ondřej Vašík 917089
 }
Ondřej Vašík 917089
 
Ondřej Vašík 917089
 /* Update `environ' for the new shell based on PW, with SHELL being
Ondřej Vašík 917089
@@ -274,19 +498,41 @@ modify_environment (const struct passwd *pw, const char *shell)
Ondřej Vašík 917089
             }
Ondřej Vašík 917089
         }
Ondřej Vašík 917089
     }
Ondřej Vašík 917089
+
Ondřej Vašík 917089
+#ifdef USE_PAM
Ondřej Vašík 917089
+  export_pamenv ();
Ondřej Vašík 917089
+#endif
Ondřej Vašík 917089
 }
Ondřej Vašík 917089
 
Ondřej Vašík 917089
 /* Become the user and group(s) specified by PW.  */
Ondřej Vašík 917089
 
Ondřej Vašík 917089
 static void
Ondřej Vašík 917089
-change_identity (const struct passwd *pw)
Ondřej Vašík 917089
+init_groups (const struct passwd *pw)
Ondřej Vašík 917089
 {
Ondřej Vašík 917089
 #ifdef HAVE_INITGROUPS
Ondřej Vašík 917089
   errno = 0;
Ondřej Vašík 917089
   if (initgroups (pw->pw_name, pw->pw_gid) == -1)
Ondřej Vašík 917089
-    error (EXIT_CANCELED, errno, _("cannot set groups"));
Ondřej Vašík 917089
+    {
Ondřej Vašík 917089
+#ifdef USE_PAM
Ondřej Vašík 917089
+      cleanup_pam (PAM_ABORT);
Ondřej Vašík 917089
+#endif
Ondřej Vašík 917089
+      error (EXIT_FAILURE, errno, _("cannot set groups"));
Ondřej Vašík 917089
+    }
Ondřej Vašík 917089
   endgrent ();
Ondřej Vašík 917089
 #endif
Ondřej Vašík 917089
+
Ondřej Vašík 917089
+#ifdef USE_PAM
Ondřej Vašík 917089
+  retval = pam_setcred (pamh, PAM_ESTABLISH_CRED);
Ondřej Vašík 917089
+  if (retval != PAM_SUCCESS)
Ondřej Vašík 917089
+    error (EXIT_FAILURE, 0, "%s", pam_strerror (pamh, retval));
Ondřej Vašík 917089
+  else
Ondřej Vašík 917089
+    _pam_cred_established = 1;
Ondřej Vašík 917089
+#endif
Ondřej Vašík 917089
+}
Ondřej Vašík 917089
+
Ondřej Vašík 917089
+static void
Ondřej Vašík 917089
+change_identity (const struct passwd *pw)
Ondřej Vašík 917089
+{
Ondřej Vašík 917089
   if (setgid (pw->pw_gid))
Ondřej Vašík 917089
     error (EXIT_CANCELED, errno, _("cannot set group id"));
Ondřej Vašík 917089
   if (setuid (pw->pw_uid))
Ondřej Vašík 917089
@@ -500,9 +746,21 @@ main (int argc, char **argv)
Ondřej Vašík 917089
       shell = NULL;
Ondřej Vašík 917089
     }
Ondřej Vašík 917089
   shell = xstrdup (shell ? shell : pw->pw_shell);
Ondřej Vašík 917089
-  modify_environment (pw, shell);
Ondřej Vašík 917089
+
Ondřej Vašík 917089
+  init_groups (pw);
Ondřej Vašík 917089
+
Ondřej Vašík 917089
+#ifdef USE_PAM
Ondřej Vašík 917089
+  create_watching_parent ();
Ondřej Vašík 917089
+  /* Now we're in the child.  */
Ondřej Vašík 917089
+#endif
Ondřej Vašík 917089
 
Ondřej Vašík 917089
   change_identity (pw);
Ondřej Vašík 917089
+
Ondřej Vašík 917089
+  /* Set environment after pam_open_session, which may put KRB5CCNAME
Ondřej Vašík 917089
+     into the pam_env, etc.  */
Ondřej Vašík 917089
+
Ondřej Vašík 917089
+  modify_environment (pw, shell);
Ondřej Vašík 917089
+
Ondřej Vašík 917089
   if (simulate_login && chdir (pw->pw_dir) != 0)
Ondřej Vašík 917089
     error (0, errno, _("warning: cannot change directory to %s"), pw->pw_dir);
Ondřej Vašík 917089
 
Ondřej Vašík 917089
-- 
Ondřej Vašík 917089
1.7.1
Ondřej Vašík 917089
diff -urNp coreutils-8.7-orig/doc/coreutils.texi coreutils-8.7/doc/coreutils.texi
Ondřej Vašík 917089
--- coreutils-8.7-orig/doc/coreutils.texi	2010-11-15 12:47:03.529922880 +0100
Ondřej Vašík 917089
+++ coreutils-8.7/doc/coreutils.texi	2010-11-15 12:49:55.945171380 +0100
Ondřej Vašík 917089
@@ -15180,7 +15180,9 @@ the exit status of @var{command} otherwi
Ondřej Vašík 917089
 
Ondřej Vašík 917089
 @command{su} allows one user to temporarily become another user.  It runs a
Ondřej Vašík 917089
 command (often an interactive shell) with the real and effective user
Ondřej Vašík 917089
-ID, group ID, and supplemental groups of a given @var{user}.  Synopsis:
Ondřej Vašík 917089
+ID, group ID, and supplemental groups of a given @var{user}. When the -l
Ondřej Vašík 917089
+option is given, the su-l PAM file is used instead of the default su PAM file.
Ondřej Vašík 917089
+Synopsis:
Ondřej Vašík 917089
 
Ondřej Vašík 917089
 @example
Ondřej Vašík 917089
 su [@var{option}]@dots{} [@var{user} [@var{arg}]@dots{}]
Ondřej Vašík 917089
@@ -15259,7 +15261,8 @@ environment variables except @env{TERM},
Ondřej Vašík 917089
 (which are set, even for the super-user, as described above), and set
Ondřej Vašík 917089
 @env{PATH} to a compiled-in default value.  Change to @var{user}'s home
Ondřej Vašík 917089
 directory.  Prepend @samp{-} to the shell's name, intended to make it
Ondřej Vašík 917089
-read its login startup file(s).
Ondřej Vašík 917089
+read its login startup file(s). When this option is given, /etc/pam.d/su-l
Ondřej Vašík 917089
+PAM file is used instead of the default one.
Ondřej Vašík 917089
 
Ondřej Vašík 917089
 @item -m
Ondřej Vašík 917089
 @itemx -p