[PATCH] Authentication rewrite

Andrew Bartlett abartlet at pcug.org.au
Wed Apr 18 03:15:40 GMT 2001


For some unknown reason (actually, to implant some sanity into a product
I use a LOT) I decided to reorganize much of samba's authentication
infrastructure.  

The basic idea came from something I saw in Samba-TNG a while back:  All
authentications were changed to domain logons, and passed through one
piece of code.

My implementation is slightly different, but I still use the RPC
authentication setup to get the job done.  The basic idea is to create a
ctr structure (with an id? element) that contains all the information
needed to authenticate the user, we then pass this to the net_logon()
function, where all the checks are done - no matter what protocol the
password was passed over.

This allows things like checking accounts with PAM (even for encrypted
logins), and null password prohibition to occur in one place.  It also
allows rhosts/hosts.equiv to be used for domain logins, and I think it
makes domain trusts a bit easier to implement.  I intend to use it to
add ntlmv2 support to samba, as that doesn't look too difficult.

This patch adds NT_STATUS constants to much of samba, and is only a few
lines away from reporting them to normal file-share clients.  It also
starts to move all authentication code (as opposed to passdb code) into
an 'auth' subdirectory.  (I would move pass_check.c and pampass.c, but I
want to preserve the patch readers sanity).

This patch simply reorganize the authentication, and broadens the use of
rhosts/hosts.equiv.  (Not that I think its sane to use either of these
protocols, but I prefer that their use is easy to follow).  

I hope not to have changed existing behavior too much, here are the
changes I know about:
 - All logons much pass the smb_pass->acct_ctrl & ACB_DISABLED test
 - All logons to a 'null password' account are accepted, not just
encrypted logons
	(this is of course after checking lp_null_passswords())
 - SWAT logins are treated the same as all others, instead of going
direct to pass_check.

I will in future (ie once this is tested/commented on) move the domain
security code into this function - allowing its use for both domain
logons (domain logon proxy server?, domain trusts?) and for file-share
access.  I will also look at what server level security requires in this
area.  This code should also allow interesting things like enabling NTLM
authentication with SWAT, as there is now a much more defined interface
for that kind of stuff.

I have tested the new code with Win98 and smbclient, and will test with
NT4 when I get VMware working.  (Yes, the changes to rpc_server are
completely untested, sorry).

In the minor hacks department, this code also automatically creates
smb_pwd structs when a user exists in /etc/passwd but not in
/etc/samba/smbpasswd, which I hope is a better solution to the issue
than the one in TNG (the problem is that a plain-text login could create
a smbpasswd entry with 'update encrypted', but some of the code needs
that smbpasswd entry, your options are to either delay opening the file
- which doesn't work well with my design anyway - or to fake up the
entry.)

The update encrypted setup might work, but I haven't tested it.  Also I
think I may have broken remote password changes - I'll get that fixed
once I get some comments in on the basic idea.

Finally, I hope I have done justice to people with my Copyright
attributions, I have moved a lot of code around, and I have tried my
best to take the appropriate copyright with them.

As is noted in the patch, the 'General Logon' code is from Samba-TNG. 
They have done some really neat work over there, and this particular
code made my job a LOT easier.

At this point I would like to thank everybody who has worked on Samba
and Samba-TNG, its a marvelous product, and one I am glad to have the
pleasure of contributing to.

This patch is a work in progress, how it progresses depends very much on
the reaction it receives :-).

Andrew Bartlett
abartlet at pcug.org.au
-- 
Andrew Bartlett
abartlet at pcug.org.au
-------------- next part --------------
Index: source/passdb/pampass.c
===================================================================
RCS file: /cvsroot/samba/source/passdb/pampass.c,v
retrieving revision 1.1.2.7
diff -u -r1.1.2.7 pampass.c
--- source/passdb/pampass.c	2001/04/13 04:09:37	1.1.2.7
+++ source/passdb/pampass.c	2001/04/18 00:41:37
@@ -24,7 +24,7 @@
 /*
  * This module provides PAM based functions for validation of
  * username/password pairs, account managment, session and access control.
- * Note: SMB password checking is done in smbpass.c
+ * Note: SMB password checking is done in auth/auth.c
  */
 
 #include "includes.h"
@@ -69,6 +69,21 @@
 	return True;
 }
 
+static BOOL 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 (!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
@@ -142,6 +157,7 @@
 		pam_error = pam_end(pamh, 0);
 		if(pam_error_handler(pamh, pam_error, "End Cleanup Failed", 2) == True) {
 			DEBUG(4, ("PAM: PAM_END OK.\n"));
+			pamh = NULL;
     			return True;
 		}
        }
@@ -192,9 +208,10 @@
 /*
  * PAM Authentication Handler
  */
-static BOOL pam_auth(pam_handle_t *pamh, char *user, char *password)
+static uint32 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:
@@ -206,86 +223,90 @@
 	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:
+	        default:
 			DEBUG(0, ("PAM: UNKNOWN ERROR while authenticating user %s\n", user));
+		        nt_status = NT_STATUS_LOGON_FAILURE;
 	}
-	if(!pam_error_handler(pamh, pam_error, "Authentication Failure", 2)) {
+	if(!pam_nt_status_error_handler(pamh, pam_error, "Authentication Failure", 2, &nt_status)) {
 		proc_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 pam_account(pam_handle_t *pamh, char * user, char * password)
+static uint32 pam_account(pam_handle_t *pamh, char * user, char * password)
 {
 	int pam_error;
+	uint32 nt_status = NT_STATUS_LOGON_FAILURE;
 
         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_DISABLED;
 			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));
+			DEBUG(4, ("PAM: UNKNOWN PAM ERROR for User: %s\n", user));
+			nt_status = NT_STATUS_LOGON_FAILURE;
 	}
-	if(!pam_error_handler(pamh, pam_error, "Account Check Failed", 2)) {
+	if(!pam_nt_status_error_handler(pamh, pam_error, "Account Check Failed", 2, &nt_status)) {
 		proc_pam_end(pamh);
-		return False;
+		return nt_status;
 	}
 
-	/*
-	 * This will allow samba to aquire a kerberos token. And, when
-	 * exporting an AFS cell, be able to /write/ to this cell.
-	 */
-
-        DEBUG(4,("PAM: Account Management SetCredentials for User: %s\n", user));
-	pam_error = pam_setcred(pamh, (PAM_ESTABLISH_CRED|PAM_SILENT)); 
-	if(!pam_error_handler(pamh, pam_error, "Set Credential Failure", 2)) {
-		proc_pam_end(pamh);
-		return False;
-	}
-	
 	/* If this point is reached, the user has been authenticated. */
-	return (True);
+	return nt_status;
 }
 
 
@@ -363,47 +384,63 @@
 
 /*
  * PAM Externally accessible Account handler
+ * Returns NT_STATUS constant.
  */
-BOOL pam_accountcheck(char * user)
+uint32 pam_accountcheck(char * user)
 {
 	pam_handle_t *pamh = NULL;
 
+	uint32 nt_status = NT_STATUS_LOGON_FAILURE;
+
 	PAM_username = user;
 	PAM_password = NULL;
 
 	if( proc_pam_start(&pamh, user))
 	{
-			if ( pam_account(pamh, user, NULL))
-			{
-				return( proc_pam_end(pamh));
-			}
+	  nt_status = pam_account(pamh, user, NULL);
+	  if (nt_status == NT_STATUS_NOPROBLEMO) 
+	    {
+	      if (proc_pam_end(pamh)) {
+		return nt_status;
+	      } else {
+		nt_status = NT_STATUS_LOGON_FAILURE;
+	      }
+	    }
 	}
 	DEBUG(0, ("PAM: Account Validation Failed - Rejecting User!\n"));
-	return( False );
+	return( nt_status );
 }
 
 /*
  * PAM Password Validation Suite
  */
