[PATCH] Add NT_STATUS constants to pass_check and PAM, free twice fixes

Andrew Bartlett abartlet at pcug.org.au
Tue Apr 24 13:41:40 GMT 2001


This patch adds NT_STATUS constants to both the PAM code and the
pass_check.c code.  This is particularly usefull becouse it allows NT to
display a USEFUL error message on a failed authentication (PAM account
checking).  

This patch also ADDS PAM account checking to the srv_pipe code, where it
was absent previously.

Included in this e-mail are two patches, an incremental patch containing
only this change (and a fix where I was freeing a pamh twice in the
session code in my previous patch) and a full patch from current samba
2.2. cvs.

This patch is TESTED.  A full NT domain login and share connect
functions as expected, and expired accoutnts are indicated as such. 
Password Changes procede as expected, changing the password as root on
the local machine.  (I'm not sure if the srv_pipe changes were exercised
by this, if they were not, then then were not tested...).

Swat was not tested - but the change is trivial.

Andrew Bartlett
-- 
Andrew Bartlett
abartlet at pcug.org.au
-------------- next part --------------
diff -ur samba-2.2.0cvs/source/passdb/pampass.c samba-intermediate/source/passdb/pampass.c
--- samba-2.2.0cvs/source/passdb/pampass.c	Tue Apr 24 23:30:01 2001
+++ samba-intermediate/source/passdb/pampass.c	Tue Apr 24 22:48:52 2001
@@ -70,6 +70,21 @@
 	return True;
 }
 
+static BOOL smb_pam_nt_status_error_handler(pam_handle_t *pamh, int pam_error, char *msg, int dbglvl, uint32 *nt_status)
+{
+	/* This function is a sainity check, to make sure that we NEVER report failure as sucess */
+        if (!smb_pam_error_handler(pamh, pam_error, msg, dbglvl)) {
+		if (*nt_status == NT_STATUS_NOPROBLEMO) {
+			/* Complain LOUDLY */
+			DEBUG(0, ("PAM: BUG: PAM and NT_STATUS error MISMATCH, forcing to NT_STATUS_LOGON_FAILURE"));
+			*nt_status = NT_STATUS_LOGON_FAILURE;
+		}
+		return False;
+	} else {
+		return True;
+	}
+}
+
 /*
  * PAM conversation function
  * Here we assume (for now, at least) that echo on means login name, and
@@ -272,88 +287,105 @@
 /*
  * PAM Authentication Handler
  */
-static BOOL smb_pam_auth(pam_handle_t *pamh, char *user, char *password)
+static uint32 smb_pam_auth(pam_handle_t *pamh, char *user, char *password)
 {
 	int pam_error;
-
+	uint32 nt_status = NT_STATUS_LOGON_FAILURE;
+	
 	/*
 	 * To enable debugging set in /etc/pam.d/samba:
 	 *	auth required /lib/security/pam_pwdb.so nullok shadow audit
 	 */
 	
-	DEBUG(4,("PAM: Authenticate User: %s\n", user));
-	pam_error = pam_authenticate(pamh, PAM_SILENT); /* Can we authenticate user? */
+        DEBUG(4,("PAM: Authenticate User: %s\n", user));
+	pam_error = pam_authenticate(pamh, PAM_SILENT | lp_null_passwords() ? 0 : PAM_DISALLOW_NULL_AUTHTOK); /* Can we authenticate user? */
 	switch( pam_error ){
 		case PAM_AUTH_ERR:
 			DEBUG(2, ("PAM: Athentication Error\n"));
+			nt_status = NT_STATUS_WRONG_PASSWORD;
 			break;
 		case PAM_CRED_INSUFFICIENT:
 			DEBUG(2, ("PAM: Insufficient Credentials\n"));
+			nt_status = NT_STATUS_INSUFFICIENT_LOGON_INFO;
 			break;
 		case PAM_AUTHINFO_UNAVAIL:
 			DEBUG(2, ("PAM: Authentication Information Unavailable\n"));
+			nt_status = NT_STATUS_LOGON_FAILURE;
 			break;
 		case PAM_USER_UNKNOWN:
 			DEBUG(2, ("PAM: Username NOT known to Authentication system\n"));
+			nt_status = NT_STATUS_NO_SUCH_USER;
 			break;
 		case PAM_MAXTRIES:
 			DEBUG(2, ("PAM: One or more authentication modules reports user limit exceeeded\n"));
+			nt_status = NT_STATUS_REMOTE_SESSION_LIMIT;
 			break;
 		case PAM_ABORT:
 			DEBUG(0, ("PAM: One or more PAM modules failed to load\n"));
+			nt_status = NT_STATUS_LOGON_FAILURE;
 			break;
 	        case PAM_SUCCESS:
 			DEBUG(4, ("PAM: User %s Authenticated OK\n", user));
+			nt_status = NT_STATUS_NOPROBLEMO;
 		        break;
 		default:
 			DEBUG(0, ("PAM: UNKNOWN ERROR (%d) while authenticating user %s\n", pam_error, user));
+			nt_status = NT_STATUS_LOGON_FAILURE;
 	}
-	if(!smb_pam_error_handler(pamh, pam_error, "Authentication Failure", 2)) {
+	if(!smb_pam_nt_status_error_handler(pamh, pam_error, "Authentication Failure", 2, &nt_status)) {
 		smb_pam_end(pamh);
-		return False;
+		return nt_status;
 	}
 	/* If this point is reached, the user has been authenticated. */
-	return (True);
+	return nt_status;
 }
 
 /* 
  * PAM Account Handler
  */
-static BOOL smb_pam_account(pam_handle_t *pamh, char * user, char * password)
+static uint32 smb_pam_account(pam_handle_t *pamh, char * user, char * password)
 {
 	int pam_error;
+	uint32 nt_status = NT_STATUS_ACCOUNT_DISABLED;
 
 	DEBUG(4,("PAM: Account Management for User: %s\n", user));
 	pam_error = pam_acct_mgmt(pamh, PAM_SILENT); /* Is user account enabled? */
 	switch( pam_error ) {
 		case PAM_AUTHTOK_EXPIRED:
 			DEBUG(2, ("PAM: User is valid but password is expired\n"));
+			nt_status = NT_STATUS_PASSWORD_EXPIRED;
 			break;
 		case PAM_ACCT_EXPIRED:
 			DEBUG(2, ("PAM: User no longer permitted to access system\n"));
+			nt_status = NT_STATUS_ACCOUNT_EXPIRED;
 			break;
 		case PAM_AUTH_ERR:
 			DEBUG(2, ("PAM: There was an authentication error\n"));
+			nt_status = NT_STATUS_LOGON_FAILURE;
 			break;
 		case PAM_PERM_DENIED:
 			DEBUG(0, ("PAM: User is NOT permitted to access system at this time\n"));
+			nt_status = NT_STATUS_ACCOUNT_RESTRICTION;
 			break;
 		case PAM_USER_UNKNOWN:
 			DEBUG(0, ("PAM: User \"%s\" is NOT known to account management\n", user));
+			nt_status = NT_STATUS_NO_SUCH_USER;
 			break;
 	        case PAM_SUCCESS:
 			DEBUG(4, ("PAM: Account OK for User: %s\n", user));
-		        break;
+		        nt_status = NT_STATUS_NOPROBLEMO;
+			break;
 		default:
+			nt_status = NT_STATUS_ACCOUNT_DISABLED;
 			DEBUG(0, ("PAM: UNKNOWN PAM ERROR (%d) during Account Management for User: %s\n", pam_error, user));
 	}
-	if(!smb_pam_error_handler(pamh, pam_error, "Account Check Failed", 2)) {
+	if(!smb_pam_nt_status_error_handler(pamh, pam_error, "Account Check Failed", 2, &nt_status)) {
 		smb_pam_end(pamh);
-		return False;
+		return nt_status;
 	}
 	
 	/* If this point is reached, the user has been authenticated. */
-	return (True);
+	return (nt_status);
 }
 
 /* 
@@ -362,7 +394,7 @@
 static BOOL smb_pam_setcred(pam_handle_t *pamh, char * user)
 {
 	int pam_error;
-
+	uint32 nt_status = NT_STATUS_NO_TOKEN;
 	/*
 	 * This will allow samba to aquire a kerberos token. And, when
 	 * exporting an AFS cell, be able to /write/ to this cell.
@@ -372,30 +404,36 @@
 	pam_error = pam_setcred(pamh, (PAM_ESTABLISH_CRED|PAM_SILENT)); 
 	switch( pam_error ) {
 		case PAM_CRED_UNAVAIL:
-			DEBUG(0, ("PAM: Credentials not found for user:%s", user ));
+			DEBUG(0, ("PAM: Credentials not found for user:%s\n", user ));
+			nt_status = NT_STATUS_NO_TOKEN;
 			break;
 		case PAM_CRED_EXPIRED:
-			DEBUG(0, ("PAM: Credentials for user: \"%s\" EXPIRED!", user ));
+			DEBUG(0, ("PAM: Credentials for user: \"%s\" EXPIRED!\n", user ));
+			nt_status = NT_STATUS_PASSWORD_EXPIRED;
 			break;
 		case PAM_USER_UNKNOWN:
-			DEBUG(0, ("PAM: User: \"%s\" is NOT known so can not set credentials!", user ));
+			DEBUG(0, ("PAM: User: \"%s\" is NOT known so can not set credentials!\n", user ));
+			nt_status = NT_STATUS_NO_SUCH_USER;
 			break;
 		case PAM_CRED_ERR:
-			DEBUG(0, ("PAM: Unknown setcredentials error - unable to set credentials for %s", user ));
+			DEBUG(0, ("PAM: Unknown setcredentials error - unable to set credentials for %s\n", user ));
+			nt_status = NT_STATUS_LOGON_FAILURE;
 			break;
 	        case PAM_SUCCESS:
 			DEBUG(4, ("PAM: SetCredentials OK for User: %s\n", user));
+			nt_status = NT_STATUS_NOPROBLEMO;
 		        break;
 		default:
 			DEBUG(0, ("PAM: UNKNOWN PAM ERROR (%d) during SetCredentials for User: %s\n", pam_error, user));
+			nt_status = NT_STATUS_NO_TOKEN;
 	}
-	if(!smb_pam_error_handler(pamh, pam_error, "Set Credential Failure", 2)) {
+	if(!smb_pam_nt_status_error_handler(pamh, pam_error, "Set Credential Failure", 2, &nt_status)) {
 		smb_pam_end(pamh);
-		return False;
+		return nt_status;
 	}
 	
 	/* If this point is reached, the user has been authenticated. */
-	return (True);
+	return (nt_status);
 }
 
 
@@ -412,19 +450,25 @@
 #ifdef PAM_TTY
 	DEBUG(4,("PAM: tty set to: %s\n", tty));
 	pam_error = pam_set_item(pamh, PAM_TTY, tty);
-	if (!smb_pam_error_handler(pamh, pam_error, "set tty failed", 0))
+	if (!smb_pam_error_handler(pamh, pam_error, "set tty failed", 0)) {
+		smb_pam_end(pamh);
 		return False;
+	}
 #endif
-
+	
 	if (flag) {
 		pam_error = pam_open_session(pamh, PAM_SILENT);
-		if (!smb_pam_error_handler(pamh, pam_error, "session setup failed", 0))
+		if (!smb_pam_error_handler(pamh, pam_error, "session setup failed", 0)) {
+			smb_pam_end(pamh);
 			return False;
+		}
 	} else {
 		pam_setcred(pamh, (PAM_DELETE_CRED|PAM_SILENT));  /* We don't care if this fails */ 
 		pam_error = pam_close_session(pamh, PAM_SILENT);  /* This will probably pick up the error anyway */
-		if (!smb_pam_error_handler(pamh, pam_error, "session close failed", 0))
+		if (!smb_pam_error_handler(pamh, pam_error, "session close failed", 0)){
+			smb_pam_end(pamh);
 			return False;
+		}
 	}
 	return (True);
 }
