102-srv_netlog_nt.c.diff   [plain text]


Index: samba/source/rpc_server/srv_netlog_nt.c
===================================================================
--- samba/source/rpc_server/srv_netlog_nt.c.orig
+++ samba/source/rpc_server/srv_netlog_nt.c
@@ -25,6 +25,7 @@
 /* This is the implementation of the netlogon pipe. */
 
 #include "includes.h"
+#include "opendirectory.h"
 
 extern userdom_struct current_user_info;
 
@@ -361,6 +362,7 @@ NTSTATUS _net_auth(pipes_struct *p, NET_
 	fstring remote_machine;
 	DOM_CHAL srv_chal_out;
 
+
 	if (!p->dc || !p->dc->challenge_sent) {
 		return NT_STATUS_ACCESS_DENIED;
 	}
@@ -370,7 +372,23 @@ NTSTATUS _net_auth(pipes_struct *p, NET_
 	rpcstr_pull(remote_machine, q_u->clnt_id.uni_comp_name.buffer,sizeof(fstring),
 				q_u->clnt_id.uni_comp_name.uni_str_len*2,0);
 
-	status = get_md4pw((char *)p->dc->mach_pw, mach_acct, q_u->clnt_id.sec_chan);
+	if (lp_opendirectory()) {
+		tDirStatus dirStatus;
+		become_root();
+		dirStatus = opendirectory_cred_session_key(&p->dc->clnt_chal,
+				&p->dc->srv_chal, mach_acct,
+				p->dc->sess_key, 0);
+		unbecome_root();
+		DEBUG(4, ("_net_auth opendirectory_cred_session_key [%d]\n",
+				dirStatus));
+
+		status = (dirStatus == eDSNoErr) ? NT_STATUS_OK
+						 : NT_STATUS_UNSUCCESSFUL;
+	} else {
+		status = get_md4pw((char *)p->dc->mach_pw, mach_acct,
+				q_u->clnt_id.sec_chan);
+	}
+
 	if (!NT_STATUS_IS_OK(status)) {
 		DEBUG(0,("_net_auth: creds_server_check failed. Failed to "
 			"get password for machine account %s "
@@ -430,6 +448,7 @@ NTSTATUS _net_auth_2(pipes_struct *p, NE
 	fstring mach_acct;
 	fstring remote_machine;
 	DOM_CHAL srv_chal_out;
+	u_int32_t session_key_type = 0;
 
 	rpcstr_pull(mach_acct, q_u->clnt_id.uni_acct_name.buffer,sizeof(fstring),
 				q_u->clnt_id.uni_acct_name.uni_str_len*2,0);
@@ -438,10 +457,16 @@ NTSTATUS _net_auth_2(pipes_struct *p, NE
 	rpcstr_pull(remote_machine, q_u->clnt_id.uni_comp_name.buffer,sizeof(fstring),
 				q_u->clnt_id.uni_comp_name.uni_str_len*2,0);
 
+	if (q_u->clnt_flgs.neg_flags & NETLOGON_NEG_128BIT) {
+		DEBUG(4, ("_net_auth2: NETLOGON_NEG_128BIT auth attempt\n"));
+		session_key_type = 1;
+	}
+
 	if (!p->dc || !p->dc->challenge_sent) {
 		DEBUG(0,("_net_auth2: no challenge sent to client %s\n",
 			remote_machine ));
-		return NT_STATUS_ACCESS_DENIED;
+		status = NT_STATUS_ACCESS_DENIED;
+		goto exit_on_error;
 	}
 
 	if ( (lp_server_schannel() == True) &&
@@ -451,16 +476,42 @@ NTSTATUS _net_auth_2(pipes_struct *p, NE
 		DEBUG(0,("_net_auth2: schannel required but client failed "
 			"to offer it. Client was %s\n",
 			mach_acct ));
-		return NT_STATUS_ACCESS_DENIED;
+		status = NT_STATUS_ACCESS_DENIED;
+		goto exit_on_error;
+	}
+
+
+	if (lp_opendirectory()) {
+		//check acct_ctrl flags
+		tDirStatus dirStatus;
+		become_root();
+		dirStatus =
+			opendirectory_cred_session_key(&p->dc->clnt_chal,
+					&p->dc->srv_chal, mach_acct,
+					p->dc->sess_key, session_key_type);
+		unbecome_root();
+		DEBUG(4, ("_net_auth_2: "
+			"opendirectory_cred_session_key [%d] session_key_type[%d]\n",
+				dirStatus,session_key_type));
+
+		/* FIXME: there should be a proper error mapping from
+		 * tDirStatus to NT_ERROR types -- jpeach
+		 */
+		status = (dirStatus == eDSNoErr) ? NT_STATUS_OK
+		: NT_STATUS_UNSUCCESSFUL;
+
+	} else {
+		status = get_md4pw((char *)p->dc->mach_pw, mach_acct,
+				q_u->clnt_id.sec_chan);
 	}
 
-	status = get_md4pw((char *)p->dc->mach_pw, mach_acct, q_u->clnt_id.sec_chan);
 	if (!NT_STATUS_IS_OK(status)) {
 		DEBUG(0,("_net_auth2: failed to get machine password for "
 			"account %s: %s\n",
 			mach_acct, nt_errstr(status) ));
 		/* always return NT_STATUS_ACCESS_DENIED */
-		return NT_STATUS_ACCESS_DENIED;
+		status = NT_STATUS_ACCESS_DENIED;
+		goto exit_on_error;
 	}
 
 	/* From the client / server challenges and md4 password, generate sess key */
@@ -476,31 +527,40 @@ NTSTATUS _net_auth_2(pipes_struct *p, NE
 		DEBUG(0,("_net_auth2: creds_server_check failed. Rejecting auth "
 			"request from client %s machine account %s\n",
 			remote_machine, mach_acct ));
-		return NT_STATUS_ACCESS_DENIED;
+		status = NT_STATUS_ACCESS_DENIED;
+		goto exit_on_error;
+	} else {
+		DEBUG(4, ("_net_auth2: creds_server_check - server validated client challenge session_key_type[%d]\n", session_key_type));
+		status = NT_STATUS_OK;
 	}
 
+exit_on_error:
+	/* set server capabalities on return */
 	srv_flgs.neg_flags = 0x000001ff;
 
 	if (lp_server_schannel() != False) {
 		srv_flgs.neg_flags |= NETLOGON_NEG_SCHANNEL;
 	}
-
+	if (session_key_type == 1) {
+		srv_flgs.neg_flags |= NETLOGON_NEG_128BIT;
+	}
 	/* set up the LSA AUTH 2 response */
-	init_net_r_auth_2(r_u, &srv_chal_out, &srv_flgs, NT_STATUS_OK);
-
-	fstrcpy(p->dc->mach_acct, mach_acct);
-	fstrcpy(p->dc->remote_machine, remote_machine);
-	fstrcpy(p->dc->domain, lp_workgroup() );
-
-	p->dc->authenticated = True;
+	init_net_r_auth_2(r_u, &srv_chal_out, &srv_flgs, status);
 
-	/* Store off the state so we can continue after client disconnect. */
-	become_root();
-	secrets_store_schannel_session_info(p->mem_ctx,
-					remote_machine,
-					p->dc);
-	unbecome_root();
+	if (NT_STATUS_IS_OK(status)) {
+		fstrcpy(p->dc->mach_acct, mach_acct);
+		fstrcpy(p->dc->remote_machine, remote_machine);
+		fstrcpy(p->dc->domain, lp_workgroup() );
 
+		p->dc->authenticated = True;
+
+		/* Store off the state so we can continue after client disconnect. */
+		become_root();
+		secrets_store_schannel_session_info(p->mem_ctx,
+						remote_machine,
+						p->dc);
+		unbecome_root();
+	}
 	return r_u->status;
 }
 
@@ -603,35 +663,52 @@ NTSTATUS _net_srv_pwset(pipes_struct *p,
 		DEBUG(100,("%02X ", pwd[i]));
 	DEBUG(100,("\n"));
 
-	old_pw = pdb_get_nt_passwd(sampass);
-
-	if (old_pw && memcmp(pwd, old_pw, 16) == 0) {
-		/* Avoid backend modificiations and other fun if the 
-		   client changed the password to the *same thing* */
+	if (lp_opendirectory()) {
+		tDirStatus dirStatus = eDSNullParameter;
 
-		ret = True;
-	} else {
+		become_root();
+		dirStatus =
+		    opendirectory_set_workstation_nthash(p->dc->mach_acct, pwd);
+		unbecome_root();
 
-		/* LM password should be NULL for machines */
-		if (!pdb_set_lanman_passwd(sampass, NULL, PDB_CHANGED)) {
-			TALLOC_FREE(sampass);
-			return NT_STATUS_NO_MEMORY;
-		}
-		
-		if (!pdb_set_nt_passwd(sampass, pwd, PDB_CHANGED)) {
+		DEBUG(2, ("_net_srv_pwset "
+			"opendirectory_set_workstation_nthash [%d]\n",
+			dirStatus));
+		if (dirStatus != eDSNoErr) {
 			TALLOC_FREE(sampass);
-			return NT_STATUS_NO_MEMORY;
+			return NT_STATUS_UNSUCCESSFUL;
 		}
-		
+	} else {
+		old_pw = pdb_get_nt_passwd(sampass);
+
+		if (old_pw && memcmp(pwd, old_pw, 16) == 0) {
+			/* Avoid backend modificiations and other fun if the
+			   client changed the password to the *same thing* */
+
+			ret = True;
+		} else {
+
+			/* LM password should be NULL for machines */
+			if (!pdb_set_lanman_passwd(sampass, NULL, PDB_CHANGED)) {
+				TALLOC_FREE(sampass);
+				return NT_STATUS_NO_MEMORY;
+			}
+
+			if (!pdb_set_nt_passwd(sampass, pwd, PDB_CHANGED)) {
+				TALLOC_FREE(sampass);
+				return NT_STATUS_NO_MEMORY;
+			}
+
 		if (!pdb_set_pass_last_set_time(sampass, time(NULL), PDB_CHANGED)) {
-			TALLOC_FREE(sampass);
-			/* Not quite sure what this one qualifies as, but this will do */
-			return NT_STATUS_UNSUCCESSFUL; 
+				TALLOC_FREE(sampass);
+				/* Not quite sure what this one qualifies as, but this will do */
+				return NT_STATUS_UNSUCCESSFUL;
+			}
+
+			become_root();
+			r_u->status = pdb_update_sam_account(sampass);
+			unbecome_root();
 		}
-		
-		become_root();
-		r_u->status = pdb_update_sam_account(sampass);
-		unbecome_root();
 	}
 
 	/* set up the LSA Server Password Set response */
@@ -964,14 +1041,11 @@ static NTSTATUS _net_sam_logon_internal(
 	{
 		DOM_GID *gids = NULL;
 		const DOM_SID *user_sid = NULL;
-		const DOM_SID *group_sid = NULL;
 		DOM_SID domain_sid;
 		uint32 user_rid, group_rid; 
 
 		int num_gids = 0;
 		pstring my_name;
-		fstring user_sid_string;
-		fstring group_sid_string;
 		unsigned char user_session_key[16];
 		unsigned char lm_session_key[16];
 		unsigned char pipe_session_key[16];
@@ -983,28 +1057,14 @@ static NTSTATUS _net_sam_logon_internal(
 		usr_info->ptr_user_info = 0;
 
 		user_sid = pdb_get_user_sid(sampw);
-		group_sid = pdb_get_group_sid(sampw);
 
-		if ((user_sid == NULL) || (group_sid == NULL)) {
-			DEBUG(1, ("_net_sam_logon: User without group or user SID\n"));
+		if ((user_sid == NULL)) {
+			DEBUG(1, ("_net_sam_logon: User without user SID\n"));
 			return NT_STATUS_UNSUCCESSFUL;
 		}
 
 		sid_copy(&domain_sid, user_sid);
 		sid_split_rid(&domain_sid, &user_rid);
-
-		if (!sid_peek_check_rid(&domain_sid, group_sid, &group_rid)) {
-			DEBUG(1, ("_net_sam_logon: user %s\\%s has user sid "
-				  "%s\n but group sid %s.\n"
-				  "The conflicting domain portions are not "
-				  "supported for NETLOGON calls\n", 	    
-				  pdb_get_domain(sampw),
-				  pdb_get_username(sampw),
-				  sid_to_string(user_sid_string, user_sid),
-				  sid_to_string(group_sid_string, group_sid)));
-			return NT_STATUS_UNSUCCESSFUL;
-		}
-		
 		
 		if(server_info->login_server) {
 		        pstrcpy(my_name, server_info->login_server);
Index: samba/source/libsmb/credentials.c
===================================================================
--- samba/source/libsmb/credentials.c.orig
+++ samba/source/libsmb/credentials.c
@@ -70,9 +70,44 @@ static void creds_init_128(struct dcinfo
 	DEBUG(5,("\tclnt_chal_in: %s\n", credstr(clnt_chal_in->data)));
 	DEBUG(5,("\tsrv_chal_in : %s\n", credstr(srv_chal_in->data)));
 	dump_data_pw("\tsession_key ", (const unsigned char *)dc->sess_key, 16);
+	DEBUG(5,("\tsession_key : \n"));
+	dump_data(5, (const unsigned char *)dc->sess_key,16);
 
 	/* Generate the next client and server creds. */
-	
+
+	des_crypt112(dc->clnt_chal.data,		/* output */
+			clnt_chal_in->data,		/* input */
+			dc->sess_key,			/* input */
+			1);
+
+	des_crypt112(dc->srv_chal.data,			/* output */
+			srv_chal_in->data,		/* input */
+			dc->sess_key,			/* input */
+			1);
+
+	/* Seed is the client chal. */
+	memcpy(dc->seed_chal.data, dc->clnt_chal.data, 8);
+}
+
+/* In the OpenDirectory case, DirectoryService has already provided us
+ * the generated session key because we can't get at the trust account
+ * password hash.
+ */
+static void creds_init_od(struct dcinfo *dc,
+			const DOM_CHAL *clnt_chal_in,
+			const DOM_CHAL *srv_chal_in,
+			const unsigned char mach_pw[16])
+{
+	SMB_ASSERT(lp_opendirectory());
+
+	/* debug output */
+	DEBUG(5,("%s\n", __func__));
+	DEBUG(5,("\tclnt_chal_in: %s\n", credstr(clnt_chal_in->data)));
+	DEBUG(5,("\tsrv_chal_in : %s\n", credstr(srv_chal_in->data)));
+	DEBUG(5,("\tsess_key_out : %s\n", credstr(dc->sess_key)));
+
+	/* Generate the next client and server creds. */
+
 	des_crypt112(dc->clnt_chal.data,		/* output */
 			clnt_chal_in->data,		/* input */
 			dc->sess_key,			/* input */
@@ -187,16 +222,19 @@ void creds_server_init(uint32 neg_flags,
 	dump_data_pw("creds_server_init: machine pass", mach_pw, 16);
 
 	/* Generate the session key and the next client and server creds. */
-	if (neg_flags & NETLOGON_NEG_128BIT) {
-		creds_init_128(dc,
-			clnt_chal,
-			srv_chal,
-			mach_pw);
+	if (lp_opendirectory()) {
+		creds_init_od(dc, clnt_chal,
+			srv_chal, mach_pw);
 	} else {
-		creds_init_64(dc,
-			clnt_chal,
-			srv_chal,
-			mach_pw);
+		if (neg_flags & NETLOGON_NEG_128BIT) {
+		    creds_init_128(dc,
+			    clnt_chal,
+			    srv_chal,
+			    mach_pw);
+		} else {
+			creds_init_64(dc, clnt_chal,
+				srv_chal, mach_pw);
+		}
 	}
 
 	dump_data_pw("creds_server_init: session key", dc->sess_key, 16);
@@ -249,6 +287,10 @@ BOOL creds_server_step(struct dcinfo *dc
 	BOOL ret;
 	struct dcinfo tmp_dc = *dc;
 
+	if (!received_cred || !cred_out) {
+		return false;
+	}
+
 	/* Do all operations on a temporary copy of the dc,
 	   which we throw away if the checks fail. */
 
Index: samba/source/rpc_server/srv_pipe.c
===================================================================
--- samba/source/rpc_server/srv_pipe.c.orig
+++ samba/source/rpc_server/srv_pipe.c
@@ -2062,7 +2062,7 @@ BOOL api_pipe_schannel_process(pipes_str
 
 	auth_len = p->hdr.auth_len;
 
-	if (auth_len != RPC_AUTH_SCHANNEL_SIGN_OR_SEAL_CHK_LEN) {
+	if (auth_len < RPC_AUTH_SCHANNEL_SIGN_OR_SEAL_CHK_LEN) {
 		DEBUG(0,("Incorrect auth_len %u.\n", (unsigned int)auth_len ));
 		return False;
 	}