-BOOL pam_passcheck(char * user, char * password)
+uint32 pam_passcheck(char * user, char * password)
 {
 	pam_handle_t *pamh = NULL;
 
+	uint32 nt_status = NT_STATUS_LOGON_FAILURE;
+
 	PAM_username = user;
 	PAM_password = password;
 
 	if( proc_pam_start(&pamh, user))
 	{
-		if ( pam_auth(pamh, user, password))
+	  nt_status = pam_auth(pamh, user, password);
+		if ( nt_status == NT_STATUS_NOPROBLEMO)
 		{
-			if ( pam_account(pamh, user, password))
+		  nt_status = pam_account(pamh, user, password);
+			if ( nt_status == NT_STATUS_NOPROBLEMO)
 			{
-				return( proc_pam_end(pamh));
+			  if (proc_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 );
 }
 
 #else
Index: source/passdb/pass_check.c
===================================================================
RCS file: /cvsroot/samba/source/passdb/pass_check.c,v
retrieving revision 1.11.4.3
diff -u -r1.11.4.3 pass_check.c
--- source/passdb/pass_check.c	2001/04/10 19:43:12	1.11.4.3
+++ source/passdb/pass_check.c	2001/04/18 00:41:39
@@ -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 (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,41 +707,52 @@
 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();
-	struct passwd *pass;
+	uint32 nt_status;
+	DEBUG(4, ("Checking password for user %s (l=%d)\n", user, pwlen));
 
-	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;
+
+	/* 
+	 * We should not second-guess PAM on this stuff, jump straight 
+	 * to PAM below.  Also saves a getpwnam lookup. 
+	 */
+#ifndef WITH_PAM  
+      {
+	struct passwd *pass;
+
 	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;
 		user = pass->pw_name;
-	} else {
-		pass = Get_Pwnam(user, True);
-	}
-
-
-	DEBUG(4, ("Checking password for user %s (l=%d)\n", user, pwlen));
+	} else if (!pwd && user) {
+                pass = sys_getpwnam(user);  
+                /* Case conversion should happen WAY before now, if ever */
+        } else {
+                pass = pwd;
+        }
 
 	if (!pass) {
 		DEBUG(3, ("Couldn't find user %s\n", user));
-		return (False);
+		return (NT_STATUS_NO_SUCH_USER);
 	}
 
 #ifdef HAVE_GETSPNAM
@@ -777,7 +816,6 @@
 #endif
 
 	/* extract relevant info */
-	fstrcpy(this_user, pass->pw_name);
 	fstrcpy(this_salt, pass->pw_passwd);
 
 #if defined(HAVE_TRUNCATED_SALT)
@@ -792,28 +830,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 */
@@ -822,10 +866,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);
 		}
 	}
 
@@ -833,20 +878,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);
 }
+
+
+
-------------- next part --------------
Index: source/Makefile.in
===================================================================
RCS file: /cvsroot/samba/source/Makefile.in,v
retrieving revision 1.227.2.39
diff -u -r1.227.2.39 Makefile.in
--- source/Makefile.in	2001/04/16 01:26:21	1.227.2.39
+++ source/Makefile.in	2001/04/18 00:41:18
@@ -159,6 +159,8 @@
              passdb/pass_check.o passdb/ldap.o passdb/nispass.o passdb/smbpasschange.o \
 	     passdb/tdbpass.o passdb/pampass.o
 
+AUTH_OBJ = auth/auth_rpc.o auth/auth.o auth/auth_chal.o auth/auth_rhosts.o
+
 PROFILE_OBJ = profile/profile.o
 
 OPLOCK_OBJ = smbd/oplock.o smbd/oplock_irix.o smbd/oplock_linux.o
@@ -188,7 +190,8 @@
 SMBD_OBJ = $(SMBD_OBJ1) $(MSDFS_OBJ) $(PARAM_OBJ) $(LIBSMB_OBJ) $(UBIQX_OBJ) \
            $(RPC_SERVER_OBJ) $(RPC_PARSE_OBJ) $(RPC_CLIENT_OBJ) \
            $(LOCKING_OBJ) $(PASSDB_OBJ) $(PRINTING_OBJ) $(PROFILE_OBJ) $(LIB_OBJ) \
-	   $(PRINTBACKEND_OBJ) $(QUOTAOBJS) $(OPLOCK_OBJ) $(NOTIFY_OBJ)
+	   $(PRINTBACKEND_OBJ) $(QUOTAOBJS) $(OPLOCK_OBJ) $(NOTIFY_OBJ) \
+	   $(AUTH_OBJ)
 
 
 NMBD_OBJ1 = nmbd/asyncdns.o nmbd/nmbd.o nmbd/nmbd_become_dmb.o \
@@ -210,7 +213,7 @@
 SWAT_OBJ = web/cgi.o web/diagnose.o web/startstop.o web/statuspage.o \
            web/swat.o $(PRINTING_OBJ) $(LIBSMB_OBJ) $(LOCKING_OBJ) \
            $(PARAM_OBJ) $(PASSDB_OBJ) $(RPC_PARSE_OBJ) \
-           $(UBIQX_OBJ) $(LIB_OBJ) 
+           $(UBIQX_OBJ) $(LIB_OBJ) $(AUTH_OBJ) 
 
 SMBSH_OBJ = smbwrapper/smbsh.o smbwrapper/shared.o \
             $(PARAM_OBJ) $(UBIQX_OBJ) $(LIB_OBJ)
Index: source/include/rpc_netlogon.h
===================================================================
RCS file: /cvsroot/samba/source/include/rpc_netlogon.h,v
retrieving revision 1.14.2.2
diff -u -r1.14.2.2 rpc_netlogon.h
--- source/include/rpc_netlogon.h	2001/02/24 00:39:22	1.14.2.2
+++ source/include/rpc_netlogon.h	2001/04/18 00:41:31
@@ -323,6 +323,24 @@
 
 } NET_R_SRV_PWSET;
 
+/* NET_ID_INFO_4 */
+typedef struct net_network_info_4
+{
+	uint32            ptr_id_info4;        /* pointer to id_info_2 */
+	UNIHDR            hdr_domain_name;     /* domain name unicode header */
+	uint32            param_ctrl;          /* param control (0x2) */
+        DOM_LOGON_ID      logon_id;            /* logon ID */
+	UNIHDR            hdr_user_name;       /* user name unicode header */
+	UNIHDR            hdr_wksta_name;      /* wksta name unicode header */
+	STRHDR            hdr_general;         /* general response */
+
+	UNISTR2           uni_domain_name;     /* domain name unicode string */
+	UNISTR2           uni_user_name;       /* user name unicode string */
+	UNISTR2           uni_wksta_name;      /* workgroup name unicode string */
+	STRING2           str_general;         /* general response */
+
+} NET_ID_INFO_4;
+
 /* NET_ID_INFO_2 */
 typedef struct net_network_info_2
 {
@@ -363,6 +381,8 @@
 
 #define INTERACTIVE_LOGON_TYPE 1
 #define NET_LOGON_TYPE 2
+#define GENERAL_LOGON_TYPE 4
+
 
 /* NET_ID_INFO_CTR */
 typedef struct net_id_info_ctr_info
@@ -373,7 +393,7 @@
   {
     NET_ID_INFO_1 id1; /* auth-level 1 - interactive user login */
     NET_ID_INFO_2 id2; /* auth-level 2 - workstation referred login */
-
+    NET_ID_INFO_4 id4; /* auth-level 4 - plaintext login */
   } auth;
   
 } NET_ID_INFO_CTR;