@@ -485,33 +529,42 @@
 /*
  * PAM Externally accessible Account handler
  */
-BOOL smb_pam_accountcheck(char * user)
+uint32 smb_pam_accountcheck(char * user)
 {
 	pam_handle_t *pamh = NULL;
 
+	uint32 nt_status = NT_STATUS_ACCOUNT_DISABLED;
+
 	PAM_username = user;
 	PAM_password = NULL;
 
 	/* Ignore PAM if told to. */
 
 	if (!lp_obey_pam_restrictions())
-		return True;
+		return NT_STATUS_NOPROBLEMO;
 
-	if( smb_pam_start(&pamh, user, NULL, NULL)) {
-		if ( smb_pam_account(pamh, user, NULL)) {
-			return( smb_pam_end(pamh));
+	if (smb_pam_start(&pamh, user, NULL, NULL)) {
+		nt_status = smb_pam_account(pamh, user, NULL);
+		if (nt_status == NT_STATUS_NOPROBLEMO) {
+			if (smb_pam_end(pamh)) {
+				return nt_status;
+			} else {
+				nt_status = NT_STATUS_ACCOUNT_DISABLED;
+			}
 		}
 	}
 	DEBUG(0, ("PAM: Account Validation Failed - Rejecting User!\n"));
-	return( False );
+	return( nt_status );
 }
 
 /*
  * PAM Password Validation Suite
  */
-BOOL smb_pam_passcheck(char * user, char * password)
+uint32 smb_pam_passcheck(char * user, char * password)
 {
 	pam_handle_t *pamh = NULL;
+
+	uint32 nt_status = NT_STATUS_LOGON_FAILURE;
 	
 	PAM_username = user;
 	PAM_password = password;
@@ -522,17 +575,24 @@
 	 * compiled --with-pam.
 	 */
 
-	if( smb_pam_start(&pamh, user, NULL, NULL)) {
-		if ( smb_pam_auth(pamh, user, password)) {
-			if ( smb_pam_account(pamh, user, password)) {
-				if ( smb_pam_setcred(pamh, user)) {
-					return( smb_pam_end(pamh));
+	if (smb_pam_start(&pamh, user, NULL, NULL)) {
+		nt_status = smb_pam_auth(pamh, user, password);
+		if (nt_status == NT_STATUS_NOPROBLEMO) {
+			nt_status = smb_pam_account(pamh, user, password);
+			if (nt_status == NT_STATUS_NOPROBLEMO) {
+				nt_status = smb_pam_setcred(pamh, user);
+				if (nt_status == NT_STATUS_NOPROBLEMO) {
+					if (smb_pam_end(pamh)) {
+						return nt_status;
+					} else {
+						nt_status = NT_STATUS_LOGON_FAILURE;
+					}
 				}
 			}
 		}
 	}
 	DEBUG(0, ("PAM: System Validation Failed - Rejecting User!\n"));
-	return( False );
+	return( nt_status );
 }
 
 /*
@@ -557,14 +617,12 @@
         }
 
 	if (!smb_pam_start(&pamh, user, rhost, NULL)) {
-		smb_pam_end(pamh);
 		return False;
 	}
 
 	if (smb_internal_pam_session(pamh, user, tty, True)) {
 		return smb_pam_end(pamh);
 	} else {
-		smb_pam_end(pamh);
 		return False;
 	}
 }
@@ -586,7 +644,6 @@
 	user = strdup(in_user);
 	
 	if (!smb_pam_start(&pamh, user, rhost, NULL)) {
-		smb_pam_end(pamh);
 		return False;
 	}
 
@@ -628,9 +685,9 @@
 #else
 
 /* If PAM not used, no PAM restrictions on accounts. */
- BOOL smb_pam_accountcheck(char * user)
+ uint32 smb_pam_accountcheck(char * user)
 {
-	return True;
+	return NT_STATUS_NOPROBLEMO;
 }
 
 /* If PAM not used, also no PAM restrictions on sessions. */
Only in samba-intermediate/source/passdb: pampass.c~
Binary files samba-2.2.0cvs/source/passdb/pampass.o and samba-intermediate/source/passdb/pampass.o differ
diff -ur samba-2.2.0cvs/source/passdb/pass_check.c samba-intermediate/source/passdb/pass_check.c
--- samba-2.2.0cvs/source/passdb/pass_check.c	Tue Apr 24 13:19:49 2001
+++ samba-intermediate/source/passdb/pass_check.c	Tue Apr 24 18:13:59 2001
@@ -550,7 +550,7 @@
 offset is the first char to try and change (start with 0)
 it assumes the string starts lowercased
 ****************************************************************************/
-static BOOL string_combinations2(char *s, int offset, BOOL (*fn) (char *),
+static BOOL string_combinations2(char *s, int offset, uint32 (*fn) (char *),
 				 int N)
 {
 	int len = strlen(s);
@@ -568,7 +568,7 @@
 		if (!islower(c))
 			continue;
 		s[i] = toupper(c);
-		if (string_combinations2(s, i + 1, fn, N - 1))
+		if (string_combinations2(s, i + 1, fn, N - 1) == NT_STATUS_NOPROBLEMO)
 			return (True);
 		s[i] = c;
 	}
@@ -582,11 +582,11 @@
 offset is the first char to try and change (start with 0)
 it assumes the string starts lowercased
 ****************************************************************************/
-static BOOL string_combinations(char *s, BOOL (*fn) (char *), int N)
+static uint32 string_combinations(char *s, uint32 (*fn) (char *), int N)
 {
 	int n;
 	for (n = 1; n <= N; n++)
-		if (string_combinations2(s, 0, fn, n))
+		if (string_combinations2(s, 0, fn, n) == NT_STATUS_NOPROBLEMO)
 			return (True);
 	return (False);
 }
@@ -595,54 +595,67 @@
 /****************************************************************************
 core of password checking routine
 ****************************************************************************/
-static BOOL password_check(char *password)
+static uint32 password_check(char *password)
 {
-
+  BOOL ret;
 #ifdef WITH_PAM
 	return (smb_pam_passcheck(this_user, password));
 #endif /* WITH_PAM */
 
 #ifdef WITH_AFS
 	if (afs_auth(this_user, password))
-		return (True);
+		return (NT_STATUS_NOPROBLEMO);
 #endif /* WITH_AFS */
 
 #ifdef WITH_DFS
 	if (dfs_auth(this_user, password))
-		return (True);
+		return (NT_STATUS_NOPROBLEMO);
 #endif /* WITH_DFS */
 
 #ifdef KRB5_AUTH
 	if (krb5_auth(this_user, password))
-		return (True);
+		return (NT_STATUS_NOPROBLEMO);
 #endif /* KRB5_AUTH */
 
 #ifdef KRB4_AUTH
 	if (krb4_auth(this_user, password))
-		return (True);
+		return (NT_STATUS_NOPROBLEMO);
 #endif /* KRB4_AUTH */
 
 #ifdef OSF1_ENH_SEC
-	{
-		BOOL ret =
-			(strcmp
-			 (osf1_bigcrypt(password, this_salt),
+	
+	        ret = (strcmp(osf1_bigcrypt(password, this_salt),
 			  this_crypted) == 0);
 		if (!ret) {
 			DEBUG(2,
 			      ("OSF1_ENH_SEC failed. Trying normal crypt.\n"));
 			ret = (strcmp((char *)crypt(password, this_salt), this_crypted) == 0);
 		}
-		return ret;
-	}
+	        if (ret) {
+		        return NT_STATUS_NOPROBLEMO;
+		} else {
+		        return NT_STATUS_WRONG_PASSWORD;
+		}
+
 #endif /* OSF1_ENH_SEC */
 
 #ifdef ULTRIX_AUTH
-	return (strcmp((char *)crypt16(password, this_salt), this_crypted) == 0);
+	ret = (strcmp((char *)crypt16(password, this_salt), this_crypted) == 0);
+        if (ret) {
+          return NT_STATUS_NOPROBLEMO;
+        } else {
+	  return NT_STATUS_WRONG_PASSWORD;
+	}
+
 #endif /* ULTRIX_AUTH */
 
 #ifdef LINUX_BIGCRYPT
-	return (linux_bigcrypt(password, this_salt, this_crypted));
+	ret = (linux_bigcrypt(password, this_salt, this_crypted));
+        if (ret) {
+	  return NT_STATUS_NOPROBLEMO;
+	} else {
+	  return NT_STATUS_WRONG_PASSWORD;
+	}
 #endif /* LINUX_BIGCRYPT */
 
 #if defined(HAVE_BIGCRYPT) && defined(HAVE_CRYPT) && defined(USE_BOTH_CRYPT_CALLS)
@@ -655,20 +668,35 @@
 	 */
 
 	if (strcmp(bigcrypt(password, this_salt), this_crypted) == 0)
-		return True;
+		return NT_STATUS_NOPROBLEMO;
 	else
-		return (strcmp((char *)crypt(password, this_salt), this_crypted) == 0);
+		ret = (strcmp((char *)crypt(password, this_salt), this_crypted) == 0);
+                if (ret) {
+		  return NT_STATUS_NOPROBLEMO;
+		} else {
+		  return NT_STATUS_WRONG_PASSWORD;
+		}
 #else /* HAVE_BIGCRYPT && HAVE_CRYPT && USE_BOTH_CRYPT_CALLS */
 
 #ifdef HAVE_BIGCRYPT
-	return (strcmp(bigcrypt(password, this_salt), this_crypted) == 0);
+	ret = (strcmp(bigcrypt(password, this_salt), this_crypted) == 0);
+        if (ret) {
+	  return NT_STATUS_NOPROBLEMO;
+	} else {
+	  return NT_STATUS_WRONG_PASSWORD;
+	}
 #endif /* HAVE_BIGCRYPT */
 
 #ifndef HAVE_CRYPT
 	DEBUG(1, ("Warning - no crypt available\n"));
-	return (False);
+	return (NT_STATUS_LOGON_FAILURE);
 #else /* HAVE_CRYPT */
-	return (strcmp((char *)crypt(password, this_salt), this_crypted) == 0);
+	ret = (strcmp((char *)crypt(password, this_salt), this_crypted) == 0);
+        if (ret) {
+	  return NT_STATUS_NOPROBLEMO;
+	} else {
+	  return NT_STATUS_WRONG_PASSWORD;
+	}
 #endif /* HAVE_CRYPT */
 #endif /* HAVE_BIGCRYPT && HAVE_CRYPT && USE_BOTH_CRYPT_CALLS */
 }
@@ -679,28 +707,30 @@
 check if a username/password is OK
 the function pointer fn() points to a function to call when a successful
 match is found and is used to update the encrypted password file 
-return True on correct match, False otherwise
+return NT_STATUS_NOPROBLEMO on correct match, NT_STATUS_WRONG_PASSWORD otherwise
 ****************************************************************************/
-
-BOOL pass_check(char *user, char *password, int pwlen, struct passwd *pwd,
+uint32 pass_check(char *user, char *password, int pwlen, struct passwd *pwd,
 		BOOL (*fn) (char *, char *))
 {
 	pstring pass2;
 	int level = lp_passwordlevel();
+	uint32 nt_status;
 	struct passwd *pass = NULL;
 
-	if (password)
-		password[pwlen] = 0;
+	fstrcpy(this_user, user);
 
 #if DEBUG_PASSWORD
 	DEBUG(100, ("checking user=[%s] pass=[%s]\n", user, password));
 #endif
 
+	if (password)
+		password[pwlen] = 0;
+
 	if (!password)
-		return (False);
+		return (NT_STATUS_WRONG_PASSWORD);
 
 	if (((!*password) || (!pwlen)) && !lp_null_passwords())
-		return (False);
+		return (NT_STATUS_WRONG_PASSWORD);
 
 	if (pwd && !user) {
 		pass = (struct passwd *)pwd;
@@ -726,7 +756,7 @@
 
 	if (!pass) {
 		DEBUG(3, ("Couldn't find user %s\n", user));
-		return (False);
+		return (NT_STATUS_NO_SUCH_USER);
 	}
 
 #ifdef HAVE_GETSPNAM
@@ -790,7 +820,6 @@
 #endif
 
 	/* extract relevant info */
-	fstrcpy(this_user, pass->pw_name);
 	fstrcpy(this_salt, pass->pw_passwd);
 
 #if defined(HAVE_TRUNCATED_SALT)
@@ -805,30 +834,34 @@
 		if (!lp_null_passwords()) {
 			DEBUG(2, ("Disallowing %s with null password\n",
 				  this_user));
-			return (False);
+			return (NT_STATUS_WRONG_PASSWORD);
 		}
 		if (!*password) {
 			DEBUG(3,
 			      ("Allowing access to %s with null password\n",
 			       this_user));
-			return (True);
+			return (NT_STATUS_NOPROBLEMO);
 		}
 	}
 
 #endif /* WITH_PAM */
 
 	/* try it as it came to us */
-	if (password_check(password)) {
-		if (fn)
-			fn(user, password);
-		return (True);
-	}
+        nt_status = password_check(password);
+        if (nt_status == NT_STATUS_NOPROBLEMO) {
+                if (fn)
+                        fn(user, password);
+		return (nt_status);
+	} else if (nt_status != NT_STATUS_WRONG_PASSWORD) {
+                /* No point continuing if its not the password thats to blame (ie PAM disabled). */
+                return (nt_status);
+        }
 
 	/* if the password was given to us with mixed case then we don't
-	   need to proceed as we know it hasn't been case modified by the
-	   client */
+	 * need to proceed as we know it hasn't been case modified by the
+	 * client */
 	if (strhasupper(password) && strhaslower(password)) {
-		return (False);
+		return (NT_STATUS_WRONG_PASSWORD);
 	}
 
 	/* make a copy of it */
@@ -837,10 +870,11 @@
 	/* try all lowercase if it's currently all uppercase */
 	if (strhasupper(password)) {
 		strlower(password);
-		if (password_check(password)) {
-			if (fn)
+		nt_status = password_check(password);
+		if (nt_status == NT_STATUS_NOPROBLEMO) {
+		        if (fn)
 				fn(user, password);
-			return (True);
+			return (nt_status);
 		}
 	}
 
@@ -848,20 +882,24 @@
 	if (level < 1) {
 		/* restore it */
 		fstrcpy(password, pass2);
-		return (False);
+		return (NT_STATUS_WRONG_PASSWORD);
 	}
 
 	/* last chance - all combinations of up to level chars upper! */
 	strlower(password);
 
-	if (string_combinations(password, password_check, level)) {
-		if (fn)
+        nt_status = (string_combinations(password, password_check, level)); 
+        if (nt_status == NT_STATUS_NOPROBLEMO) {
+                if (fn)
 			fn(user, password);
-		return (True);
+		return (NT_STATUS_NOPROBLEMO);
 	}
-
+        
 	/* restore it */
 	fstrcpy(password, pass2);
 
-	return (False);
+	return (NT_STATUS_WRONG_PASSWORD);
 }
+
+
+
Only in samba-intermediate/source/passdb: pass_check.c~
Binary files samba-2.2.0cvs/source/passdb/pass_check.o and samba-intermediate/source/passdb/pass_check.o differ
diff -ur samba-2.2.0cvs/source/rpc_server/CVS/Entries samba-intermediate/source/rpc_server/CVS/Entries
--- samba-2.2.0cvs/source/rpc_server/CVS/Entries	Tue Apr 24 18:10:44 2001
+++ samba-intermediate/source/rpc_server/CVS/Entries	Tue Apr 24 17:58:39 2001
@@ -18,5 +18,5 @@
 /srv_lsa_nt.c/1.1.2.18/Sun Apr 22 07:06:50 2001//TSAMBA_2_2
 /srv_netlog.c/1.75.2.5/Tue Apr 24 01:00:36 2001//TSAMBA_2_2
 /srv_pipe.c/1.50.2.14/Tue Apr 24 03:19:51 2001//TSAMBA_2_2
-/srv_netlog_nt.c/1.1.2.12/Tue Apr 24 08:10:44 2001//TSAMBA_2_2
+/srv_netlog_nt.c/1.1.2.12/Tue Apr 24 07:58:39 2001//TSAMBA_2_2
 D
diff -ur samba-2.2.0cvs/source/rpc_server/srv_netlog_nt.c samba-intermediate/source/rpc_server/srv_netlog_nt.c
--- samba-2.2.0cvs/source/rpc_server/srv_netlog_nt.c	Tue Apr 24 23:30:01 2001
+++ samba-intermediate/source/rpc_server/srv_netlog_nt.c	Tue Apr 24 22:08:49 2001
@@ -593,13 +593,6 @@
 	  }
 	} 
 
-	become_root();
-	if (!smb_pam_accountcheck(nt_username)) {
-		unbecome_root();
-		return NT_STATUS_ACCOUNT_DISABLED;
-	}
-	unbecome_root();
-
 	if (!(smb_pass->acct_ctrl & ACB_PWNOTREQ)) {
 		switch (q_u->sam_id.logon_level) {
 		case INTERACTIVE_LOGON_TYPE:
@@ -613,6 +606,13 @@
 		}
 	}
     
+	become_root();
+	status = smb_pam_accountcheck(nt_username);
+	unbecome_root();
+	if (status != NT_STATUS_NOPROBLEMO) {
+		return status;
+	}
+
 	if (status != NT_STATUS_NOPROBLEMO)
 		return status;
 
diff -ur samba-2.2.0cvs/source/rpc_server/srv_pipe.c samba-intermediate/source/rpc_server/srv_pipe.c
--- samba-2.2.0cvs/source/rpc_server/srv_pipe.c	Tue Apr 24 13:19:51 2001
+++ samba-intermediate/source/rpc_server/srv_pipe.c	Tue Apr 24 18:21:47 2001
@@ -380,6 +380,13 @@
 			return False;
 		}
 
+		if (smb_pam_accountcheck(pipe_user_name) == NT_STATUS_NOPROBLEMO) {
+			DEBUG(1,("api_pipe_ntlmssp_verify: PAM denied account for user %s.\n",
+				pipe_user_name));
+			unbecome_root();
+			return False;
+		}
+
 		if(!(smb_pass = getsmbpwnam(pipe_user_name))) {
 			DEBUG(1,("api_pipe_ntlmssp_verify: Cannot find user %s in smb passwd database.\n",
 				pipe_user_name));
diff -ur samba-2.2.0cvs/source/smbd/password.c samba-intermediate/source/smbd/password.c
--- samba-2.2.0cvs/source/smbd/password.c	Tue Apr 24 13:19:55 2001
+++ samba-intermediate/source/smbd/password.c	Tue Apr 24 18:51:01 2001
@@ -500,7 +500,8 @@
 		return True;
 	}
 
-	if((smb_pass->smb_passwd != NULL) && 
+	if(lp_lanman_auth() && 
+	   (smb_pass->smb_passwd != NULL) && 
 	   smb_password_check((char *)lm_pass, 
 			      (uchar *)smb_pass->smb_passwd, challenge)) {
 		DEBUG(4,("LM MD4 password check succeeded\n"));
@@ -621,14 +622,14 @@
 		 */
 
 		if (ret)
-		  return smb_pam_accountcheck(user);
+		  return (smb_pam_accountcheck(user) == NT_STATUS_NOPROBLEMO);
 
 		return ret;
 	} 
 
-	return pass_check(user, password, pwlen, pwd, 
+	return (pass_check(user, password, pwlen, pwd, 
 			  lp_update_encrypted() ? 
-			  update_smbpassword_file : NULL);
+			  update_smbpassword_file : NULL) == NT_STATUS_NOPROBLEMO);
 }
 
 /****************************************************************************
Binary files samba-2.2.0cvs/source/smbd/password.o and samba-intermediate/source/smbd/password.o differ
Binary files samba-2.2.0cvs/source/smbd/session.o and samba-intermediate/source/smbd/session.o differ
diff -ur samba-2.2.0cvs/source/web/cgi.c samba-intermediate/source/web/cgi.c
--- samba-2.2.0cvs/source/web/cgi.c	Tue Apr 24 13:20:02 2001
+++ samba-intermediate/source/web/cgi.c	Tue Apr 24 18:17:58 2001
@@ -377,7 +377,7 @@
 
 	tested_pass = True;
 
-	if(pass_check(user, user_pass, strlen(user_pass), NULL, NULL) == True) {
+	if(pass_check(user, user_pass, strlen(user_pass), NULL, NULL) == NT_STATUS_NOPROBLEMO) {
 
 		/*
 		 * Password was ok.
Binary files samba-2.2.0cvs/source/web/cgi.o and samba-intermediate/source/web/cgi.o differ
-------------- next part --------------
Index: source/include/local.h
===================================================================
RCS file: /cvsroot/samba/source/include/local.h,v
retrieving revision 1.54.4.1
diff -u -r1.54.4.1 local.h
--- source/include/local.h	2001/04/18 16:30:28	1.54.4.1
+++ source/include/local.h	2001/04/24 13:20:16
@@ -173,6 +173,14 @@
 
 #define DEFAULT_PASSWD_CHAT "*new*password* %n\\n *new*password* %n\\n *changed*"
 
+/*
+ * Default passwd chat script.
+ */
+
+#define DEFAULT_PAM_CURRENTPW_PROMPT "(current)"
+#define DEFAULT_PAM_NEWPW_PROMPT "New"
+#define DEFAULT_PAM_REPPW_PROMPT "Retype"
+
 /* Minimum length of allowed password when changing UNIX password. */
 #define MINPASSWDLENGTH 5
 
Index: source/param/loadparm.c
===================================================================
RCS file: /cvsroot/samba/source/param/loadparm.c,v
retrieving revision 1.251.2.35
diff -u -r1.251.2.35 loadparm.c
--- source/param/loadparm.c	2001/04/23 20:43:24	1.251.2.35
+++ source/param/loadparm.c	2001/04/24 13:20:37
@@ -180,6 +180,11 @@
 	char *szAddShareCommand;
 	char *szChangeShareCommand;
 	char *szDeleteShareCommand;
+#ifdef WITH_PAM
+	char *szPAMcurrentpw;
+	char *szPAMnewpw;
+	char *szPAMreppw;
+#endif
 	int max_log_size;
 	int mangled_stack;
 	int max_xmit;
@@ -1005,6 +1010,13 @@
 	{"hide local users", P_BOOL, P_GLOBAL, &Globals.bHideLocalUsers, NULL,
 	 NULL, 0},
 
+#ifdef WITH_PAM
+	{"PAM options", P_SEP, P_SEPARATOR},
+	
+	{"pam currentpw prompt", P_STRING, P_GLOBAL, &Globals.szPAMcurrentpw, NULL, NULL, FLAG_GLOBAL},
+	{"pam newpw prompt", P_STRING, P_GLOBAL, &Globals.szPAMnewpw, NULL, NULL, FLAG_GLOBAL},
+	{"pam repeatpw prompt", P_STRING, P_GLOBAL, &Globals.szPAMreppw, NULL, NULL, FLAG_GLOBAL},
+#endif
 	{"VFS options", P_SEP, P_SEPARATOR},
 	
 	{"vfs object", P_STRING, P_LOCAL, &sDefault.szVfsObjectFile, handle_vfs_object, NULL, 0},
@@ -1191,6 +1203,16 @@
 	string_set(&Globals.szPasswdProgram, PASSWD_PROGRAM);
 	string_set(&Globals.szPrintcapname, PRINTCAP_NAME);
 	string_set(&Globals.szLockDir, LOCKDIR);
+
+	/*
+	 * Allow the default PAM password change chat to be overridden in local.h.
+	 */
+#ifdef WITH_PAM
+	string_set(&Globals.szPAMcurrentpw, DEFAULT_PAM_CURRENTPW_PROMPT);
+	string_set(&Globals.szPAMnewpw, DEFAULT_PAM_NEWPW_PROMPT);
+	string_set(&Globals.szPAMreppw, DEFAULT_PAM_REPPW_PROMPT);
+#endif
+
 #ifdef WITH_UTMP
 	string_set(&Globals.szUtmpDir, "");
 	string_set(&Globals.szWtmpDir, "");
@@ -1482,6 +1504,11 @@
 FN_GLOBAL_STRING(lp_add_share_cmd, &Globals.szAddShareCommand)
 FN_GLOBAL_STRING(lp_change_share_cmd, &Globals.szChangeShareCommand)
 FN_GLOBAL_STRING(lp_delete_share_cmd, &Globals.szDeleteShareCommand)
+#ifdef WITH_PAM
+FN_GLOBAL_STRING(lp_pam_currentpw_prompt, &Globals.szPAMcurrentpw)
+FN_GLOBAL_STRING(lp_pam_newpw_prompt, &Globals.szPAMnewpw)
+FN_GLOBAL_STRING(lp_pam_repeatpw_prompt, &Globals.szPAMreppw)
+#endif /* WITH_PAM */
 
 #ifdef WITH_SSL
 FN_GLOBAL_INTEGER(lp_ssl_version, &Globals.sslVersion)
Index: source/passdb/pampass.c
===================================================================
RCS file: /cvsroot/samba/source/passdb/pampass.c,v
retrieving revision 1.1.2.16
diff -u -r1.1.2.16 pampass.c
--- source/passdb/pampass.c	2001/04/23 20:43:24	1.1.2.16
+++ source/passdb/pampass.c	2001/04/24 13:20:39
@@ -50,6 +50,7 @@
 
 static char *PAM_username;
 static char *PAM_password;
+static char *PAM_newpassword;
 
 /*
  *  Macros to help make life easy
@@ -69,6 +70,21 @@
 	return True;
 }
 
+static BOOL smb_pam_nt_status_error_handler(pam_handle_t *pamh, int pam_error, char *msg, int dbglvl, uint32 *nt_status)
+{
+	/* This function is a sainity check, to make sure that we NEVER report failure as sucess */
+        if (!smb_pam_error_handler(pamh, pam_error, msg, dbglvl)) {
+		if (*nt_status == NT_STATUS_NOPROBLEMO) {
+			/* Complain LOUDLY */
+			DEBUG(0, ("PAM: BUG: PAM and NT_STATUS error MISMATCH, forcing to NT_STATUS_LOGON_FAILURE"));
+			*nt_status = NT_STATUS_LOGON_FAILURE;
+		}
+		return False;
+	} else {
+		return True;
+	}
+}
+
 /*
  * PAM conversation function
  * Here we assume (for now, at least) that echo on means login name, and
@@ -128,6 +144,79 @@
 	NULL
 };
 
+/*
+ * PAM conversation function
+ * Here we assume (for now, at least) that echo on means login name, and
+ * echo off means password.
+ */
+
+static int smb_pam_passchange_conv(int num_msg,
+		    const struct pam_message **msg,
+		    struct pam_response **resp,
+		    void *appdata_ptr)
+{
+	int replies = 0;
+	struct pam_response *reply = NULL;
+
+	reply = malloc(sizeof(struct pam_response) * num_msg);
+	if (!reply)
+		return PAM_CONV_ERR;
+
+	for (replies = 0; replies < num_msg; replies++)
+	{
+		switch (msg[replies]->msg_style)
+		{
+			case PAM_PROMPT_ECHO_ON:
+				reply[replies].resp_retcode = PAM_SUCCESS;
+			reply[replies].resp =
+					COPY_STRING(PAM_username);
+				/* PAM frees resp */
+				break;
+
+			case PAM_PROMPT_ECHO_OFF:
+				reply[replies].resp_retcode = PAM_SUCCESS;
+				DEBUG(10,("PAM Replied: %s\n", msg[replies]->msg));
+				if (strncmp(lp_pam_currentpw_prompt(), msg[replies]->msg, strlen(lp_pam_currentpw_prompt())) == 0) {
+					reply[replies].resp =
+						COPY_STRING(PAM_password);
+				} else if (strncmp(lp_pam_newpw_prompt(), msg[replies]->msg, strlen(lp_pam_newpw_prompt())) == 0) {
+					reply[replies].resp =
+						COPY_STRING(PAM_newpassword);
+				} else if (strncmp(lp_pam_repeatpw_prompt(), msg[replies]->msg, strlen(lp_pam_repeatpw_prompt())) == 0) {
+					reply[replies].resp =
+						COPY_STRING(PAM_newpassword);
+				} else {
+					DEBUG(3,("Could not find reply for PAM prompt: %s\n",msg[replies]->msg));
+					DEBUG(5,("Prompts available:\n CurrentPW: \"%s\"\n NewPW: \"%s\"\n RepeatPW: \"%s\"\n",lp_pam_currentpw_prompt(),lp_pam_newpw_prompt(),lp_pam_repeatpw_prompt()));
+				}
+				/* PAM frees resp */
+				break;
+
+			case PAM_TEXT_INFO:
+				/* fall through */
+
+			case PAM_ERROR_MSG:
+				/* ignore it... */
+				reply[replies].resp_retcode = PAM_SUCCESS;
+				reply[replies].resp = NULL;
+				break;
+
+			default:
+				/* Must be an error of some sort... */
+				free(reply);
+				return PAM_CONV_ERR;
+		}
+	}
+	if (reply)
+		*resp = reply;
+	return PAM_SUCCESS;
+}
+
+static struct pam_conv smb_pam_passchange_conversation = {
+	&smb_pam_passchange_conv,
+	NULL
+};
+
 /* 
  * PAM Closing out cleanup handler
  */
@@ -149,15 +238,19 @@
 /*
  * Start PAM authentication for specified account
  */
-static BOOL smb_pam_start(pam_handle_t **pamh, char *user, char *rhost)
+static BOOL smb_pam_start(pam_handle_t **pamh, char *user, char *rhost, struct pam_conv * selected_pam_conv)
 {
 	int pam_error;
 
 	*pamh = (pam_handle_t *)NULL;
 
 	DEBUG(4,("PAM: Init user: %s\n", user));
+
+	if (selected_pam_conv == NULL) {
+		selected_pam_conv = &smb_pam_conversation;
+	}
 
-	pam_error = pam_start("samba", user, &smb_pam_conversation, pamh);
+	pam_error = pam_start("samba", user, selected_pam_conv, pamh);
 	if( !smb_pam_error_handler(*pamh, pam_error, "Init Failed", 0)) {
 		*pamh = (pam_handle_t *)NULL;
 		return False;
@@ -194,94 +287,114 @@
 /*
  * PAM Authentication Handler
  */
-static BOOL smb_pam_auth(pam_handle_t *pamh, char *user, char *password)
+static uint32 smb_pam_auth(pam_handle_t *pamh, char *user, char *password)
 {
 	int pam_error;
-
+	uint32 nt_status = NT_STATUS_LOGON_FAILURE;
+	
 	/*
 	 * To enable debugging set in /etc/pam.d/samba:
 	 *	auth required /lib/security/pam_pwdb.so nullok shadow audit
 	 */
 	
-	DEBUG(4,("PAM: Authenticate User: %s\n", user));
-	pam_error = pam_authenticate(pamh, PAM_SILENT); /* Can we authenticate user? */
+        DEBUG(4,("PAM: Authenticate User: %s\n", user));
+	pam_error = pam_authenticate(pamh, PAM_SILENT | lp_null_passwords() ? 0 : PAM_DISALLOW_NULL_AUTHTOK); /* Can we authenticate user? */
 	switch( pam_error ){
 		case PAM_AUTH_ERR:
 			DEBUG(2, ("PAM: Athentication Error\n"));
+			nt_status = NT_STATUS_WRONG_PASSWORD;
 			break;
 		case PAM_CRED_INSUFFICIENT:
 			DEBUG(2, ("PAM: Insufficient Credentials\n"));
+			nt_status = NT_STATUS_INSUFFICIENT_LOGON_INFO;
 			break;
 		case PAM_AUTHINFO_UNAVAIL:
 			DEBUG(2, ("PAM: Authentication Information Unavailable\n"));
+			nt_status = NT_STATUS_LOGON_FAILURE;
 			break;
 		case PAM_USER_UNKNOWN:
 			DEBUG(2, ("PAM: Username NOT known to Authentication system\n"));
+			nt_status = NT_STATUS_NO_SUCH_USER;
 			break;
 		case PAM_MAXTRIES:
 			DEBUG(2, ("PAM: One or more authentication modules reports user limit exceeeded\n"));
+			nt_status = NT_STATUS_REMOTE_SESSION_LIMIT;
 			break;
 		case PAM_ABORT:
 			DEBUG(0, ("PAM: One or more PAM modules failed to load\n"));
+			nt_status = NT_STATUS_LOGON_FAILURE;
 			break;
 	        case PAM_SUCCESS:
 			DEBUG(4, ("PAM: User %s Authenticated OK\n", user));
+			nt_status = NT_STATUS_NOPROBLEMO;
 		        break;
 		default:
-			DEBUG(0, ("PAM: UNKNOWN ERROR while authenticating user %s\n", user));
+			DEBUG(0, ("PAM: UNKNOWN ERROR (%d) while authenticating user %s\n", pam_error, user));
+			nt_status = NT_STATUS_LOGON_FAILURE;
 	}
-	if(!smb_pam_error_handler(pamh, pam_error, "Authentication Failure", 2)) {
+	if(!smb_pam_nt_status_error_handler(pamh, pam_error, "Authentication Failure", 2, &nt_status)) {
 		smb_pam_end(pamh);
-		return False;
+		return nt_status;
 	}
 	/* If this point is reached, the user has been authenticated. */
-	return (True);
+	return nt_status;
 }
 
 /* 
  * PAM Account Handler
  */
-static BOOL smb_pam_account(pam_handle_t *pamh, char * user, char * password, BOOL pam_auth)
+static uint32 smb_pam_account(pam_handle_t *pamh, char * user, char * password)
 {
 	int pam_error;
+	uint32 nt_status = NT_STATUS_ACCOUNT_DISABLED;
 
 	DEBUG(4,("PAM: Account Management for User: %s\n", user));
 	pam_error = pam_acct_mgmt(pamh, PAM_SILENT); /* Is user account enabled? */
 	switch( pam_error ) {
 		case PAM_AUTHTOK_EXPIRED:
 			DEBUG(2, ("PAM: User is valid but password is expired\n"));
+			nt_status = NT_STATUS_PASSWORD_EXPIRED;
 			break;
 		case PAM_ACCT_EXPIRED:
 			DEBUG(2, ("PAM: User no longer permitted to access system\n"));
+			nt_status = NT_STATUS_ACCOUNT_EXPIRED;
 			break;
 		case PAM_AUTH_ERR:
 			DEBUG(2, ("PAM: There was an authentication error\n"));
+			nt_status = NT_STATUS_LOGON_FAILURE;
 			break;
 		case PAM_PERM_DENIED:
 			DEBUG(0, ("PAM: User is NOT permitted to access system at this time\n"));
+			nt_status = NT_STATUS_ACCOUNT_RESTRICTION;
 			break;
 		case PAM_USER_UNKNOWN:
 			DEBUG(0, ("PAM: User \"%s\" is NOT known to account management\n", user));
+			nt_status = NT_STATUS_NO_SUCH_USER;
 			break;
 	        case PAM_SUCCESS:
 			DEBUG(4, ("PAM: Account OK for User: %s\n", user));
-		        break;
+		        nt_status = NT_STATUS_NOPROBLEMO;
+			break;
 		default:
-			DEBUG(0, ("PAM: UNKNOWN ERROR for User: %s\n", user));
+			nt_status = NT_STATUS_ACCOUNT_DISABLED;
+			DEBUG(0, ("PAM: UNKNOWN PAM ERROR (%d) during Account Management for User: %s\n", pam_error, user));
 	}
-	if(!smb_pam_error_handler(pamh, pam_error, "Account Check Failed", 2)) {
+	if(!smb_pam_nt_status_error_handler(pamh, pam_error, "Account Check Failed", 2, &nt_status)) {
 		smb_pam_end(pamh);
-		return False;
+		return nt_status;
 	}
-
-	/* Skip the pam_setcred() call if we didn't use pam_authenticate()
-	   for authentication -- it's an error to call pam_setcred without
-	   calling pam_authenticate first */
-	if (!pam_auth) {
-		DEBUG(4, ("PAM: Skipping setcred for user: %s (using encrypted passwords)\n", user));
-		return True;
-	}
+	
+	/* If this point is reached, the user has been authenticated. */
+	return (nt_status);
+}
 
+/* 
+ * PAM Credential Setting
+ */
+static BOOL smb_pam_setcred(pam_handle_t *pamh, char * user)
+{
+	int pam_error;
+	uint32 nt_status = NT_STATUS_NO_TOKEN;
 	/*
 	 * This will allow samba to aquire a kerberos token. And, when
 	 * exporting an AFS cell, be able to /write/ to this cell.
@@ -291,37 +404,43 @@
 	pam_error = pam_setcred(pamh, (PAM_ESTABLISH_CRED|PAM_SILENT)); 
 	switch( pam_error ) {
 		case PAM_CRED_UNAVAIL:
-			DEBUG(0, ("PAM: Credentials not found for user:%s", user ));
+			DEBUG(0, ("PAM: Credentials not found for user:%s\n", user ));
+			nt_status = NT_STATUS_NO_TOKEN;
 			break;
 		case PAM_CRED_EXPIRED:
-			DEBUG(0, ("PAM: Credentials for user: \"%s\" EXPIRED!", user ));
+			DEBUG(0, ("PAM: Credentials for user: \"%s\" EXPIRED!\n", user ));
+			nt_status = NT_STATUS_PASSWORD_EXPIRED;
 			break;
 		case PAM_USER_UNKNOWN:
-			DEBUG(0, ("PAM: User: \"%s\" is NOT known so can not set credentials!", user ));
+			DEBUG(0, ("PAM: User: \"%s\" is NOT known so can not set credentials!\n", user ));
+			nt_status = NT_STATUS_NO_SUCH_USER;
 			break;
 		case PAM_CRED_ERR:
-			DEBUG(0, ("PAM: Unknown setcredentials error - unable to set credentials for %s", user ));
+			DEBUG(0, ("PAM: Unknown setcredentials error - unable to set credentials for %s\n", user ));
+			nt_status = NT_STATUS_LOGON_FAILURE;
 			break;
 	        case PAM_SUCCESS:
 			DEBUG(4, ("PAM: SetCredentials OK for User: %s\n", user));
+			nt_status = NT_STATUS_NOPROBLEMO;
 		        break;
 		default:
-			DEBUG(0, ("PAM: Error Condition Unknown in pam_setcred function call!"));
+			DEBUG(0, ("PAM: UNKNOWN PAM ERROR (%d) during SetCredentials for User: %s\n", pam_error, user));
+			nt_status = NT_STATUS_NO_TOKEN;
 	}
-	if(!smb_pam_error_handler(pamh, pam_error, "Set Credential Failure", 2)) {
+	if(!smb_pam_nt_status_error_handler(pamh, pam_error, "Set Credential Failure", 2, &nt_status)) {
 		smb_pam_end(pamh);
-		return False;
+		return nt_status;
 	}
 	
 	/* If this point is reached, the user has been authenticated. */
-	return (True);
+	return (nt_status);
 }
 
 
 /*
  * PAM Internal Session Handler
  */
-static BOOL smb_internal_pam_session(pam_handle_t *pamh, char *user, char *tty, BOOL flag)
+static BOOL smb_internal_pam_session(pam_handle_t *pamh, char *user, const char *tty, BOOL flag)
 {
 	int pam_error;
 
@@ -331,84 +450,122 @@
 #ifdef PAM_TTY
 	DEBUG(4,("PAM: tty set to: %s\n", tty));
 	pam_error = pam_set_item(pamh, PAM_TTY, tty);
-	if (!smb_pam_error_handler(pamh, pam_error, "set tty failed", 0))
+	if (!smb_pam_error_handler(pamh, pam_error, "set tty failed", 0)) {
+		smb_pam_end(pamh);
 		return False;
+	}
 #endif
-
+	
 	if (flag) {
 		pam_error = pam_open_session(pamh, PAM_SILENT);
-		if (!smb_pam_error_handler(pamh, pam_error, "session setup failed", 0))
+		if (!smb_pam_error_handler(pamh, pam_error, "session setup failed", 0)) {
+			smb_pam_end(pamh);
 			return False;
+		}
 	} else {
-		pam_error = pam_close_session(pamh, PAM_SILENT);
-		if (!smb_pam_error_handler(pamh, pam_error, "session close failed", 0))
+		pam_setcred(pamh, (PAM_DELETE_CRED|PAM_SILENT));  /* We don't care if this fails */ 
+		pam_error = pam_close_session(pamh, PAM_SILENT);  /* This will probably pick up the error anyway */
+		if (!smb_pam_error_handler(pamh, pam_error, "session close failed", 0)){
+			smb_pam_end(pamh);
 			return False;
+		}
 	}
 	return (True);
 }
 
-/*
- * PAM Externally accessible Session handler
- */
 
-BOOL smb_pam_session(BOOL flag, const char *in_user, char *tty, char *rhost)
+/* 
+ * PAM Password Changer
+ */
+static BOOL smb_pam_chauthtok(pam_handle_t *pamh, char * user, char * oldpassword, char * newpassword)
 {
-	pam_handle_t *pamh = NULL;
-	char * user;
-
-	/* Ignore PAM if told to. */
-
-	if (!lp_obey_pam_restrictions())
-		return True;
+	int pam_error;
 
-	user = strdup(in_user);
-	if ( user == NULL ) {
-		DEBUG(0, ("PAM: PAM_session Malloc Failed!\n"));
-		return False;
-	}
+	PAM_username = user;
+	PAM_password = oldpassword;
+	PAM_newpassword = newpassword;
 
-	if (!smb_pam_start(&pamh, user, rhost)) {
-		return False;
+        DEBUG(4,("PAM: Password Change for User: %s\n", user));
+	pam_error = pam_chauthtok(pamh, PAM_SILENT); /* Change Password */
+	switch( pam_error ) {
+	case PAM_AUTHTOK_ERR:
+		DEBUG(2, ("PAM: unable to obtain the new authentication token - is password to weak?\n"));
+		break;
+	case PAM_AUTHTOK_RECOVER_ERR:
+		DEBUG(2, ("PAM: unable to obtain the old authentication token - was the old password wrong?.\n"));
+		break;
+	case PAM_AUTHTOK_LOCK_BUSY:
+		DEBUG(2, ("PAM: unable to change the authentication token since it is currently locked.\n"));
+		break;
+	case PAM_AUTHTOK_DISABLE_AGING:
+		DEBUG(2, ("PAM: Authentication token aging has been disabled.\n"));
+		break;
+	case PAM_PERM_DENIED:
+		DEBUG(0, ("PAM: Permission denied.\n"));
+		break;
+	case PAM_TRY_AGAIN:
+		DEBUG(0, ("PAM: Could not update all authentication token(s). No authentication tokens were updated.\n"));
+		break;
+	case PAM_USER_UNKNOWN:
+		DEBUG(0, ("PAM: User not known to PAM\n"));
+		break;
+	case PAM_SUCCESS:
+		DEBUG(4, ("PAM: Account OK for User: %s\n", user));
+		break;
+	default:
+		DEBUG(0, ("PAM: UNKNOWN PAM ERROR (%d) for User: %s\n", pam_error, user));
 	}
 
-	if (!smb_internal_pam_session(pamh, user, tty, flag)) {
+	if(!smb_pam_error_handler(pamh, pam_error, "Password Change Failed", 2)) {
 		smb_pam_end(pamh);
 		return False;
 	}
-	return smb_pam_end(pamh);
+	
+	/* If this point is reached, the password has changed. */
+	return True;
 }
 
+
 /*
  * PAM Externally accessible Account handler
  */
-BOOL smb_pam_accountcheck(char * user)
+uint32 smb_pam_accountcheck(char * user)
 {
 	pam_handle_t *pamh = NULL;
 
+	uint32 nt_status = NT_STATUS_ACCOUNT_DISABLED;
+
 	PAM_username = user;
 	PAM_password = NULL;
 
 	/* Ignore PAM if told to. */
 
 	if (!lp_obey_pam_restrictions())
-		return True;
+		return NT_STATUS_NOPROBLEMO;
 
-	if( smb_pam_start(&pamh, user, NULL)) {
-		if ( smb_pam_account(pamh, user, NULL, False)) {
-			return( smb_pam_end(pamh));
+	if (smb_pam_start(&pamh, user, NULL, NULL)) {
+		nt_status = smb_pam_account(pamh, user, NULL);
+		if (nt_status == NT_STATUS_NOPROBLEMO) {
+			if (smb_pam_end(pamh)) {
+				return nt_status;
+			} else {
+				nt_status = NT_STATUS_ACCOUNT_DISABLED;
+			}
 		}
 	}
 	DEBUG(0, ("PAM: Account Validation Failed - Rejecting User!\n"));
-	return( False );
+	return( nt_status );
 }
 
 /*
  * PAM Password Validation Suite
  */
-BOOL smb_pam_passcheck(char * user, char * password)
+uint32 smb_pam_passcheck(char * user, char * password)
 {
 	pam_handle_t *pamh = NULL;
 
+	uint32 nt_status = NT_STATUS_LOGON_FAILURE;
+	
 	PAM_username = user;
 	PAM_password = password;
 
@@ -418,21 +575,128 @@
 	 * compiled --with-pam.
 	 */
 
-	if( smb_pam_start(&pamh, user, NULL)) {
-		if ( smb_pam_auth(pamh, user, password)) {
-			if ( smb_pam_account(pamh, user, password, True)) {
-				return( smb_pam_end(pamh));
+	if (smb_pam_start(&pamh, user, NULL, NULL)) {
+		nt_status = smb_pam_auth(pamh, user, password);
+		if (nt_status == NT_STATUS_NOPROBLEMO) {
+			nt_status = smb_pam_account(pamh, user, password);
+			if (nt_status == NT_STATUS_NOPROBLEMO) {
+				nt_status = smb_pam_setcred(pamh, user);
+				if (nt_status == NT_STATUS_NOPROBLEMO) {
+					if (smb_pam_end(pamh)) {
+						return nt_status;
+					} else {
+						nt_status = NT_STATUS_LOGON_FAILURE;
+					}
+				}
 			}
 		}
 	}
 	DEBUG(0, ("PAM: System Validation Failed - Rejecting User!\n"));
+	return( nt_status );
+}
+
+/*
+ * PAM Externally accessible Session handler
+ */
+BOOL smb_pam_claim_session(const char *in_user, char *tty, char *rhost)
+{
+	pam_handle_t *pamh = NULL;
+	char * user;
+
+	/* Ignore PAM if told to. */
+
+	if (!lp_obey_pam_restrictions())
+		return True;
+
+	/* This is freed by PAM */
+	user = strdup(in_user);
+
+	if ( user == NULL ) {
+                DEBUG(0, ("PAM: PAM_session Malloc Failed!\n"));
+                return False;
+        }
+
+	if (!smb_pam_start(&pamh, user, rhost, NULL)) {
+		return False;
+	}
+
+	if (smb_internal_pam_session(pamh, user, tty, True)) {
+		return smb_pam_end(pamh);
+	} else {
+		return False;
+	}
+}
+
+/*
+ * PAM Externally accessible Session handler
+ */
+BOOL smb_pam_close_session(char *in_user, char *tty, char *rhost)
+{
+	pam_handle_t *pamh = NULL;
+
+	char * user;
+	/* Ignore PAM if told to. */
+
+	if (!lp_obey_pam_restrictions())
+		return True;
+
+	/* This is freed by PAM */
+	user = strdup(in_user);
+	
+	if (!smb_pam_start(&pamh, user, rhost, NULL)) {
+		return False;
+	}
+
+	
+
+	if (smb_internal_pam_session(pamh, user, tty, False)) {
+		return smb_pam_end(pamh);
+	} else {
+		smb_pam_end(pamh);
+		return False;
+	}
+}
+
+/*
+ * PAM Password Change Suite
+ */
+BOOL smb_pam_passchange(char * user, char * oldpassword, char * newpassword)
+{
+
+	/* Appropriate quantities of root should be obtained BEFORE calling this funcation */
+
+	pam_handle_t *pamh = NULL;
+
+	if( smb_pam_start(&pamh, user, NULL, &smb_pam_passchange_conversation))
+	{
+		if (smb_pam_chauthtok(pamh, user, oldpassword, newpassword))
+		{
+			if (smb_pam_end(pamh)) {
+				return True;
+			}
+			
+		}
+	}
+
+	DEBUG(0, ("PAM: Password Change Failed!\n"));
 	return( False );
 }
 
 #else
 
 /* If PAM not used, no PAM restrictions on accounts. */
- BOOL smb_pam_accountcheck(char * user)
+ uint32 smb_pam_accountcheck(char * user)
+{
+	return NT_STATUS_NOPROBLEMO;
+}
+
+/* If PAM not used, also no PAM restrictions on sessions. */
+ BOOL smb_pam_claim_session(const char *in_user, char *tty, char *rhost)
+{
+	return True;
+}
+
+ BOOL smb_pam_close_session(const char *in_user, char *tty, char *rhost)
 {
 	return True;
 }
Index: source/passdb/pass_check.c
===================================================================
RCS file: /cvsroot/samba/source/passdb/pass_check.c,v
retrieving revision 1.11.4.5
diff -u -r1.11.4.5 pass_check.c
--- source/passdb/pass_check.c	2001/04/23 04:08:29	1.11.4.5
+++ source/passdb/pass_check.c	2001/04/24 13:20:41
@@ -550,7 +550,7 @@
 offset is the first char to try and change (start with 0)
 it assumes the string starts lowercased
 ****************************************************************************/
-static BOOL string_combinations2(char *s, int offset, BOOL (*fn) (char *),
+static BOOL string_combinations2(char *s, int offset, uint32 (*fn) (char *),
 				 int N)
 {
 	int len = strlen(s);
@@ -568,7 +568,7 @@
 		if (!islower(c))
 			continue;
 		s[i] = toupper(c);
-		if (string_combinations2(s, i + 1, fn, N - 1))
+		if (string_combinations2(s, i + 1, fn, N - 1) == NT_STATUS_NOPROBLEMO)
 			return (True);
 		s[i] = c;
 	}
@@ -582,11 +582,11 @@
 offset is the first char to try and change (start with 0)
 it assumes the string starts lowercased
 ****************************************************************************/
-static BOOL string_combinations(char *s, BOOL (*fn) (char *), int N)
+static uint32 string_combinations(char *s, uint32 (*fn) (char *), int N)
 {
 	int n;
 	for (n = 1; n <= N; n++)
-		if (string_combinations2(s, 0, fn, n))
+		if (string_combinations2(s, 0, fn, n) == NT_STATUS_NOPROBLEMO)
 			return (True);
 	return (False);
 }
@@ -595,54 +595,67 @@
 /****************************************************************************
 core of password checking routine
 ****************************************************************************/
-static BOOL password_check(char *password)
+static uint32 password_check(char *password)
 {
-
+  BOOL ret;
 #ifdef WITH_PAM
 	return (smb_pam_passcheck(this_user, password));
 #endif /* WITH_PAM */
 
 #ifdef WITH_AFS
 	if (afs_auth(this_user, password))
-		return (True);
+		return (NT_STATUS_NOPROBLEMO);
 #endif /* WITH_AFS */
 
 #ifdef WITH_DFS
 	if (dfs_auth(this_user, password))
-		return (True);
+		return (NT_STATUS_NOPROBLEMO);
 #endif /* WITH_DFS */
 
 #ifdef KRB5_AUTH
 	if (krb5_auth(this_user, password))
-		return (True);
+		return (NT_STATUS_NOPROBLEMO);
 #endif /* KRB5_AUTH */
 
 #ifdef KRB4_AUTH
 	if (krb4_auth(this_user, password))
-		return (True);
+		return (NT_STATUS_NOPROBLEMO);
 #endif /* KRB4_AUTH */
 
 #ifdef OSF1_ENH_SEC
-	{
-		BOOL ret =
-			(strcmp
-			 (osf1_bigcrypt(password, this_salt),
+	
+	        ret = (strcmp(osf1_bigcrypt(password, this_salt),
 			  this_crypted) == 0);
 		if (!ret) {
 			DEBUG(2,
 			      ("OSF1_ENH_SEC failed. Trying normal crypt.\n"));
 			ret = (strcmp((char *)crypt(password, this_salt), this_crypted) == 0);
 		}
-		return ret;
-	}
+	        if (ret) {
+		        return NT_STATUS_NOPROBLEMO;
+		} else {
+		        return NT_STATUS_WRONG_PASSWORD;
+		}
+
 #endif /* OSF1_ENH_SEC */
 
 #ifdef ULTRIX_AUTH
-	return (strcmp((char *)crypt16(password, this_salt), this_crypted) == 0);
+	ret = (strcmp((char *)crypt16(password, this_salt), this_crypted) == 0);
+        if (ret) {
+          return NT_STATUS_NOPROBLEMO;
+        } else {
+	  return NT_STATUS_WRONG_PASSWORD;
+	}
+
 #endif /* ULTRIX_AUTH */
 
 #ifdef LINUX_BIGCRYPT
-	return (linux_bigcrypt(password, this_salt, this_crypted));
+	ret = (linux_bigcrypt(password, this_salt, this_crypted));
+        if (ret) {
+	  return NT_STATUS_NOPROBLEMO;
+	} else {
+	  return NT_STATUS_WRONG_PASSWORD;
+	}
 #endif /* LINUX_BIGCRYPT */
 
 #if defined(HAVE_BIGCRYPT) && defined(HAVE_CRYPT) && defined(USE_BOTH_CRYPT_CALLS)
@@ -655,20 +668,35 @@
 	 */
 
 	if (strcmp(bigcrypt(password, this_salt), this_crypted) == 0)
-		return True;
+		return NT_STATUS_NOPROBLEMO;
 	else
-		return (strcmp((char *)crypt(password, this_salt), this_crypted) == 0);
+		ret = (strcmp((char *)crypt(password, this_salt), this_crypted) == 0);
+                if (ret) {
+		  return NT_STATUS_NOPROBLEMO;
+		} else {
+		  return NT_STATUS_WRONG_PASSWORD;
+		}
 #else /* HAVE_BIGCRYPT && HAVE_CRYPT && USE_BOTH_CRYPT_CALLS */
 
 #ifdef HAVE_BIGCRYPT
-	return (strcmp(bigcrypt(password, this_salt), this_crypted) == 0);
+	ret = (strcmp(bigcrypt(password, this_salt), this_crypted) == 0);
+        if (ret) {
+	  return NT_STATUS_NOPROBLEMO;
+	} else {
+	  return NT_STATUS_WRONG_PASSWORD;
+	}
 #endif /* HAVE_BIGCRYPT */
 
 #ifndef HAVE_CRYPT
 	DEBUG(1, ("Warning - no crypt available\n"));
-	return (False);
+	return (NT_STATUS_LOGON_FAILURE);
 #else /* HAVE_CRYPT */
-	return (strcmp((char *)crypt(password, this_salt), this_crypted) == 0);
+	ret = (strcmp((char *)crypt(password, this_salt), this_crypted) == 0);
+        if (ret) {
+	  return NT_STATUS_NOPROBLEMO;
+	} else {
+	  return NT_STATUS_WRONG_PASSWORD;
+	}
 #endif /* HAVE_CRYPT */
 #endif /* HAVE_BIGCRYPT && HAVE_CRYPT && USE_BOTH_CRYPT_CALLS */
 }
@@ -679,28 +707,30 @@
 check if a username/password is OK
 the function pointer fn() points to a function to call when a successful
 match is found and is used to update the encrypted password file 
-return True on correct match, False otherwise
+return NT_STATUS_NOPROBLEMO on correct match, NT_STATUS_WRONG_PASSWORD otherwise
 ****************************************************************************/
-
-BOOL pass_check(char *user, char *password, int pwlen, struct passwd *pwd,
+uint32 pass_check(char *user, char *password, int pwlen, struct passwd *pwd,
 		BOOL (*fn) (char *, char *))
 {
 	pstring pass2;
 	int level = lp_passwordlevel();
+	uint32 nt_status;
 	struct passwd *pass = NULL;
 
-	if (password)
-		password[pwlen] = 0;
+	fstrcpy(this_user, user);
 
 #if DEBUG_PASSWORD
 	DEBUG(100, ("checking user=[%s] pass=[%s]\n", user, password));
 #endif
 
+	if (password)
+		password[pwlen] = 0;
+
 	if (!password)
-		return (False);
+		return (NT_STATUS_WRONG_PASSWORD);
 
 	if (((!*password) || (!pwlen)) && !lp_null_passwords())
-		return (False);
+		return (NT_STATUS_WRONG_PASSWORD);
 
 	if (pwd && !user) {
 		pass = (struct passwd *)pwd;
@@ -726,7 +756,7 @@
 
 	if (!pass) {
 		DEBUG(3, ("Couldn't find user %s\n", user));
-		return (False);
+		return (NT_STATUS_NO_SUCH_USER);
 	}
 
 #ifdef HAVE_GETSPNAM
@@ -790,7 +820,6 @@
 #endif
 
 	/* extract relevant info */
-	fstrcpy(this_user, pass->pw_name);
 	fstrcpy(this_salt, pass->pw_passwd);
 
 #if defined(HAVE_TRUNCATED_SALT)
@@ -805,30 +834,34 @@
 		if (!lp_null_passwords()) {
 			DEBUG(2, ("Disallowing %s with null password\n",
 				  this_user));
-			return (False);
+			return (NT_STATUS_WRONG_PASSWORD);
 		}
 		if (!*password) {
 			DEBUG(3,
 			      ("Allowing access to %s with null password\n",
 			       this_user));
-			return (True);
+			return (NT_STATUS_NOPROBLEMO);
 		}
 	}
 
 #endif /* WITH_PAM */
 
 	/* try it as it came to us */
-	if (password_check(password)) {
-		if (fn)
-			fn(user, password);
-		return (True);
-	}
+        nt_status = password_check(password);
+        if (nt_status == NT_STATUS_NOPROBLEMO) {
+                if (fn)
+                        fn(user, password);
+		return (nt_status);
+	} else if (nt_status != NT_STATUS_WRONG_PASSWORD) {
+                /* No point continuing if its not the password thats to blame (ie PAM disabled). */
+                return (nt_status);
+        }
 
 	/* if the password was given to us with mixed case then we don't
-	   need to proceed as we know it hasn't been case modified by the
-	   client */
+	 * need to proceed as we know it hasn't been case modified by the
+	 * client */
 	if (strhasupper(password) && strhaslower(password)) {
-		return (False);
+		return (NT_STATUS_WRONG_PASSWORD);
 	}
 
 	/* make a copy of it */
@@ -837,10 +870,11 @@
 	/* try all lowercase if it's currently all uppercase */
 	if (strhasupper(password)) {
 		strlower(password);
-		if (password_check(password)) {
-			if (fn)
+		nt_status = password_check(password);
+		if (nt_status == NT_STATUS_NOPROBLEMO) {
+		        if (fn)
 				fn(user, password);
-			return (True);
+			return (nt_status);
 		}
 	}
 
@@ -848,20 +882,24 @@
 	if (level < 1) {
 		/* restore it */
 		fstrcpy(password, pass2);
-		return (False);
+		return (NT_STATUS_WRONG_PASSWORD);
 	}
 
 	/* last chance - all combinations of up to level chars upper! */
 	strlower(password);
 
-	if (string_combinations(password, password_check, level)) {
-		if (fn)
+        nt_status = (string_combinations(password, password_check, level)); 
+        if (nt_status == NT_STATUS_NOPROBLEMO) {
+                if (fn)
 			fn(user, password);
-		return (True);
+		return (NT_STATUS_NOPROBLEMO);
 	}
-
+        
 	/* restore it */
 	fstrcpy(password, pass2);
 
-	return (False);
+	return (NT_STATUS_WRONG_PASSWORD);
 }
+
+
+
Index: source/rpc_server/srv_netlog_nt.c
===================================================================
RCS file: /cvsroot/samba/source/rpc_server/srv_netlog_nt.c,v
retrieving revision 1.1.2.12
diff -u -r1.1.2.12 srv_netlog_nt.c
--- source/rpc_server/srv_netlog_nt.c	2001/04/23 23:31:00	1.1.2.12
+++ source/rpc_server/srv_netlog_nt.c	2001/04/24 13:20:43
@@ -593,12 +593,6 @@
 	  }
 	} 
 
-#ifdef WITH_PAM
-	if (!smb_pam_accountcheck(nt_username)) {
-	  return NT_STATUS_ACCOUNT_DISABLED;
-	}
-#endif
-
 	if (!(smb_pass->acct_ctrl & ACB_PWNOTREQ)) {
 		switch (q_u->sam_id.logon_level) {
 		case INTERACTIVE_LOGON_TYPE:
@@ -612,6 +606,13 @@
 		}
 	}
     
+	become_root();
+	status = smb_pam_accountcheck(nt_username);
+	unbecome_root();
+	if (status != NT_STATUS_NOPROBLEMO) {
+		return status;
+	}
+
 	if (status != NT_STATUS_NOPROBLEMO)
 		return status;
 
Index: source/rpc_server/srv_pipe.c
===================================================================
RCS file: /cvsroot/samba/source/rpc_server/srv_pipe.c,v
retrieving revision 1.50.2.14
diff -u -r1.50.2.14 srv_pipe.c
--- source/rpc_server/srv_pipe.c	2001/04/08 20:22:53	1.50.2.14
+++ source/rpc_server/srv_pipe.c	2001/04/24 13:20:45
@@ -380,6 +380,13 @@
 			return False;
 		}
 
+		if (smb_pam_accountcheck(pipe_user_name) == NT_STATUS_NOPROBLEMO) {
+			DEBUG(1,("api_pipe_ntlmssp_verify: PAM denied account for user %s.\n",
+				pipe_user_name));
+			unbecome_root();
+			return False;
+		}
+
 		if(!(smb_pass = getsmbpwnam(pipe_user_name))) {
 			DEBUG(1,("api_pipe_ntlmssp_verify: Cannot find user %s in smb passwd database.\n",
 				pipe_user_name));
Index: source/smbd/chgpasswd.c
===================================================================
RCS file: /cvsroot/samba/source/smbd/chgpasswd.c,v
retrieving revision 1.64.4.1
diff -u -r1.64.4.1 chgpasswd.c
--- source/smbd/chgpasswd.c	2001/02/21 00:11:55	1.64.4.1
+++ source/smbd/chgpasswd.c	2001/04/24 13:20:47
@@ -52,6 +52,7 @@
 extern int DEBUGLEVEL;
 
 #if ALLOW_CHANGE_PASSWORD
+#ifndef WITH_PAM /* We have MUCH better ways of doing this... */
 
 static int findpty(char **slave)
 {
@@ -525,6 +526,19 @@
 	return (chat_with_program
 		(passwordprogram, name, chatsequence, as_root));
 }
+
+#else /* not WITH_PAM */
+BOOL chgpasswd(char *name, char *oldpass, char *newpass, BOOL as_root)
+{
+	if (as_root) {
+		become_root();
+	}
+	return smb_pam_passchange(name, oldpass, newpass);
+	if (as_root) {
+		unbecome_root();
+	}
+}
+#endif
 
 #else /* ALLOW_CHANGE_PASSWORD */
 BOOL chgpasswd(char *name, char *oldpass, char *newpass, BOOL as_root)
Index: source/smbd/password.c
===================================================================
RCS file: /cvsroot/samba/source/smbd/password.c,v
retrieving revision 1.186.2.19
diff -u -r1.186.2.19 password.c
--- source/smbd/password.c	2001/04/23 04:08:29	1.186.2.19
+++ source/smbd/password.c	2001/04/24 13:20:51
@@ -500,7 +500,8 @@
 		return True;
 	}
 
-	if((smb_pass->smb_passwd != NULL) && 
+	if(lp_lanman_auth() && 
+	   (smb_pass->smb_passwd != NULL) && 
 	   smb_password_check((char *)lm_pass, 
 			      (uchar *)smb_pass->smb_passwd, challenge)) {
 		DEBUG(4,("LM MD4 password check succeeded\n"));
@@ -621,14 +622,14 @@
 		 */
 
 		if (ret)
-		  return smb_pam_accountcheck(user);
+		  return (smb_pam_accountcheck(user) == NT_STATUS_NOPROBLEMO);
 
 		return ret;
 	} 
 
-	return pass_check(user, password, pwlen, pwd, 
+	return (pass_check(user, password, pwlen, pwd, 
 			  lp_update_encrypted() ? 
-			  update_smbpassword_file : NULL);
+			  update_smbpassword_file : NULL) == NT_STATUS_NOPROBLEMO);
 }
 
 /****************************************************************************
Index: source/smbd/session.c
===================================================================
RCS file: /cvsroot/samba/source/smbd/session.c,v
retrieving revision 1.1.2.5
diff -u -r1.1.2.5 session.c
--- source/smbd/session.c	2001/04/23 23:07:53	1.1.2.5
+++ source/smbd/session.c	2001/04/24 13:20:52
@@ -99,6 +99,13 @@
 	sessionid.id_num = i;
 	sessionid.pid = pid;
 
+	if (!smb_pam_claim_session(sessionid.username, sessionid.id_str, sessionid.hostname)) {
+		DEBUG(1,("pam_session rejected the session for %s [%s]\n",
+			 sessionid.username, sessionid.id_str));
+		tdb_delete(tdb, key);
+		return False;
+	}
+
 	dlen = tdb_pack(dbuf, sizeof(dbuf), "fffdd",
 			sessionid.username, sessionid.hostname, sessionid.id_str,
 			sessionid.id_num, sessionid.pid);
@@ -110,15 +117,6 @@
 		return False;
 	}
 
-#if WITH_PAM
-	if (!smb_pam_session(True, sessionid.username, sessionid.id_str, sessionid.hostname)) {
-		DEBUG(1,("smb_pam_session rejected the session for %s [%s]\n",
-			 sessionid.username, sessionid.id_str));
-		tdb_delete(tdb, key);
-		return False;
-	}
-#endif
-
 #if WITH_UTMP	
 	if (lp_utmp()) {
 		sys_utmp_claim(sessionid.username, sessionid.hostname, 
@@ -169,9 +167,7 @@
 	}
 #endif
 
-#if WITH_PAM
-	smb_pam_session(False, sessionid.username, sessionid.id_str, sessionid.hostname);
-#endif
+	smb_pam_close_session(sessionid.username, sessionid.id_str, sessionid.hostname);
 
 	tdb_delete(tdb, key);
 }
Index: source/web/cgi.c
===================================================================
RCS file: /cvsroot/samba/source/web/cgi.c,v
retrieving revision 1.37.2.3
diff -u -r1.37.2.3 cgi.c
--- source/web/cgi.c	2001/03/09 01:06:59	1.37.2.3
+++ source/web/cgi.c	2001/04/24 13:20:54
@@ -377,7 +377,7 @@
 
 	tested_pass = True;
 
-	if(pass_check(user, user_pass, strlen(user_pass), NULL, NULL) == True) {
+	if(pass_check(user, user_pass, strlen(user_pass), NULL, NULL) == NT_STATUS_NOPROBLEMO) {
 
 		/*
 		 * Password was ok.


More information about the samba-technical mailing list