[Pkg-shadow-devel] Bug#412061: login: su ends PAM sesstion in subshell

Philipp Matthias Hahn pmhahn at debian.org
Fri Feb 23 10:44:30 CET 2007

Package: login
Version: 1:
Severity: normal

I'm currently deploying Kerberos authentication in our group. I'm using
libpam-krb5 in /etc/pam.d/common-* and have a problem with the Kerberos
credential cache file being deleted when using 'su'.

When logging in via login/gdm/kdm, the pam_krb5.so module puts the
Kerberos5 credentials in a file like /tmp/krb5cc_1000, so all other
processes can use those credentials directly without requiring another
password entry. This file cache is creates by pam_acct_mgmt() and/or

Using 'su - some_user' doesn't work as expected, since the cache file is
deleted before executing the shell. Strace'ing a 'su' shows the
following behaviour:

open("/tmp/krb5cc_pam_N2kh8U", O_RDWR|O_CREAT|O_EXCL, 0600) = 4
# This is for the Ticket granting ticket
unlink("/tmp/krb5cc_pam_N2kh8U")        = 0
open("/tmp/krb5cc_pam_N2kh8U", O_RDWR|O_CREAT|O_TRUNC|O_EXCL, 0600) = 4
open("/tmp/krb5cc_pam_N2kh8U", O_RDWR)  = 4
open("/tmp/krb5cc_1000_q9oTxG", O_RDWR|O_CREAT|O_EXCL, 0600) = 4
# This is the user's ticket
open("/tmp/krb5cc_pam_N2kh8U", O_RDONLY) = 4
open("/tmp/krb5cc_pam_N2kh8U", O_RDONLY) = 4
open("/tmp/krb5cc_pam_N2kh8U", O_RDONLY) = 4
unlink("/tmp/krb5cc_1000_q9oTxG")       = 0
open("/tmp/krb5cc_1000_q9oTxG", O_RDWR|O_CREAT|O_TRUNC|O_EXCL, 0600) = 4
# no idea why it is done a second time
open("/tmp/krb5cc_1000_q9oTxG", O_RDWR) = 4
chown32("/tmp/krb5cc_1000_q9oTxG", 1000, 1000) = 0
open("/tmp/krb5cc_pam_N2kh8U", O_RDWR)  = 4
unlink("/tmp/krb5cc_pam_N2kh8U")        = 0
# the TGT is no longer needed
clone(Process 25189 attached
[pid 25189] open("/tmp/krb5cc_1000_q9oTxG", O_RDWR) = 3
[pid 25189] unlink("/tmp/krb5cc_1000_q9oTxG") = 0
##### this is the culprit #####
[pid 25189] execve("/bin/bash", ["-su"], [/* 10 vars */]) = 0
Process 25189 detached
open("/tmp/krb5cc_1000_q9oTxG", O_RDWR) = -1 ENOENT (No such file or directory)

Taking a look at shadow- shows the following code:
        child = fork ();
        if (child == 0) {       /* child shell */
                pam_end (pamh, PAM_SUCCESS); <<<<<<<<<<<<<<<<<<

                if (doshell)
                        (void) shell (shellstr, (char *) args[0], envp);
                        (void) execve (shellstr, (char **) args, envp);
                exit (errno == ENOENT ? E_CMD_NOTFOUND : E_CMD_NOEXEC);
        ret = pam_close_session (pamh, 0);
        pam_end (pamh, ret);

Calling pam_end() in the child closes the PAM session and by that
deletes the credential cache. I think that is wrong. For example, take a
look at what 'login' does in shadow-
        child = fork ();
        if (child < 0) {
        } else if (child) {
                wait (NULL);
                exit (0);
        /* child */
        if ((tmp = getdef_str ("FAKE_SHELL")) != NULL)
                err = shell (tmp, pwent.pw_shell, newenvp); /* fake shell */
                /* exec the shell finally */
                err = shell (pwent.pw_shell, (char *) 0, newenvp);
        exit (err == ENOENT ? E_CMD_NOTFOUND : E_CMD_NOEXEC);

No call to pam_end() for the child. Apple doesn't do it either:
FreeBSD asks the same question:

I haven't checked other PAM users
(http://www.google.de/search?q=su.c+pam_end+fork), but I think just
calling pam_end() in the child is wrong. The manual page of pam_end(3)
has the following text on this:
              Terminate  the  Linux-PAM  library.  The service application associated with
              the pamh handle, is terminated.  The argument, pam_status, passes the  value
              most recently returned to the application from the library; it indicates the
              manner in which the library should be shutdown.  Besides carrying  a  return
              value,  this argument may be logically OR’d with PAM_DATA_SILENT to indicate
              that the module should not treat the call too  seriously.  It  is  generally
              used  to  indicate that the current closing of the library is in a fork(2)ed
              process, and that the parent will take care of cleaning up things that exist
              outside of the current process space (files etc.).

        Note,  the  PAM_DATA_SILENT  flag  is  pending  acceptance  with
        the DCE  (as  of 1996/12/4).

And now the BUTs:
1. Grepping libpam-krb5-2.6 pam-0.79 shadow- for PAM_DATA_SILENT
does not show anything interesting. It seems not to be implemented, so
using is would be "right", but doesn't solve the problem.

2. Removing the pam_end() for the child solves the problem. Looking at
pam-0.79/Linux-PAM/libpam/pam_end.c and
pam-0.79/Linux-PAM/libpam/pam_data.c shows, that pam_end() mostly frees
memory, but modules may do other things (as does pam_krb5, which unlinks
it's cache file). Memory will not be leaked if the call is removed,
since the child calls execve() and thus replaces the process image. It
other resources like open files, which would get closed when pam_end()
isn't called any more, but I don't know if a PAM-session might open
files and have them put into the session context. I don't think so, but
the documentation of PAM is week.

3. Before changing it, I would like some feedback from PAM and Kerberos5
experienced developers/maintainers.

Philipp Hahn

-- System Information:
Debian Release: 4.0
  APT prefers unstable
  APT policy: (989, 'unstable'), (1, 'experimental')
Architecture: i386 (i686)
Shell:  /bin/sh linked to /bin/bash
Kernel: Linux
Locale: LANG=de_DE.UTF-8, LC_CTYPE=en_US.UTF-8 (charmap=UTF-8)

Versions of packages login depends on:
ii  libc6                       2.3.6.ds1-13 GNU C Library: Shared libraries
ii  libpam-modules              0.79-4       Pluggable Authentication Modules f
ii  libpam-runtime              0.79-4       Runtime support for the PAM librar
ii  libpam0g                    0.79-4       Pluggable Authentication Modules l
ii  libpam-krb5                 2.6-1        PAM module for MIT Kerberos

login recommends no packages.

-- no debconf information

More information about the Pkg-shadow-devel mailing list