Index: source/passdb/passdb.c
===================================================================
RCS file: /cvsroot/samba/source/passdb/passdb.c,v
retrieving revision 1.62.2.12
diff -u -r1.62.2.12 passdb.c
--- source/passdb/passdb.c	2001/03/26 18:18:18	1.62.2.12
+++ source/passdb/passdb.c	2001/04/18 00:41:42
@@ -1491,3 +1491,34 @@
 
 	return True;
 }
+
+/***********************************************************
+ Code to change the oem password. Changes both the lanman
+ and NT hashes.
+ override = False, normal
+ override = True, override XXXXXXXXXX'd password
+************************************************************/
+
+BOOL change_oem_password(struct smb_passwd *smbpw, char *new_passwd,
+			 BOOL override)
+{
+	int ret;
+	uchar new_nt_p16[16];
+	uchar new_p16[16];
+
+	nt_lm_owf_gen(new_passwd, new_nt_p16, new_p16);
+
+	smbpw->smb_passwd = new_p16;
+	smbpw->smb_nt_passwd = new_nt_p16;
+
+	/* Now write it into the file. */
+	ret = mod_smbpwd_entry(smbpw, override);
+
+	memset(new_passwd, '\0', strlen(new_passwd));
+
+	return ret;
+}
+
+
+
+
Index: source/passdb/smbpass.c
===================================================================
RCS file: /cvsroot/samba/source/passdb/Attic/smbpass.c,v
retrieving revision 1.102.4.5
diff -u -r1.102.4.5 smbpass.c
--- source/passdb/smbpass.c	2001/04/09 20:50:59	1.102.4.5
+++ source/passdb/smbpass.c	2001/04/18 00:41:45
@@ -1272,8 +1272,11 @@
 
 static struct smb_passwd *iterate_getsmbpwnam(char *name)
 {
-	struct smb_passwd *pwd = NULL;
+        static struct smb_passwd our_smb_pwd;
+        struct smb_passwd *smb_pwd = NULL;
+	struct passwd *pwd;
 	void *fp = NULL;
+	static pstring pw_name;
 
 	DEBUG(10, ("search by name: %s\n", name));
 
@@ -1286,16 +1289,25 @@
 		return NULL;
 	}
 
-	while ((pwd = getsmbpwent(fp)) != NULL && !strequal(pwd->smb_name, name))
+	while ((smb_pwd = getsmbpwent(fp)) != NULL && !strequal(smb_pwd->smb_name, name))
       ;
 
-	if (pwd != NULL)
+	if (smb_pwd != NULL)
 	{
 		DEBUG(10, ("found by name: %s\n", name));
+	} else {
+	  pwd = sys_getpwnam(name);
+	  if (pwd != NULL) 
+	    {
+	        pstrcpy(pw_name, pwd->pw_name); 
+	        our_smb_pwd.smb_name = pw_name;
+		our_smb_pwd.smb_userid = pwd->pw_uid;
+		return &our_smb_pwd;
+	    }
 	}
 
 	endsmbpwent(fp);
-	return pwd;
+	return smb_pwd;
 }
 
 /*
Index: source/rpc_parse/parse_net.c
===================================================================
RCS file: /cvsroot/samba/source/rpc_parse/parse_net.c,v
retrieving revision 1.43.2.8
diff -u -r1.43.2.8 parse_net.c
--- source/rpc_parse/parse_net.c	2001/03/13 19:14:13	1.43.2.8
+++ source/rpc_parse/parse_net.c	2001/04/18 00:41:48
@@ -2,9 +2,10 @@
  *  Unix SMB/Netbios implementation.
  *  Version 1.9.
  *  RPC Pipe client / server routines
- *  Copyright (C) Andrew Tridgell              1992-1997,
- *  Copyright (C) Luke Kenneth Casson Leighton 1996-1997,
- *  Copyright (C) Paul Ashton                       1997.
+ *  Copyright (C) Andrew Tridgell              1992-2000,
+ *  Copyright (C) Luke Kenneth Casson Leighton 1996-2000,
+ *  Copyright (C) Paul Ashton                  1997-2000,
+ *  Copyright (C) Sander Striker                    2000
  *  
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
@@ -907,7 +908,109 @@
 	return True;
 }
 
+/*******************************************************************
+makes a NET_ID_INFO_4 structure.
+
+This is a network logon packet. The log_id parameters
+are what an NT server would generate for LUID once the
+user is logged on. I don't think we care about them.
+
+Note that this has no access to the NT and LM hashed passwords,
+so it forwards the challenge, and the NT and LM responses (24
+bytes each) over the secure channel to the Domain controller
+for it to say yea or nay. This is the preferred method of 
+checking for a logon as it doesn't export the password
+hashes to anyone who has compromised the secure channel. JRA.
+********************************************************************/
+
+BOOL init_id_info4(NET_ID_INFO_4 * id, const char *domain_name,
+		   uint32 param_ctrl,
+		   uint32 log_id_low, uint32 log_id_high,
+		   char *user_name, char *wksta_name,
+		   char *general)
+{
+	int len_domain_name = strlen(domain_name);
+	int len_user_name = strlen(user_name);
+	int len_wksta_name = strlen(wksta_name);
+	int len_general = strlen(general);
+
+	if (id == NULL)
+		return False;
+
+	DEBUG(5, ("make_id_info4: %d\n", __LINE__));
+
+	id->ptr_id_info4 = 1;
+
+	init_uni_hdr(&(id->hdr_domain_name), len_domain_name);
+
+	id->param_ctrl = param_ctrl;
+	id->logon_id.low = log_id_low;
+	id->logon_id.high = log_id_high;
 
+	init_uni_hdr(&(id->hdr_user_name), len_user_name);
+	init_uni_hdr(&(id->hdr_wksta_name), len_wksta_name);
+	init_str_hdr(&(id->hdr_general), len_general, len_general, 1);
+
+	init_unistr2(&(id->uni_domain_name), domain_name, len_domain_name);
+	init_unistr2(&(id->uni_user_name), user_name, len_user_name);
+	init_unistr2(&(id->uni_wksta_name), wksta_name, len_wksta_name);
+	init_string2(&(id->str_general), general, len_general);
+
+	return True;
+}
+
+/*******************************************************************
+reads or writes an NET_ID_INFO_4 structure.
+********************************************************************/
+static BOOL net_io_id_info4(char *desc, NET_ID_INFO_4 * id, prs_struct *ps,
+			    int depth)
+{
+	if (id == NULL)
+		return False;
+
+	prs_debug(ps, depth, desc, "net_io_id_info4");
+	depth++;
+
+	prs_align(ps);
+
+	prs_uint32("ptr_id_info4", ps, depth, &(id->ptr_id_info4));
+
+	if (id->ptr_id_info4 != 0)
+	{
+		if(!smb_io_unihdr("unihdr", &(id->hdr_domain_name), ps, depth))
+		  return False;
+
+		if(!prs_uint32("param_ctrl", ps, depth, &(id->param_ctrl)))
+		  return False;
+		if(!smb_io_logon_id("", &id->logon_id, ps, depth))
+		  return False;
+
+		if(!smb_io_unihdr("hdr_user   ", &(id->hdr_user_name), ps, depth))
+		  return False;
+		if(!smb_io_unihdr("hdr_wksta  ", &(id->hdr_wksta_name), ps,
+			      depth))
+		  return False;
+		if(!smb_io_strhdr("hdr_general", &(id->hdr_general), ps, depth))
+		  return False;
+
+		if(!smb_io_unistr2("uni_domain_name", &(id->uni_domain_name),
+			       id->hdr_domain_name.buffer, ps, depth))
+		  return False;
+		if(!smb_io_unistr2("uni_user_name  ", &(id->uni_user_name),
+			       id->hdr_user_name.buffer, ps, depth))
+		  return False;
+		if(!smb_io_unistr2("uni_wksta_name ", &(id->uni_wksta_name),
+			       id->hdr_wksta_name.buffer, ps, depth))
+		  return False;
+		if(!smb_io_string2("str_general    ", &(id->str_general),
+			       id->hdr_general.buffer, ps, depth))
+		  return False;
+	}
+
+	return True;
+}
+
+
 /*******************************************************************
  Inits a DOM_SAM_INFO structure.
 ********************************************************************/
