From nobody Sat Jun  8 17:10:23 2002
Return-Path: <debbugs@master.debian.org>
Received: from fort-point-station.mit.edu by po10.mit.edu (8.9.2/4.7) id BAA24724; Wed, 27 Feb 2002 01:18:05 -0500 (EST)
Received: from master.debian.org (master.debian.org [216.234.231.5])
	by fort-point-station.mit.edu (8.9.2/8.9.2) with ESMTP id BAA00397
	for <hartmans@mit.edu>; Wed, 27 Feb 2002 01:18:04 -0500 (EST)
Received: from debbugs by master.debian.org with local (Exim 3.12 1 (Debian))
	id 16fxPf-0006Oh-00; Wed, 27 Feb 2002 00:18:03 -0600
X-Loop: owner@bugs.debian.org
Subject: Bug#135990: libpam-modules: pam_unix_passwd.c - _unix_verify_shadow() calls getpwnam()
Reply-To: Martin Schwenke <martin@meltin.net>, 135990@bugs.debian.org
Resent-From: Martin Schwenke <martin@meltin.net>
Resent-To: debian-bugs-dist@lists.debian.org
Resent-CC: Sam Hartman <hartmans@debian.org>, pam@packages.qa.debian.org
Resent-Date: Wed, 27 Feb 2002 06:18:02 GMT
Resent-Message-ID: <handler.135990.B.101479040024326@bugs.debian.org>
X-Debian-PR-Message: report 135990
X-Debian-PR-Package: libpam-modules
X-Debian-PR-Keywords: patch
Received: via spool by submit@bugs.debian.org id=B.101479040024326
          (code B ref -1); Wed, 27 Feb 2002 06:18:02 GMT
From: Martin Schwenke <martin@meltin.net>
To: Debian Bug Tracking System <submit@bugs.debian.org>
X-Mailer: reportbug 1.44
Date: Wed, 27 Feb 2002 17:12:03 +1100
Message-Id: <20020227061753.B61B74130@lists.samba.org>
Delivered-To: submit@bugs.debian.org
Resent-Sender: Debian BTS <debbugs@master.debian.org>
Lines: 115
Xref: tir-na-nogth.mit.edu mail.personal:6287

Package: libpam-modules
Version: 0.72-35
Severity: normal
Tags: patch

In the "prelim check" part of pam_sm_chauthtok(),
_unix_verify_shadow() is called, which then calls getpwnam().  The
result of the call to getpwnam() is then used to check whether the
password can be changed.  If the user details are not stored in
/etc/{passwd,shadow} but are stored in some other subsystem accessible
via libnss, then _unix_verify_shadow() succeeds, making
pam_sm_chauthtok() believe that it is going to be able to change the
password.  In this case it is wrong.

This tends to upset the apple-cart a little since, if the pam_unix
module only has the sufficient condition (and it's "prelim check"
succeeds when it shouldn't), then the "prelim check" for the module
that actually knows about the user will not be done.

Below is a patch that fixes this situation.

--------8<---------8<-------- CUT HERE --------8<---------8<--------
--- pam_unix_passwd.c	Mon Feb 25 12:32:07 2002
+++ pam_unix_passwd.c.newest	Wed Feb 27 16:04:08 2002
@@ -110,6 +110,7 @@
 #define _UNIX_NEW_AUTHTOK	"-UN*X-NEW-PASS"
 
 #define MAX_PASSWD_TRIES	3
+#define PW_FILE			"/etc/passwd"
 #define PW_TMPFILE		"/etc/npasswd"
 #define SH_TMPFILE		"/etc/nshadow"
 #define CRACKLIB_DICTS		"/usr/share/dict/cracklib_dict"
@@ -207,6 +208,21 @@
 	return master;
 }
 
