Package: libpam0g
Version: 0.79-4

Package: libnss-ldap
Version: 251-7.5


On Debian Sarge in LDAP authentication enviroment it is possible to allow
login only for users listed in group identified by "pam_groupdn". In case the
user does not exist in the group, access is debied by LDAP. Usually the
pam_ldap precede pam_unix. In case the user "root" is not in LDAP but only
local user (in case of all LDAP servers failure), the user "root" can still
login even if not in "pam_groupdn" listed - pam_unix checks if user "root"
exists in system and in shadows.

On Debian Etch this does not work and PAM allows login users which are not
local on the machine and were authenticated against LDAP. Pam_ldap in this
case deny access but pam_ldap is only "sufficient" and then pam_unix is
processed and in this case pam_unix allows login to users which has not record
for shadow password. For pam_unix there is a option "broken_shadow", which
should ignore errors when reading shadown info for user. This should be the
case, but pam_unix ignores errors even without this option and allow login.

I am not sure, in which package is the error, but IMO pam_unix should not allow 
login users without correct shadow info if option "broken_shadow" not used.

I wanted to send an email into pam-list mailing list, but my email has been
never distributed in the mailing list (I am subscribed and I have sent email
from correct email address). Please, see my email to pam-list mailing list
below, it contains detailed info.

Regards,

Wolf.

###########################################################################

Dear PAM dev team,

I would like to ask you for your opinion to the following situation:

I have Linux setup for LDAP authention. On Debian system, I've installed
libnss-ldap and libpam-ldap packages and configured

/etc/pam_ldap.conf and /etc/libnss-ldap.conf
==================================================
uri ldaps://LDAP-HOST
base BASE-DN
ldap_version 3
scope sub
idle_timelimit 3600
nss_connect_policy persist
bind_policy hard
timelimit 30
pam_filter objectclass=posixAccount
pam_login_attribute uid
pam_lookup_policy yes
pam_groupdn LOGIN-ALLOWED-GROUP-DN
pam_min_uid 10000
pam_password clear
ssl on
tls_checkpeer yes
tls_cacert /etc/ldap/cacerts.pem
tls_cacertfile /etc/ldap/cacerts.pem
pam_member_attribute uniqueMember
==================================================

/etc/pam.d/ssh (default by debian package)
==================================================
auth       required     pam_env.so
auth       required     pam_env.so envfile=/etc/default/locale
@include common-auth
account    required     pam_nologin.so
@include common-account
@include common-session
session    optional     pam_motd.so
session    optional     pam_mail.so standard noenv
session    required     pam_limits.so
@include common-password
==================================================

/etc/pam.d/common-account (inserted line with pam_ldap.so)
==================================================
account sufficient /lib/security/pam_ldap.so
account required        pam_unix.so
==================================================

Everything works fine, but I would like to limit access only for users
included in group referenced by LDAP DN LOGIN-ALLOWED-GROUP-DN and I have a
user's DN in this group. I would like to keep access for root user in case of
LDAP server failure. User root has which has records in /etc/passwd and
/etc/shadow files.

I have DN of user TESTER-A in the group LOGIN-ALLOWED-GROUP-DN. User TESTER-B
is not in this group listed.

When I try to login on Debian 3.1 Sarge using SSH on account TESTER-A,
everything goes correct, and user can login. When I try to login with user
TESTER-B, system asks for password and then, because the TESTER-B is not in
LOGIN-ALLOWED-GROUP-DN group, it writes "You must be a uniqueMember of
LOGIN-ALLOWED-GROUP-DN to login. Connection closed by IP". This is what I
expect. Because "account sufficient pam_ldap" did not pass, pam_unix is
tested, but the account has no record in /etc/shadow and login is disabled.

But the same configuration on Debian 4.0 Etch and Gentoo gives the different
results. For the user TESTER-A everything goes same way, that's correct. But
for TESTER-B the system asks password and then writes "You must be a
uniqueMember of LOGIN-ALLOWED-GROUP-DN to login." but allow user to login. In
this case pam_unix does not block to login and allow to login for user which
does not exist on the system (TESTER-B exists only in LDAP).

I have found following problem in the source code:

Until version 246, libnss-ldap uses character "x" if userPassword LDAP
attribute is not present (or contains unknown type). Since version 246 it uses
character "*" (see. libnss-ldap/ChangeLog, version 246, BUG#240).

==================================================
libnss-ldap:ChangeLog
---------------------
246 Luke Howard <[EMAIL PROTECTED]>
  * fix for BUG#240: return "*" rather than "x" for
    userPassword if not present
==================================================

In the source code of pam_unix module, there is function pam_sm_acct_mgmt.
This function tries to find if user has an account. At first, it finds user
using getpwnam() function, which return line in "/etc/passwd" format. For user
from LDAP, it returns in my case line
"TESTER-A:x:10000:10000:/home/TESTER-A:/bin/bash" on Debian 3.1 Sarge with
libnss-ldap-238. But on Debian 4.0 Etch with libnss-ldap-251 it returns
"TESTER-A:*:10000:10000:/home/TESTER-A:/bin/bash".

==================================================
Linux-PAM/modules/pam_unix/pam_sm_acct_mgmt.c
---------------------------------------------
PAM_EXTERN int pam_sm_acct_mgmt(pam_handle_t * pamh, int flags, int argc, const 
char **argv) {
...
  pwent = pam_modutil_getpwnam(pamh, uname);
  if (!pwent) {
          pam_syslog(pamh, LOG_ALERT,
                   "could not identify user (from getpwnam(%s))",
                   uname);
          return PAM_USER_UNKNOWN;
  }
  if (!strcmp( pwent->pw_passwd, "*NP*" )) { /* NIS+ */
          uid_t save_euid, save_uid;

          save_euid = geteuid();
          save_uid = getuid();
          if (save_uid == pwent->pw_uid)
                  setreuid( save_euid, save_uid );
          else  {
                  setreuid( 0, -1 );
                  if (setreuid( -1, pwent->pw_uid ) == -1) {
                          setreuid( -1, 0 );
                          setreuid( 0, -1 );
                          if(setreuid( -1, pwent->pw_uid ) == -1)
                                  return PAM_CRED_INSUFFICIENT;
                  }
          }
          spent = pam_modutil_getspnam (pamh, uname);
          if (save_uid == pwent->pw_uid)
                  setreuid( save_uid, save_euid );
          else {
                  if (setreuid( -1, 0 ) == -1)
                  setreuid( save_uid, -1 );
                  setreuid( -1, save_euid );
          }

  } else if (_unix_shadowed (pwent))
          spent = pam_modutil_getspnam (pamh, uname);
  else
          return PAM_SUCCESS;

#ifdef WITH_SELINUX
  if (!spent && SELINUX_ENABLED )
      spent = _unix_run_verify_binary(pamh, ctrl, uname);
#endif

  if (!spent)
          if (on(UNIX_BROKEN_SHADOW,ctrl))
                  return PAM_SUCCESS;

  if (!spent)
          return PAM_AUTHINFO_UNAVAIL;    /* Couldn't get username from shadow 
*/
==================================================

When function pam_sm_acct_mgmt finds any user (using getpwnam() function), it
continues and tries to find record in "shadow" file using function
_unix_shadowed(). And when it could not find password as "x" character, then
if returns PAM_SUCCESS. In fact this means when user has no record in "shadow"
file, it has granted access to machine.

IMO this is not correct because there is a option for pam_unix called
"broken_shadow" with description "Ignore errors reading shadow inforation for
users in the account management module." should be for such a case when shadow
info is unreadable.

==================================================
Linux-PAM/modules/pam_unix/support.c
------------------------------------
int _unix_shadowed(const struct passwd *pwd)
{
        if (pwd != NULL) {
                if (strcmp(pwd->pw_passwd, "x") == 0) {
                        return 1;
                }
                if ((pwd->pw_passwd[0] == '#') &&
                    (pwd->pw_passwd[1] == '#') &&
                    (strcmp(pwd->pw_name, pwd->pw_passwd + 2) == 0)) {
                        return 1;
                }
        }
        return 0;
}
==================================================


This is the problem I found. I don't know in which package is the error. But I
have a few questions:

1) I think, the "x" character in /etc/passwd password field means, that the
password is in shadow file - right? What exactly the "*" character means in
password field of /etc/passwd?

2) Do you think function _unix_shadowed of Linux-PAM/pam_unix/support.c should
check "*" too?

3) A user has LDAP record with userPassword attribute set. libnss-ldap,
pam-ldap and the other connects anonymously to read user attributes. And when
the libnss-ldap connects as LDAP administrator (which is not secure in
production env), it can read userPassword, but it is {SSHA} encrypted.
libnss-ldap expects attribute userPassword either in RFC2307 ({CRYPT}) or in
RFC3112 (CRYPT$) format. Question: What do you think, what kind of password
(character) should function _nss_ldap_locate_userpassword() of
libnss-ldap/ldap-nss.c returns for unreadable userPassword attribute?
Character "x" (as shadowed password) or character "*" (in what meaning)? What
character would be better for NSS compatibility and for PAM (pam_unix)?


Thank you for your answer.

Regards,

Wolf.


-- 
To UNSUBSCRIBE, email to [EMAIL PROTECTED]
with a subject of "unsubscribe". Trouble? Contact [EMAIL PROTECTED]

Reply via email to