@@ -965,6 +1068,10 @@
 	case 2:
 		if(!net_io_id_info2("", &ctr->auth.id2, ps, depth))
 			return False;
+		break;
+	case 4:
+		if (!net_io_id_info4("", &(ctr->auth.id4), ps, depth))
+		        return False;
 		break;
 	default:
 		/* PANIC! */
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.10
diff -u -r1.1.2.10 srv_netlog_nt.c
--- source/rpc_server/srv_netlog_nt.c	2001/04/13 01:52:29	1.1.2.10
+++ source/rpc_server/srv_netlog_nt.c	2001/04/18 00:41:49
@@ -4,8 +4,9 @@
  *  RPC Pipe client / server routines
  *  Copyright (C) Andrew Tridgell              1992-1997,
  *  Copyright (C) Luke Kenneth Casson Leighton 1996-1997,
- *  Copyright (C) Paul Ashton                       1997.
- *  Copyright (C) Jeremy Allison               1998-2001.
+ *  Copyright (C) Paul Ashton                       1997,
+ *  Copyright (C) Jeremy Allison               1998-2001,
+ *  Copyright (C) Andrew Bartlett                   2001.
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
@@ -353,103 +354,8 @@
 	return r_u->status;
 }
 
-/*************************************************************************
- net_login_interactive:
- *************************************************************************/
-
-static uint32 net_login_interactive(NET_ID_INFO_1 *id1, struct smb_passwd *smb_pass, pipes_struct *p)
-{
-	uint32 status = 0x0;
-
-	char nt_pwd[16];
-	char lm_pwd[16];
-	unsigned char key[16];
-
-	memset(key, 0, 16);
-	memcpy(key, p->dc.sess_key, 8);
-
-	memcpy(lm_pwd, id1->lm_owf.data, 16);
-	memcpy(nt_pwd, id1->nt_owf.data, 16);
-
-#ifdef DEBUG_PASSWORD
-	DEBUG(100,("key:"));
-	dump_data(100, (char *)key, 16);
-
-	DEBUG(100,("lm owf password:"));
-	dump_data(100, lm_pwd, 16);
-
-	DEBUG(100,("nt owf password:"));
-	dump_data(100, nt_pwd, 16);
-#endif
-
-	SamOEMhash((uchar *)lm_pwd, key, False);
-	SamOEMhash((uchar *)nt_pwd, key, False);
-
-#ifdef DEBUG_PASSWORD
-	DEBUG(100,("decrypt of lm owf password:"));
-	dump_data(100, lm_pwd, 16);
-
-	DEBUG(100,("decrypt of nt owf password:"));
-	dump_data(100, nt_pwd, 16);
-#endif
-
-	if (memcmp(smb_pass->smb_passwd   , lm_pwd, 16) != 0 ||
-	    memcmp(smb_pass->smb_nt_passwd, nt_pwd, 16) != 0)
-	{
-		status = NT_STATUS_WRONG_PASSWORD;
-	}
 
-	return status;
-}
-
 /*************************************************************************
- _net_login_network:
- *************************************************************************/
-
-static uint32 net_login_network(NET_ID_INFO_2 *id2, struct smb_passwd *smb_pass)
-{
-	DEBUG(5,("net_login_network: lm_len: %d nt_len: %d\n",
-		id2->hdr_lm_chal_resp.str_str_len, 
-		id2->hdr_nt_chal_resp.str_str_len));
-
-	/* JRA. Check the NT password first if it exists - this is a higher quality 
-           password, if it exists and it doesn't match - fail. */
-
-	if (id2->hdr_nt_chal_resp.str_str_len == 24 && 
-		smb_pass->smb_nt_passwd != NULL)
-	{
-		if(smb_password_check((char *)id2->nt_chal_resp.buffer,
-		                   smb_pass->smb_nt_passwd,
-                           id2->lm_chal)) 
-			return NT_STATUS_NO_PROBLEMO;
-		else
-			return NT_STATUS_WRONG_PASSWORD;
-	}
-
-	/* lkclXXXX this is not a good place to put disabling of LM hashes in.
-	   if that is to be done, first move this entire function into a
-	   library routine that calls the two smb_password_check() functions.
-	   if disabling LM hashes (which nt can do for security reasons) then
-	   an attempt should be made to disable them everywhere (which nt does
-	   not do, for various security-hole reasons).
-	 */
-
-	if (lp_lanman_auth() &&
-	    id2->hdr_lm_chal_resp.str_str_len == 24 &&
-		smb_password_check((char *)id2->lm_chal_resp.buffer,
-		                   smb_pass->smb_passwd,
-		                   id2->lm_chal))
-	{
-		return NT_STATUS_NO_PROBLEMO;
-	}
-
-
-	/* oops! neither password check succeeded */
-
-	return NT_STATUS_WRONG_PASSWORD;
-}
-
-/*************************************************************************
  _net_sam_logon
  *************************************************************************/
 
@@ -462,7 +368,9 @@
     struct sam_passwd *sam_pass = NULL;
     UNISTR2 *uni_samlogon_user = NULL;
     fstring nt_username;
-   
+    char *enc_user_sess_key = NULL;
+    char user_sess_key[16];
+
 	usr_info = (NET_USER_INFO_3 *)talloc(p->mem_ctx, sizeof(NET_USER_INFO_3));
 	if (!usr_info)
 		return NT_STATUS_NO_MEMORY;
@@ -499,6 +407,11 @@
             
 		DEBUG(3,("SAM Logon (Network). Domain:[%s].  ", lp_workgroup()));
 		break;
+	case GENERAL_LOGON_TYPE:
+	        uni_samlogon_user = &q_u->sam_id.ctr->auth.id4.uni_user_name;
+		
+		DEBUG(3, ("SAM Logon (General). Domain:[%s].  ", lp_workgroup()));
+		break;
 	default:
 		DEBUG(2,("SAM Logon: unsupported switch value\n"));
 		return NT_STATUS_INVALID_INFO_CLASS;