+static struct passwd *_unix_getpwnam(const char *name)
+{
+	struct passwd *ent = NULL;
+	FILE *pwfile;
+
+	pwfile = fopen(PW_FILE, "r");
+	if (pwfile != NULL) {
+		ent = fgetpwent(pwfile);
+		while (ent && (strcmp(ent->pw_name, name) != 0))
+			ent = fgetpwent(pwfile);
+		fclose(pwfile);
+	}
+	return ent;
+}
+
 static int check_old_password(const char *forwho, const char *newpass)
 {
 	static char buf[16384];
@@ -300,7 +316,7 @@
 	}
 	fclose(opwfile);
 	if (!found) {
-		pwd = getpwnam(forwho);
+		pwd = _unix_getpwnam(forwho);
 		if (pwd == NULL) {
 			retval = PAM_AUTHTOK_ERR;
 			err = 1;
@@ -338,7 +354,7 @@
 	oldmask = umask(077);
 	pwfile = fopen(PW_TMPFILE, "w");
 	umask(oldmask);
-	opwfile = fopen("/etc/passwd", "r");
+	opwfile = fopen(PW_FILE, "r");
 	if (pwfile == NULL || opwfile == NULL)
 		return PAM_AUTHTOK_ERR;
 	chown(PW_TMPFILE, 0, 0);
@@ -367,7 +383,7 @@
 		err = 1;
 	}
 	if (!err)
-		rename(PW_TMPFILE, "/etc/passwd");
+		rename(PW_TMPFILE, PW_FILE);
 	else
 		unlink(PW_TMPFILE);
 
@@ -532,9 +548,7 @@
 	int retval = PAM_SUCCESS;
 
 	/* UNIX passwords area */
-	setpwent();
-	pwd = getpwnam(user);	/* Get password file entry... */
-	endpwent();
+	pwd = _unix_getpwnam(user);	/* Get password *file* entry... */
 	if (pwd == NULL)
 		return PAM_AUTHINFO_UNAVAIL;	/* We don't need to do the rest... */
 
--------8<---------8<-------- CUT HERE --------8<---------8<--------

This implements _unix_getpwnam, which always looks up a user in
/etc/passwd, and uses it in the places that I think are correct.
Hopefully using this function in these 2 places does not break NIS.  I
don't think it does, but I haven't tested it.

peace & happiness,
martin

-- System Information
Debian Release: 3.0
Architecture: i386
Kernel: Linux rover 2.4.18-pre7 #1 Thu Jan 31 14:47:36 EST 2002 i686
Locale: LANG=C, LC_CTYPE=

Versions of packages libpam-modules depends on:
ii  libc6                         2.2.5-3    GNU C Library: Shared libraries an
ii  libcap1                       1:1.10-12  support for getting/setting POSIX.
ii  libdb3                        3.2.9-14   Berkeley v3 Database Libraries [ru
ii  libpam0g                      0.72-35    Pluggable Authentication Modules l


From nobody Sat Jun  8 17:10:33 2002
Return-Path: <debbugs@master.debian.org>
Received: from pacific-carrier-annex.mit.edu by po10.mit.edu (8.9.2/4.7) id VAA21735; Sun, 24 Feb 2002 21:03:04 -0500 (EST)
Received: from master.debian.org (master.debian.org [216.234.231.5])
	by pacific-carrier-annex.mit.edu (8.9.2/8.9.2) with ESMTP id VAA21255
	for <hartmans@mit.edu>; Sun, 24 Feb 2002 21:03:04 -0500 (EST)
Received: from debbugs by master.debian.org with local (Exim 3.12 1 (Debian))
	id 16fATm-00009w-00; Sun, 24 Feb 2002 20:03:02 -0600
X-Loop: owner@bugs.debian.org
Subject: Bug#135604: pam_unix_passwd does not fail if the user is unknown
Reply-To: Martin Schwenke <martin@meltin.net>, 135604@bugs.debian.org
Resent-From: Martin Schwenke <martin@meltin.net>
Resent-To: debian-bugs-dist@lists.debian.org
Resent-CC: Sam Hartman <hartmans@debian.org>, pam@packages.qa.debian.org
Resent-Date: Mon, 25 Feb 2002 02:03:01 GMT
Resent-Message-ID: <handler.135604.B.101460180531147@bugs.debian.org>
X-Debian-PR-Message: report 135604
X-Debian-PR-Package: libpam-modules
X-Debian-PR-Keywords: patch
Received: via spool by submit@bugs.debian.org id=B.101460180531147
          (code B ref -1); Mon, 25 Feb 2002 02:03:01 GMT
From: Martin Schwenke <martin@meltin.net>
To: Debian Bug Tracking System <submit@bugs.debian.org>
X-Reportbug-Version: 1.41.142135
X-Mailer: reportbug 1.41.142135
Date: Mon, 25 Feb 2002 12:49:22 +1100
Message-Id: <20020225015530.4F0774144@lists.samba.org>
Delivered-To: submit@bugs.debian.org
Resent-Sender: Debian BTS <debbugs@master.debian.org>
Lines: 84
Xref: tir-na-nogth.mit.edu mail.personal:6257

Package: libpam-modules
Version: 0.72-35
Severity: normal
Tags: patch

_update_passwd and _update_shadow currently return PAM_SUCCESS even if
they did not change a password in the passwd and shadow files
respectively.  This is because they loop through all of the entries in
the files, changing any that match the username, but don't record
whether there were any entries actually changed.

The problem becomes visible if, for example, I've got pam_unix_passwd
and pam_ldap listed (in that order) in my /etc/pam.d/passwd file.
Then _do_setpass calls both functions, which both return PAM_SUCCESS,
and logs:

  _log_err(LOG_NOTICE, "Password for %s was changed", forwho);

... and my LDAP password change never happens.  Oops!

Here is a patch that changes the default return value to
PAM_USER_UNKNOWN and sets it to PAM_SUCCESS when the username is
actually matched.

--------8<---------8<-------- CUT HERE --------8<---------8<--------
--- Linux-PAM-0.72.orig/modules/pam_unix/pam_unix_passwd.c	Mon Feb 25 12:35:01 2002
+++ Linux-PAM-0.72/modules/pam_unix/pam_unix_passwd.c	Mon Feb 25 12:32:07 2002
@@ -331,7 +331,7 @@
 {
 	struct passwd *tmpent = NULL;
 	FILE *pwfile, *opwfile;
-	int retval = 0;
+	int retval = PAM_USER_UNKNOWN;
 	int err = 0;
 	int oldmask;
 
@@ -347,6 +347,7 @@
 	while (tmpent) {
 		if (!strcmp(tmpent->pw_name, forwho)) {
 			tmpent->pw_passwd = towhat;
+			retval = PAM_SUCCESS;
 		}
 		if (putpwent(tmpent, pwfile)) {
 			fprintf(stderr, "error writing entry to password file: %s\n",
@@ -377,7 +378,7 @@
 {
 	struct spwd *spwdent = NULL, *stmpent = NULL;
 	FILE *pwfile, *opwfile;
-	int retval = 0;
+	int retval = PAM_USER_UNKNOWN;
 	int err = 0;
 	int oldmask;
 
@@ -399,6 +400,7 @@
 		if (!strcmp(stmpent->sp_namp, forwho)) {
 			stmpent->sp_pwdp = towhat;
 			stmpent->sp_lstchg = time(NULL) / (60 * 60 * 24);
+			retval = PAM_SUCCESS;
 
 			D(("Set password %s for %s", stmpent->sp_pwdp, forwho));
 		}
--------8<---------8<-------- CUT HERE --------8<---------8<--------

Seems to work.  There may be more efficient ways of doing this, but
this keeps the code nice and simple...

Thanks...

peace & happiness,
martin

-- System Information
Debian Release: 3.0
Architecture: i386
Kernel: Linux rover 2.4.18-pre7 #1 Thu Jan 31 14:47:36 EST 2002 i686
Locale: LANG=C, LC_CTYPE=

Versions of packages libpam-modules depends on:
ii  libc6                         2.2.5-1    GNU C Library: Shared libraries an
ii  libcap1                       1:1.10-12  support for getting/setting POSIX.
ii  libdb3                        3.2.9-14   Berkeley v3 Database Libraries [ru
ii  libpam0g                      0.72-35    Pluggable Authentication Modules l