@@ -537,40 +450,19 @@
         
 	if ((smb_pass=pdb_sam_to_smb(sam_pass)) == NULL)
 		return NT_STATUS_NO_SUCH_USER;
-	else if (smb_pass->acct_ctrl & ACB_DISABLED)
-		return NT_STATUS_ACCOUNT_DISABLED;
     
 	/* Validate password - if required. */
-    
-	if (smb_pass->acct_ctrl & ACB_PWNOTREQ) {
-	  if (!lp_null_passwords()) {
-	    DEBUG(3,("Account for user %s has a null password and null passwords are NOT allowed",nt_username));
-	    return NT_STATUS_ACCOUNT_DISABLED;
-	  }
-	} 
-
-#ifdef WITH_PAM
-	if (!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:
-			/* interactive login. */
-			status = net_login_interactive(&q_u->sam_id.ctr->auth.id1, smb_pass, p);
-			break;
-		case NET_LOGON_TYPE:
-			/* network login.  lm challenge and 24 byte responses */
-			status = net_login_network(&q_u->sam_id.ctr->auth.id2, smb_pass);
-			break;
-		}
-	}
-    
+    	q_u->sam_id.ctr->switch_value = q_u->sam_id.logon_level;
+
+	status = net_logon(q_u->sam_id.ctr, smb_pass, p->dc.sess_key, user_sess_key);
+	if (q_u->sam_id.logon_level == GENERAL_LOGON_TYPE)
+                enc_user_sess_key = user_sess_key;	
+
 	if (status != NT_STATUS_NOPROBLEMO)
 		return status;
 
+
 	/* lkclXXXX this is the point at which, if the login was
 		successful, that the SAM Local Security Authority should
 		record that the user is logged in to the domain.
@@ -641,11 +533,11 @@
 					gids    , /* DOM_GID *gids */
 					0x20    , /* uint32 user_flgs (?) */
                                
-					NULL, /* char sess_key[16] */
+					enc_user_sess_key, /* char sess_key[16] */
                                 
 					my_name     , /* char *logon_srv */
 					my_workgroup, /* char *logon_dom */
-                                
+
 					&global_sam_sid,     /* DOM_SID *dom_sid */
 					NULL); /* char *other_sids */
 		}
@@ -658,3 +550,8 @@
 
     return status;
 }
+
+
+
+
+
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/18 00:41:56
@@ -861,35 +861,6 @@
 }
 
 /***********************************************************
- Code to change the oem password. Changes both the lanman
- and NT hashes.
- override = False, normal
- override = True, override XXXXXXXXXX'd password
-************************************************************/
-
-BOOL change_oem_password(struct smb_passwd *smbpw, char *new_passwd,
-			 BOOL override)
-{
-	int ret;
-	uchar new_nt_p16[16];
-	uchar new_p16[16];
-
-	nt_lm_owf_gen(new_passwd, new_nt_p16, new_p16);
-
-	smbpw->smb_passwd = new_p16;
-	smbpw->smb_nt_passwd = new_nt_p16;
-
-	/* Now write it into the file. */
-	become_root();
-	ret = mod_smbpwd_entry(smbpw, override);
-	unbecome_root();
-
-	memset(new_passwd, '\0', strlen(new_passwd));
-
-	return ret;
-}
-
-/***********************************************************
  Code to check a plaintext password against smbpasswd entries.
 ***********************************************************/
 
@@ -937,3 +908,4 @@
 	else
 		return (True);
 }
+
Index: source/smbd/password.c
===================================================================
RCS file: /cvsroot/samba/source/smbd/password.c,v
retrieving revision 1.186.2.16
diff -u -r1.186.2.16 password.c
--- source/smbd/password.c	2001/04/13 01:52:29	1.186.2.16
+++ source/smbd/password.c	2001/04/18 00:42:01
@@ -29,67 +29,7 @@
 static pstring session_users="";
 
 extern pstring global_myname;
-extern fstring global_myworkgroup;
 
-/* Data to do lanman1/2 password challenge. */
-static unsigned char saved_challenge[8];
-static BOOL challenge_sent=False;
-
-/*******************************************************************
-Get the next challenge value - no repeats.
-********************************************************************/
-void generate_next_challenge(char *challenge)
-{
-#if 0
-        /* 
-         * Leave this ifdef'd out while we test
-         * the new crypto random number generator.
-         * JRA.
-         */
-	unsigned char buf[16];
-	static int counter = 0;
-	struct timeval tval;
-	int v1,v2;
-
-	/* get a sort-of random number */
-	GetTimeOfDay(&tval);
-	v1 = (counter++) + sys_getpid() + tval.tv_sec;
-	v2 = (counter++) * sys_getpid() + tval.tv_usec;
-	SIVAL(challenge,0,v1);
-	SIVAL(challenge,4,v2);
-
-	/* mash it up with md4 */
-	mdfour(buf, (unsigned char *)challenge, 8);
-#else
-        unsigned char buf[8];
-
-        generate_random_buffer(buf,8,False);
-#endif 
-	memcpy(saved_challenge, buf, 8);
-	memcpy(challenge,buf,8);
-	challenge_sent = True;
-}
-
-/*******************************************************************
-set the last challenge sent, usually from a password server
-********************************************************************/
-BOOL set_challenge(unsigned char *challenge)
-{
-  memcpy(saved_challenge,challenge,8);
-  challenge_sent = True;
-  return(True);
-}
-
-/*******************************************************************
-get the last challenge sent
-********************************************************************/
-static BOOL last_challenge(unsigned char *challenge)
-{
-  if (!challenge_sent) return(False);
-  memcpy(challenge,saved_challenge,8);
-  return(True);
-}
-
 /* this holds info on user ids that are already validated for this VC */
 static user_struct *validated_users;
 static int next_vuid = VUID_OFFSET;
@@ -341,274 +281,6 @@
 
 
 /****************************************************************************
-update the encrypted smbpasswd file from the plaintext username and password
-*****************************************************************************/
-static BOOL update_smbpassword_file(char *user, char *password)
-{
-	struct smb_passwd *smbpw;
-	BOOL ret;
-	
-	become_root();
-	smbpw = getsmbpwnam(user);
-	unbecome_root();
-
-	if(smbpw == NULL) {
-		DEBUG(0,("getsmbpwnam returned NULL\n"));
-		return False;
-	}
-
-	/*
-	 * Remove the account disabled flag - we are updating the
-	 * users password from a login.
-	 */
-	smbpw->acct_ctrl &= ~ACB_DISABLED;
-
-	/* Here, the flag is one, because we want to ignore the
-           XXXXXXX'd out password */
-	ret = change_oem_password( smbpw, password, True);
-	if (ret == False) {
-		DEBUG(3,("change_oem_password returned False\n"));
-	}
-
-	return ret;
-}
-
-
-
-
-
-/****************************************************************************
-core of smb password checking routine.
-****************************************************************************/
-BOOL smb_password_check(char *password, unsigned char *part_passwd, unsigned char *c8)
-{
-  /* Finish the encryption of part_passwd. */
-  unsigned char p21[21];
-  unsigned char p24[24];
-
-  if (part_passwd == NULL)
-    DEBUG(10,("No password set - allowing access\n"));
-  /* No password set - always true ! */
-  if (part_passwd == NULL)
-    return 1;
-
-  memset(p21,'\0',21);
-  memcpy(p21,part_passwd,16);
-  E_P24(p21, c8, p24);
-#if DEBUG_PASSWORD
-  {
-    int i;
-    DEBUG(100,("Part password (P16) was |"));
-    for(i = 0; i < 16; i++)
-      DEBUG(100,("%X ", (unsigned char)part_passwd[i]));
-    DEBUG(100,("|\n"));
-    DEBUG(100,("Password from client was |"));
-    for(i = 0; i < 24; i++)
-      DEBUG(100,("%X ", (unsigned char)password[i]));
-    DEBUG(100,("|\n"));
-    DEBUG(100,("Given challenge was |"));
-    for(i = 0; i < 8; i++)
-      DEBUG(100,("%X ", (unsigned char)c8[i]));
-    DEBUG(100,("|\n"));
-    DEBUG(100,("Value from encryption was |"));
-    for(i = 0; i < 24; i++)
-      DEBUG(100,("%X ", (unsigned char)p24[i]));
-    DEBUG(100,("|\n"));
-  }
-#endif
-  return (memcmp(p24, password, 24) == 0);
-}
-
-/****************************************************************************
- Do a specific test for an smb password being correct, given a smb_password and
- the lanman and NT responses.
-****************************************************************************/
-BOOL smb_password_ok(struct smb_passwd *smb_pass, uchar chal[8],
-                     uchar lm_pass[24], uchar nt_pass[24])
-{
-	uchar challenge[8];
-
-	if (!lm_pass || !smb_pass) return(False);
-
-	DEBUG(4,("Checking SMB password for user %s\n", 
-		 smb_pass->smb_name));
-
-	if(smb_pass->acct_ctrl & ACB_DISABLED) {
-		DEBUG(1,("account for user %s was disabled.\n", 
-			 smb_pass->smb_name));
-		return(False);
-	}
-
-	if (chal == NULL)
-	{
-		DEBUG(5,("use last SMBnegprot challenge\n"));
-		if (!last_challenge(challenge))
-		{
-			DEBUG(1,("no challenge done - password failed\n"));
-			return False;
-		}
-	}
-	else
-	{
-		DEBUG(5,("challenge received\n"));
-		memcpy(challenge, chal, 8);
-	}
-
-	if ((Protocol >= PROTOCOL_NT1) && (smb_pass->smb_nt_passwd != NULL)) {
-		/* We have the NT MD4 hash challenge available - see if we can
-		   use it (ie. does it exist in the smbpasswd file).
-		*/
-		DEBUG(4,("smb_password_ok: Checking NT MD4 password\n"));
-		if (smb_password_check((char *)nt_pass, 
-				       (uchar *)smb_pass->smb_nt_passwd, 
-				       challenge)) {
-			DEBUG(4,("NT MD4 password check succeeded\n"));
-			return(True);
-		}
-		DEBUG(4,("NT MD4 password check failed\n"));
-	}
-
-	/* Try against the lanman password. smb_pass->smb_passwd == NULL means
-	   no password, allow access. */
-
-	DEBUG(4,("Checking LM MD4 password\n"));
-
-	if((smb_pass->smb_passwd == NULL) && 
-	   (smb_pass->acct_ctrl & ACB_PWNOTREQ)) {
-		DEBUG(4,("no password required for user %s\n",
-			 smb_pass->smb_name));
-		return True;
-	}
-
-	if((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"));
-		return(True);
-	}
-
-	DEBUG(4,("LM MD4 password check failed\n"));
-
-	return False;
-}
-
-
-/****************************************************************************
-check if a username/password is OK assuming the password is a 24 byte
-SMB hash
-return True if the password is correct, False otherwise
-****************************************************************************/
-
-BOOL pass_check_smb(char *user, char *domain,
-		uchar *chal, uchar *lm_pwd, uchar *nt_pwd,
-		struct passwd *pwd)
-{
-	struct passwd *pass;
-	struct smb_passwd *smb_pass;
-
-	if (!lm_pwd || !nt_pwd)
-	{
-		return(False);
-	}
-
-	if (pwd != NULL && user == NULL)
-	{
-		pass = (struct passwd *) pwd;
-		user = pass->pw_name;
-	}
-	else
-	{
-		pass = smb_getpwnam(user,True);
-	}
-
-	if (pass == NULL)
-	{
-		DEBUG(1,("Couldn't find user '%s' in UNIX password database.\n",user));
-		return(False);
-	}
-
-	smb_pass = getsmbpwnam(user);
-
-	if (smb_pass == NULL)
-	{
-		DEBUG(1,("Couldn't find user '%s' in smb_passwd file.\n", user));
-		return(False);
-	}
-
-	/* Quit if the account was disabled. */
-	if(smb_pass->acct_ctrl & ACB_DISABLED) {
-		DEBUG(1,("Account for user '%s' was disabled.\n", user));
-		return(False);
-	}
-
-	/* Ensure the uid's match */
-	if (smb_pass->smb_userid != pass->pw_uid)
-	{
-		DEBUG(0,("Error : UNIX and SMB uids in password files do not match for user '%s'!\n", user));
-		return(False);
-	}
-
-	if (smb_pass->acct_ctrl & ACB_PWNOTREQ) {
-		if (lp_null_passwords()) {
-			DEBUG(3,("Account for user '%s' has no password and null passwords are allowed.\n", smb_pass->smb_name));
-			return(True);
-		} else {
-			DEBUG(3,("Account for user '%s' has no password and null passwords are NOT allowed.\n", smb_pass->smb_name));
-			return(False);
-		}		
-	}
-
-	if (smb_password_ok(smb_pass, chal, lm_pwd, nt_pwd))
-	{
-		return(True);
-	}
-	
-	DEBUG(2,("pass_check_smb failed - invalid password for user [%s]\n", user));
-	return False;
-}
-
-/****************************************************************************
-check if a username/password pair is OK either via the system password
-database or the encrypted SMB password database
-return True if the password is correct, False otherwise
-****************************************************************************/
-BOOL password_ok(char *user, char *password, int pwlen, struct passwd *pwd)
-{
-
-  BOOL ret;
-
-	if ((pwlen == 0) && !lp_null_passwords()) {
-		DEBUG(4,("Null passwords not allowed.\n"));
-		return False;
-	}
-
-	if (pwlen == 24 || (lp_encrypted_passwords() && (pwlen == 0) && lp_null_passwords()))
-	{
-		/* if 24 bytes long assume it is an encrypted password */
-		uchar challenge[8];
-
-		if (!last_challenge(challenge))
-		{
-			DEBUG(0,("Error: challenge not done for user=%s\n", user));
-			return False;
-		}
-
-		ret = pass_check_smb(user, global_myworkgroup,
-		                      challenge, (uchar *)password, (uchar *)password, pwd);
-#ifdef WITH_PAM
-		if (ret) {
-		  return pam_accountcheck(user);
-		}
-#endif
-		return ret;
-	} 
-
-	return pass_check(user, password, pwlen, pwd, 
-			  lp_update_encrypted() ? 
-			  update_smbpassword_file : NULL);
-}
-
-/****************************************************************************
 check if a username is valid
 ****************************************************************************/
 BOOL user_ok(char *user,int snum)
@@ -812,12 +482,6 @@
       ok = True;
     }
 
-      /* check for a rhosts entry */
-      if (!ok && user_ok(user,snum) && check_hosts_equiv(user)) {
-	ok = True;
-	DEBUG(3,("ACCEPTED: hosts equiv or rhosts entry\n"));
-      }
-
       /* check the user= fields and the given password */
       if (!ok && lp_username(snum)) {
 	char *auser;
@@ -883,146 +547,6 @@
 
 
 /****************************************************************************
-read the a hosts.equiv or .rhosts file and check if it
-allows this user from this machine
-****************************************************************************/
-static BOOL check_user_equiv(char *user, char *remote, char *equiv_file)
-{
-  int plus_allowed = 1;
-  char *file_host;
-  char *file_user;
-  char **lines = file_lines_load(equiv_file, NULL, False);
-  int i;
-
-  DEBUG(5, ("check_user_equiv %s %s %s\n", user, remote, equiv_file));
-  if (! lines) return False;
-  for (i=0; lines[i]; i++) {
-    char *buf = lines[i];
-    trim_string(buf," "," ");
-
-    if (buf[0] != '#' && buf[0] != '\n') 
-    {
-      BOOL is_group = False;
-      int plus = 1;
-      char *bp = buf;
-      if (strcmp(buf, "NO_PLUS\n") == 0)
-      {
-	DEBUG(6, ("check_user_equiv NO_PLUS\n"));
-	plus_allowed = 0;
-      }
-      else {
-	if (buf[0] == '+') 
-	{
-	  bp++;
-	  if (*bp == '\n' && plus_allowed) 
-	  {
-	    /* a bare plus means everbody allowed */
-	    DEBUG(6, ("check_user_equiv everybody allowed\n"));
-	    file_lines_free(lines);
-	    return True;
-	  }
-	}
-	else if (buf[0] == '-')
-	{
-	  bp++;
-	  plus = 0;
-	}
-	if (*bp == '@') 
-	{
-	  is_group = True;
-	  bp++;
-	}
-	file_host = strtok(bp, " \t\n");
-	file_user = strtok(NULL, " \t\n");
-	DEBUG(7, ("check_user_equiv %s %s\n", file_host ? file_host : "(null)", 
-                 file_user ? file_user : "(null)" ));
-	if (file_host && *file_host) 
-	{
-	  BOOL host_ok = False;
-
-#if defined(HAVE_NETGROUP) && defined(HAVE_YP_GET_DEFAULT_DOMAIN)
-	  if (is_group)
-	    {
-	      static char *mydomain = NULL;
-	      if (!mydomain)
-		yp_get_default_domain(&mydomain);
-	      if (mydomain && innetgr(file_host,remote,user,mydomain))
-		host_ok = True;
-	    }
-#else
-	  if (is_group)
-	    {
-	      DEBUG(1,("Netgroups not configured\n"));
-	      continue;
-	    }
-#endif
-
-	  /* is it this host */
-	  /* the fact that remote has come from a call of gethostbyaddr
-	   * means that it may have the fully qualified domain name
-	   * so we could look up the file version to get it into
-	   * a canonical form, but I would rather just type it
-	   * in full in the equiv file
-	   */
-	  if (!host_ok && !is_group && strequal(remote, file_host))
-	    host_ok = True;
-
-	  if (!host_ok)
-	    continue;
-
-	  /* is it this user */
-	  if (file_user == 0 || strequal(user, file_user)) 
-	    {
-	      DEBUG(5, ("check_user_equiv matched %s%s %s\n",
-			(plus ? "+" : "-"), file_host,
-			(file_user ? file_user : "")));
-	      file_lines_free(lines);
-	      return (plus ? True : False);
-	    }
-	}
-      }
-    }
-  }
-  file_lines_free(lines);
-  return False;
-}
-
-
-/****************************************************************************
-check for a possible hosts equiv or rhosts entry for the user
-****************************************************************************/
-BOOL check_hosts_equiv(char *user)
-{
-  char *fname = NULL;
-  pstring rhostsfile;
-  struct passwd *pass = Get_Pwnam(user,True);
-
-  if (!pass) 
-    return(False);
-
-  fname = lp_hosts_equiv();
-
-  /* note: don't allow hosts.equiv on root */
-  if (fname && *fname && (pass->pw_uid != 0)) {
-	  if (check_user_equiv(user,client_name(),fname))
-		  return(True);
-  }
-  
-  if (lp_use_rhosts())
-    {
-      char *home = get_user_home_dir(user);
-      if (home) {
-	      slprintf(rhostsfile, sizeof(rhostsfile)-1, "%s/.rhosts", home);
-	      if (check_user_equiv(user,client_name(),rhostsfile))
-		      return(True);
-      }
-    }
-
-  return(False);
-}
-
-
-/****************************************************************************
  Return the client state structure.
 ****************************************************************************/
 
Index: source/smbd/reply.c
===================================================================
RCS file: /cvsroot/samba/source/smbd/reply.c,v
retrieving revision 1.240.2.26
diff -u -r1.240.2.26 reply.c
--- source/smbd/reply.c	2001/04/13 04:09:39	1.240.2.26
+++ source/smbd/reply.c	2001/04/18 00:42:11
@@ -693,8 +689,7 @@
   pstring smb_apasswd;
   int   smb_ntpasslen = 0;   
   pstring smb_ntpasswd;
-  BOOL valid_nt_password = False;
-  BOOL valid_lm_password = False;
+  BOOL valid_password = False;
   pstring user;
   pstring orig_user;
   BOOL guest=False;
@@ -930,8 +928,7 @@
   if (!guest && !check_server_security(orig_user, domain, user, 
          smb_apasswd, smb_apasslen, smb_ntpasswd, smb_ntpasslen) &&
       !check_domain_security(orig_user, domain, user, smb_apasswd,
-         smb_apasslen, smb_ntpasswd, smb_ntpasslen) &&
-      !check_hosts_equiv(user))
+         smb_apasslen, smb_ntpasswd, smb_ntpasslen))
   {
 
     /* 
@@ -942,31 +939,13 @@
      * If an NT password was supplied try and validate with that
      * first. This is superior as the passwords are mixed case 
      * 128 length unicode.
-      */
+     */
 
-    if(smb_ntpasslen)
-    {
-      if(!password_ok(user, smb_ntpasswd,smb_ntpasslen,NULL))
-        DEBUG(2,("NT Password did not match for user '%s'!\n", user));
-      else
-        valid_nt_password = True;
-    } 
-    
-    
-    /* check the LanMan password only if necessary and if allowed 
-       by lp_lanman_auth() */
-    if (!valid_nt_password && lp_lanman_auth())
-    {
-      DEBUG(2,("Defaulting to Lanman password for %s\n", user));
-      valid_lm_password = password_ok(user, smb_apasswd,smb_apasslen,NULL);
-    }
-      
+    valid_password = check_password(user, domain, smb_apasswd, smb_apasslen, 
+				    smb_ntpasswd, smb_ntpasslen);
 
-    /* The true branch will be executed if 
-       (1) the NT password failed (or was not tried), and 
-       (2) LanMan authentication failed (or was disabled) 
-     */
-    if (!valid_nt_password && !valid_lm_password)
+    /* The true branch will be executed if the password check failed */
+    if (!valid_password)
     {
       if (lp_security() >= SEC_USER) 
       {
 
--- /dev/null	Wed May  6 06:32:27 1998
+++ source/auth/auth.c	Wed Apr 18 09:25:04 2001
@@ -0,0 +1,189 @@
+/* 
+   Unix SMB/Netbios implementation.
+   Version 1.9.
+   Password and authentication handling, NT Domain Authentication SMB / MSRPC client
+   Copyright (C) Andrew Tridgell 1992-1998
+   Copyright (C) Luke Kenneth Casson Leighton 1996-1997
+   Copyright (C) Jeremy Allison  1999
+   Copyright (C) Andrew Bartlett      2001
+   
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2 of the License, or
+   (at your option) any later version.
+   
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+   
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+/* 
+ * This code is a wrapper for the functions in auth_rpc.c, which are 
+ * based on RPC style structs, stolen from various places in the 
+ * rpc_server/rcp_client code.  This allows a more sane interface 
+ * to those functions.
+ */
+
+#include "includes.h"
+
+extern int DEBUGLEVEL;
+
+/****************************************************************************
+check if a username/password is OK assuming the password is a 24 byte
+SMB hash
+return True if the password is correct, False otherwise
+****************************************************************************/
+
+BOOL check_password_with_chal(char *user, uchar *chal, char *domain,
+		 uchar *lm_pwd, int lm_pwlen, 
+		 uchar *nt_pwd, int nt_pwlen)
+{
+	struct smb_passwd *smb_pass;
+	fstring dos_wksta_name, dos_username, dos_domain;
+
+	NET_ID_INFO_CTR ctr;
+	uint32 smb_userid_low;
+
+	if (!lm_pwd || !nt_pwd)
+	{
+		return(False);
+	}
+
+#if DEBUG_PASSWORD
+	DEBUG(100, ("checking user=[%s]\nlm_pwd=[%s] lm_pwlen=%d strlen(lm_pwd)=%d\n\
+nt_pwd=[%s] nt_pwlen=%d strlen(nt_pwd)=%d\n"\
+, user, lm_pwd, lm_pwlen, strlen(lm_pwd), nt_pwd, nt_pwlen, strlen(nt_pwd)));
+#endif
+
+	if (lm_pwlen == 0)
+	  lm_pwd = NULL;
+
+	if (nt_pwlen == 0)
+	  nt_pwd = NULL;
+
+	if ((domain == NULL) || (domain == "")) 
+	  domain = lp_workgroup();
+
+	smb_pass = getsmbpwnam(user);
+
+	if (smb_pass == NULL)
+	{
+		DEBUG(1,("Couldn't find user '%s' in smb_passwd file.\n", user));
+		return(False);
+	}
+
+	DEBUG(10,("Creting random LUID for user '%s'\n", user));
+
+	/* We really don't care what LUID we give the user. */
+	generate_random_buffer( (unsigned char *)&smb_userid_low, 4, False);
+
+	fstrcpy(dos_wksta_name, "");
+	unix_to_dos(dos_wksta_name, True);
+	
+	fstrcpy(dos_username, user);
+	unix_to_dos(dos_username, True);
+	
+	fstrcpy(dos_domain, domain);
+	unix_to_dos(dos_domain, True);
+	
+	
+	if (lm_pwlen == 24)
+	  {
+	    /* indicate a "network" login */
+	    ctr.switch_value = NET_LOGON_TYPE;
+	    
+	    DEBUG(10,("Creting NET_ID_INFO2 for user '%s'\n", user));
+	    
+	    /* Create the structure needed for SAM logon. */
+	    init_id_info2(&ctr.auth.id2, dos_domain, 0, smb_userid_low, 0,
+			  dos_username, dos_wksta_name,
+			  chal, lm_pwd, 
+			  nt_pwd);
+	    
+	  } else {
+
+	    /* indicate a "general" login (plaintext) */
+	    ctr.switch_value = GENERAL_LOGON_TYPE;
+
+	    DEBUG(10,("Creting NET_ID_INFO4 for user '%s'\n", user));
+	    
+	    init_id_info4(&ctr.auth.id4, dos_domain, 0, smb_userid_low, 0,
+						    dos_username, dos_wksta_name,
+						    lm_pwd);
+	  }
+	
+	DEBUG(10,("Attempting network login for user '%s'\n", user));
+	
+	/* Send client sam-logon request. */
+	if (net_logon(&ctr, smb_pass, NULL, NULL) == NT_STATUS_NOPROBLEMO) {
+	  return(True);
+	}
+	
+	DEBUG(2,("check_password failed - invalid password for user [%s]\n", user));
+	return False;
+	
+}
+
+BOOL check_password(char *user, char *domain,
+		 uchar *lm_pwd, int lm_pwlen, 
+		 uchar *nt_pwd, int nt_pwlen)
+{
+  if ((lm_pwlen == 24) || (nt_pwlen == 24))
+    {
+      /* if 24 bytes long assume it is an encrypted password */
+      uchar challenge[8];
+      
+      if (!last_challenge(challenge))
+	{
+	  DEBUG(0,("Error: challenge not done for user=%s\n", user));
+	  return False;
+	}
+      
+      return check_password_with_chal(user, challenge, domain, lm_pwd, lm_pwlen, nt_pwd, nt_pwlen);
+    } else {
+      return check_password_with_chal(user, NULL, domain, lm_pwd, lm_pwlen, nt_pwd, nt_pwlen);
+    }
+}
+
+
+/****************************************************************************
+ Do a specific test for an smb password being correct, given a smb_password and
+ the lanman and NT responses.
+****************************************************************************/
+BOOL smb_password_ok(struct smb_passwd *smb_pass, uchar chal[8],
+                     uchar lm_pass[24], uchar nt_pass[24])
+{
+  return check_password(smb_pass->smb_name, NULL, lm_pass, strlen(lm_pass), nt_pass, strlen(nt_pass));
+}
+
+
+/****************************************************************************
+check if a username/password is OK assuming the password is a 24 byte
+SMB hash
+return True if the password is correct, False otherwise
+****************************************************************************/
+
+BOOL pass_check_smb(char *user, char *domain,
+                uchar *chal, uchar *lm_pwd, uchar *nt_pwd,
+                struct passwd *pwd)
+{
+  return check_password_with_chal(user, chal, domain, lm_pwd, strlen(lm_pwd), nt_pwd, strlen(nt_pwd));
+}
+
+
+/****************************************************************************
+check if a username/password pair is OK either via the system password
+database or the encrypted SMB password database
+return True if the password is correct, False otherwise
+****************************************************************************/
+BOOL password_ok(char *user, char *password, int pwlen, struct passwd *pwd)
+{
+
+  return check_password(user, lp_workgroup(), password, pwlen, NULL, 0);
+
+}
--- /dev/null	Wed May  6 06:32:27 1998
+++ source/auth/auth_rpc.c	Wed Apr 18 08:55:57 2001
@@ -0,0 +1,357 @@
+/* 
+   Unix SMB/Netbios implementation.
+   Version 1.9.
+   Password and authentication handling, RPC Pipe client / server routines
+   Copyright (C) Andrew Tridgell              1992-2000,
+   Copyright (C) Luke Kenneth Casson Leighton 1996-2000,
+   Copyright (C) Paul Ashton                  1997-2000,
+   Copyright (C) Jeremy Allison               1998-2001,
+   Copyright (C) Sander Striker                    2000,
+   Copyright (C) Andrew Bartlett                   2001.
+   
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2 of the License, or
+   (at your option) any later version.
+   
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+   
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "includes.h"
+
+extern int DEBUGLEVEL;
+
+/*
+ * This module provides a single point for ALL authetications.  This should
+ * help prevent some of the problems we have experience with inconsistant 
+ * policy in the past.
+ * 
+ * Various parts of this file previously resisded in:
+ *   rpc_server/srv_netlogon_nt.c  (Both mainline samba 


More information about the samba-technical mailing list