[PATCH] NTLMSSP client updates (RPC pipes)

Andrew Bartlett abartlet at samba.org
Sun Jul 13 05:50:01 GMT 2003


This patch revives the client-side NTLMSSP support for RPC named pipes
in Samba.  Currently enabled by the 'sign' and 'seal' commands in 
rpcclient, this code is the result of a research effort on my part.

The aim is to prove that our separate NTLMSSP client library actually 
implements NTLMSSP signing and sealing as per Microsoft's NTLMv1 implementation.

The hope is that knowing this will assist us in correctly implementing 
NTLMSSP signing for SMB packets.

This patch replaces the NTLMSSP implementation in rpc_client/cli_pipe.c with
calls to libsmb/ntlmssp.c.  In the process, we have gained the ability to
use the more secure NT password, and the ability to sign, but not seal, 
the pipe connection.  (Previously we were limited to sealing with the 
LM-password derived key).

I have also tested the schannel code, which has had some of it's calling 
routines changed, but otherwise not altered.  I will integrate my schannel 
work into this patch at a later date.

Our new client-side NTLMSSP code also needed alteration to cope with our 
comparatively simple server-side implementation.  A future step is to replace
it with calls to the same NTLMSSP library.

This code is also much more secure than the previous code, as changes to our
cli_pipe routines ensure that the authentication footer cannot be removed
by an attacker, and more error states are correctly handled.

(The same needs to be done to our server)

Andrew Bartlett
-------------- next part --------------
? 1
? config.abartlet
? passdb.xml
? auth/auth_util.idmap-conflict.c
? bin/stNDYv74
? include/smb_ldap.h
? modules/developer.c
? modules/vfs_fake_perms-old.c
? passdb/pdb_ldap.c2
Index: include/client.h
===================================================================
RCS file: /home/cvs/samba/source/include/client.h,v
retrieving revision 1.46.2.10
diff -u -r1.46.2.10 client.h
--- include/client.h	9 Apr 2003 15:54:17 -0000	1.46.2.10
+++ include/client.h	13 Jul 2003 05:28:29 -0000
@@ -133,16 +133,17 @@
 
 	uint16 nt_pipe_fnum;               /* Pipe handle. */
 
+	/* Secure pipe parameters */
+	int pipe_auth_flags;
+
 	uint16 saved_netlogon_pipe_fnum;   /* The "first" pipe to get
                                               the session key for the
                                               schannel. */
 	struct netsec_auth_struct auth_info;
 
+	NTLMSSP_CLIENT_STATE *ntlmssp_pipe_state;
+
 	unsigned char sess_key[16];        /* Current session key. */
-	unsigned char ntlmssp_hash[258];   /* ntlmssp data. */
-	uint32 ntlmssp_cli_flgs;           /* ntlmssp client flags */
-	uint32 ntlmssp_srv_flgs;           /* ntlmssp server flags */
-	uint32 ntlmssp_seq_num;            /* ntlmssp sequence number */
 	DOM_CRED clnt_cred;                /* Client credential. */
 	fstring mach_acct;                 /* MYNAME$. */
 	fstring srv_name_slash;            /* \\remote server. */
Index: include/ntlmssp.h
===================================================================
RCS file: /home/cvs/samba/source/include/ntlmssp.h,v
retrieving revision 1.2.2.7
diff -u -r1.2.2.7 ntlmssp.h
--- include/ntlmssp.h	28 May 2003 05:14:10 -0000	1.2.2.7
+++ include/ntlmssp.h	13 Jul 2003 05:28:29 -0000
@@ -129,5 +129,10 @@
 	/* ntlmv1 */
 	unsigned char ntlmssp_hash[258];
 
+	/* it turns out that we don't always get the
+	   response in at the time we want to process it.
+	   Store it here, until we need it */
+	DATA_BLOB stored_response; 
+	
 } NTLMSSP_CLIENT_STATE;
 
Index: include/rpc_dce.h
===================================================================
RCS file: /home/cvs/samba/source/include/rpc_dce.h,v
retrieving revision 1.22.2.7
diff -u -r1.22.2.7 rpc_dce.h
--- include/rpc_dce.h	16 Apr 2003 15:39:57 -0000	1.22.2.7
+++ include/rpc_dce.h	13 Jul 2003 05:28:30 -0000
@@ -53,15 +53,23 @@
 
 /* NTLMSSP auth type and level. */
 #define NTLMSSP_AUTH_TYPE 0xa
-#define NTLMSSP_AUTH_LEVEL 0x6
+
+/* Generic flags to indicate signing or sealing of an RPC pipe */
+#define RPC_PIPE_AUTH_SIGN_LEVEL 0x5
+#define RPC_PIPE_AUTH_SEAL_LEVEL 0x6
 
 /* Netlogon schannel auth type and level */
 #define NETSEC_AUTH_TYPE 0x44
-#define NETSEC_AUTH_LEVEL 0x6
 #define NETSEC_SIGNATURE { 0x77, 0x00, 0x7a, 0x00, 0xff, 0xff, 0x00, 0x00 }
 #define RPC_AUTH_NETSEC_CHK_LEN 0x20
 #define NETLOGON_NEG_SCHANNEL    0x40000000
 
+/* Internal Flags to indicate what type of authentication on the pipe */
+#define AUTH_PIPE_SIGN    0x0001
+#define AUTH_PIPE_SEAL    0x0002
+#define AUTH_PIPE_NTLMSSP 0x0004
+#define AUTH_PIPE_NETSEC  0x0008
+
 /* Maximum PDU fragment size. */
 #define MAX_PDU_FRAG_LEN 0x1630
 /* #define MAX_PDU_FRAG_LEN 0x10b8		this is what w2k sets */
@@ -231,6 +239,7 @@
 {
 	uchar sess_key[16];
 	uint32 seq_num;
+	uint8 auth_level;
 };
 
 /* RPC_BIND_REQ - ms req bind */
@@ -349,6 +358,5 @@
 } RPC_AUTH_NTLMSSP_CHK;
 
 #define RPC_AUTH_NTLMSSP_CHK_LEN 16
-
 
 #endif /* _DCE_RPC_H */
Index: lib/util.c
===================================================================
RCS file: /home/cvs/samba/source/lib/util.c,v
retrieving revision 1.358.2.30
diff -u -r1.358.2.30 util.c
--- lib/util.c	10 Jul 2003 14:12:37 -0000	1.358.2.30
+++ lib/util.c	13 Jul 2003 05:28:36 -0000
@@ -1911,6 +1911,17 @@
 	}	
 }
 
+void dump_data_pw(const char *msg, const uchar * data, size_t len)
+{
+#ifdef DEBUG_PASSWORD
+	DEBUG(11, ("%s", msg));
+	if (data != NULL && len > 0)
+	{
+		dump_data(11, data, len);
+	}
+#endif
+}
+
 char *tab_depth(int depth)
 {
 	static pstring spaces;
Index: lib/util_str.c
===================================================================
RCS file: /home/cvs/samba/source/lib/util_str.c,v
retrieving revision 1.47.2.28
diff -u -r1.47.2.28 util_str.c
--- lib/util_str.c	3 Jul 2003 19:11:28 -0000	1.47.2.28
+++ lib/util_str.c	13 Jul 2003 05:28:40 -0000
@@ -351,7 +351,7 @@
  NOTE: oldc and newc must be 7 bit characters
 **/
 
-void string_replace(char *s,char oldc,char newc)
+void string_replace(pstring s,char oldc,char newc)
 {
 	push_ucs2(NULL, tmpbuf,s, sizeof(tmpbuf), STR_TERMINATE);
 	string_replace_w(tmpbuf, UCS2_CHAR(oldc), UCS2_CHAR(newc));
Index: libsmb/cliconnect.c
===================================================================
RCS file: /home/cvs/samba/source/libsmb/cliconnect.c,v
retrieving revision 1.71.2.26
diff -u -r1.71.2.26 cliconnect.c
--- libsmb/cliconnect.c	26 Jun 2003 05:26:20 -0000	1.71.2.26
+++ libsmb/cliconnect.c	13 Jul 2003 05:28:42 -0000
@@ -540,6 +540,12 @@
 
 	ntlmssp_state->use_ntlmv2 = lp_client_ntlmv2_auth();
 
+	if (cli->sign_info.negotiated_smb_signing 
+	    || cli->sign_info.mandetory_signing) {
+		ntlmssp_state->neg_flags |= NTLMSSP_NEGOTIATE_SIGN;
+		ntlmssp_state->neg_flags |= NTLMSSP_NEGOTIATE_ALWAYS_SIGN;
+	}
+
 	do {
 		nt_status = ntlmssp_client_update(ntlmssp_state, 
 						  blob_in, &blob_out);
Index: libsmb/clientgen.c
===================================================================
RCS file: /home/cvs/samba/source/libsmb/clientgen.c,v
retrieving revision 1.190.2.14
diff -u -r1.190.2.14 clientgen.c
--- libsmb/clientgen.c	14 May 2003 00:46:43 -0000	1.190.2.14
+++ libsmb/clientgen.c	13 Jul 2003 05:28:45 -0000
@@ -203,12 +203,9 @@
 	fstrcpy(cli->domain   , usr->domain);
 	fstrcpy(cli->user_name, usr->user_name);
 	memcpy(&cli->pwd, &usr->pwd, sizeof(usr->pwd));
-        cli->ntlmssp_flags = usr->ntlmssp_flags;
-        cli->ntlmssp_cli_flgs = usr != NULL ? usr->ntlmssp_flags : 0;
 
-        DEBUG(10,("cli_init_creds: user %s domain %s flgs: %x\nntlmssp_cli_flgs:%x\n",
-               cli->user_name, cli->domain,
-               cli->ntlmssp_flags,cli->ntlmssp_cli_flgs));
+        DEBUG(10,("cli_init_creds: user %s domain %s\n",
+               cli->user_name, cli->domain));
 }
 
 /****************************************************************************
@@ -313,6 +310,9 @@
 
 	cli_free_signing_context(cli);
 	data_blob_free(&cli->secblob);
+
+	if (cli->ntlmssp_pipe_state) 
+		ntlmssp_client_end(&cli->ntlmssp_pipe_state);
 
 	if (cli->mem_ctx) {
 		talloc_destroy(cli->mem_ctx);
Index: libsmb/ntlmssp.c
===================================================================
RCS file: /home/cvs/samba/source/libsmb/ntlmssp.c,v
retrieving revision 1.4.2.10
diff -u -r1.4.2.10 ntlmssp.c
--- libsmb/ntlmssp.c	3 Jul 2003 19:11:28 -0000	1.4.2.10
+++ libsmb/ntlmssp.c	13 Jul 2003 05:28:45 -0000
@@ -410,6 +410,10 @@
 		ntlmssp_state->neg_flags |= NTLMSSP_NEGOTIATE_UNICODE;
 	}
 	
+	if (ntlmssp_state->use_ntlmv2) {
+		ntlmssp_state->neg_flags |= NTLMSSP_NEGOTIATE_NTLM2;
+	}
+	
 	/* generate the ntlmssp negotiate packet */
 	msrpc_gen(next_request, "CddAA",
 		  "NTLMSSP",
@@ -436,7 +440,7 @@
 	uint32 chal_flags, ntlmssp_command, unkn1, unkn2;
 	DATA_BLOB server_domain_blob;
 	DATA_BLOB challenge_blob;
-	DATA_BLOB struct_blob;
+	DATA_BLOB struct_blob = data_blob(NULL, 0);
 	char *server_domain;
 	const char *chal_parse_string;
 	const char *auth_gen_string;
@@ -444,28 +448,48 @@
 	DATA_BLOB nt_response = data_blob(NULL, 0);
 	DATA_BLOB session_key = data_blob(NULL, 0);
 	uint8 datagram_sess_key[16];
+	size_t datagram_sess_key_len;
 
+#if 0 /* until we know what flag to tigger it on */
 	generate_random_buffer(datagram_sess_key, sizeof(datagram_sess_key), False);	
+	datagram_sess_key_len = sizeof(datagram_sess_key);
+#else
+	ZERO_STRUCT(datagram_sess_key);
+	datagram_sess_key_len = 0;
+#endif
 
 	if (!msrpc_parse(&reply, "CdBd",
 			 "NTLMSSP",
 			 &ntlmssp_command, 
 			 &server_domain_blob,
 			 &chal_flags)) {
-		DEBUG(0, ("Failed to parse the NTLMSSP Challenge\n"));
+		DEBUG(1, ("Failed to parse the NTLMSSP Challenge: (#1)\n"));
+		dump_data(2, reply.data, reply.length);
+
 		return NT_STATUS_INVALID_PARAMETER;
 	}
 	
 	data_blob_free(&server_domain_blob);
 
+	DEBUG(3, ("Got challenge flags:\n"));
+	debug_ntlmssp_flags(chal_flags);
+
 	if (chal_flags & NTLMSSP_NEGOTIATE_UNICODE) {
-		chal_parse_string = "CdUdbddB";
+		if (chal_flags & NTLMSSP_CHAL_TARGET_INFO) {
+			chal_parse_string = "CdUdbddB";
+		} else {
+			chal_parse_string = "CdUdbdd";
+		}
 		auth_gen_string = "CdBBUUUBd";
 		ntlmssp_state->unicode = True;
 		ntlmssp_state->neg_flags |= NTLMSSP_NEGOTIATE_UNICODE;
 		ntlmssp_state->neg_flags &= ~NTLMSSP_NEGOTIATE_OEM;
 	} else if (chal_flags & NTLMSSP_NEGOTIATE_OEM) {
-		chal_parse_string = "CdAdbddB";
+		if (chal_flags & NTLMSSP_CHAL_TARGET_INFO) {
+			chal_parse_string = "CdAdbddB";
+		} else {
+			chal_parse_string = "CdAdbdd";
+		}
 		auth_gen_string = "CdBBAAABd";
 		ntlmssp_state->unicode = False;
 		ntlmssp_state->neg_flags &= ~NTLMSSP_NEGOTIATE_UNICODE;
@@ -474,6 +498,25 @@
 		return NT_STATUS_INVALID_PARAMETER;
 	}
 
+	if (chal_flags & NTLMSSP_NEGOTIATE_LM_KEY && lp_client_lanman_auth()) {
+		/* server forcing us to use LM */
+		ntlmssp_state->neg_flags |= NTLMSSP_NEGOTIATE_LM_KEY;
+		ntlmssp_state->use_ntlmv2 = False;
+	} else {
+		ntlmssp_state->neg_flags &= ~NTLMSSP_NEGOTIATE_LM_KEY;
+	}
+
+	if (!(chal_flags & NTLMSSP_NEGOTIATE_NTLM2)) {
+		ntlmssp_state->neg_flags &= ~NTLMSSP_NEGOTIATE_NTLM2;
+	}
+
+	if (!(chal_flags & NTLMSSP_NEGOTIATE_128)) {
+		ntlmssp_state->neg_flags &= ~NTLMSSP_NEGOTIATE_128;
+	}
+
+	DEBUG(3, ("NTLMSSP: Set final flags:\n"));
+	debug_ntlmssp_flags(ntlmssp_state->neg_flags);
+
 	if (!msrpc_parse(&reply, chal_parse_string,
 			 "NTLMSSP",
 			 &ntlmssp_command, 
@@ -482,7 +525,8 @@
 			 &challenge_blob, 8,
 			 &unkn1, &unkn2,
 			 &struct_blob)) {
-		DEBUG(0, ("Failed to parse the NTLMSSP Challenge\n"));
+		DEBUG(1, ("Failed to parse the NTLMSSP Challenge: (#2)\n"));
+		dump_data(2, reply.data, reply.length);
 		return NT_STATUS_INVALID_PARAMETER;
 	}
 
@@ -494,6 +538,11 @@
 
 	if (ntlmssp_state->use_ntlmv2) {
 
+		if (!struct_blob.length) {
+			/* be lazy, match win2k - we can't do NTLMv2 without it */
+			return NT_STATUS_INVALID_PARAMETER;
+		}
+
 		/* TODO: if the remote server is standalone, then we should replace 'domain'
 		   with the server name as supplied above */
 		
@@ -507,10 +556,12 @@
 			return NT_STATUS_NO_MEMORY;
 		}
 	} else {
+		uchar lm_hash[16];
 		uchar nt_hash[16];
+		E_deshash(ntlmssp_state->password, lm_hash);
 		E_md4hash(ntlmssp_state->password, nt_hash);
 		
-		/* non encrypted password supplied. Ignore ntpass. */
+		/* lanman auth is insecure, it may be disabled */
 		if (lp_client_lanman_auth()) {
 			lm_response = data_blob(NULL, 24);
 			SMBencrypt(ntlmssp_state->password,challenge_blob.data,
@@ -520,8 +571,15 @@
 		nt_response = data_blob(NULL, 24);
 		SMBNTencrypt(ntlmssp_state->password,challenge_blob.data,
 			     nt_response.data);
+
 		session_key = data_blob(NULL, 16);
-		SMBsesskeygen_ntv1(nt_hash, NULL, session_key.data);
+		if ((ntlmssp_state->neg_flags & NTLMSSP_NEGOTIATE_LM_KEY) 
+		      && lp_client_lanman_auth()) {
+			SMBsesskeygen_lmv1(lm_hash, lm_response.data, 
+					   session_key.data);
+		} else {
+			SMBsesskeygen_ntv1(nt_hash, NULL, session_key.data);
+		}
 	}
 	data_blob_free(&struct_blob);
 
@@ -534,7 +592,7 @@
 		       ntlmssp_state->domain, 
 		       ntlmssp_state->user, 
 		       ntlmssp_state->get_global_myname(), 
-		       datagram_sess_key, 16,
+		       datagram_sess_key, datagram_sess_key_len,
 		       ntlmssp_state->neg_flags)) {
 		
 		data_blob_free(&lm_response);
@@ -576,6 +634,8 @@
 
 	(*ntlmssp_state)->unicode = True;
 
+	(*ntlmssp_state)->use_ntlmv2 = lp_client_ntlmv2_auth();
+
 	(*ntlmssp_state)->neg_flags = 
 		NTLMSSP_NEGOTIATE_128 |
 		NTLMSSP_NEGOTIATE_NTLM |
@@ -607,12 +667,18 @@
 NTSTATUS ntlmssp_client_update(NTLMSSP_CLIENT_STATE *ntlmssp_state, 
 			       DATA_BLOB reply, DATA_BLOB *next_request) 
 {
+	NTSTATUS nt_status = NT_STATUS_INVALID_PARAMETER;
 	uint32 ntlmssp_command;
 	*next_request = data_blob(NULL, 0);
 
 	if (!reply.length) {
-		return ntlmssp_client_initial(ntlmssp_state, reply, next_request);
-	} 		
+		/* If there is a cached reply, use it - otherwise this is the first packet */
+		if (!ntlmssp_state->stored_response.length) {
+			return ntlmssp_client_initial(ntlmssp_state, reply, next_request);
+		}
+		
+		reply = ntlmssp_state->stored_response;
+	}
 
 	if (!msrpc_parse(&reply, "Cd",
 			 "NTLMSSP",
@@ -621,9 +687,12 @@
 	}
 
 	if (ntlmssp_command == NTLMSSP_CHALLENGE) {
-		return ntlmssp_client_challenge(ntlmssp_state, reply, next_request);
+		nt_status = ntlmssp_client_challenge(ntlmssp_state, reply, next_request);
+	}
+	if (ntlmssp_state->stored_response.length) {
+		data_blob_free(&ntlmssp_state->stored_response);
 	}
-	return NT_STATUS_INVALID_PARAMETER;
+	return nt_status;
 }
 
 NTSTATUS ntlmssp_set_username(NTLMSSP_CLIENT_STATE *ntlmssp_state, const char *user) 
@@ -650,5 +719,18 @@
 	if (!ntlmssp_state->domain) {
 		return NT_STATUS_NO_MEMORY;
 	}
+	return NT_STATUS_OK;
+}
+
+/**
+ *  Store a DATA_BLOB containing an NTLMSSP response, for use later.
+ *  This 'keeps' the data blob - the caller must *not* free it.
+ */
+
+NTSTATUS ntlmssp_client_store_response(NTLMSSP_CLIENT_STATE *ntlmssp_state,
+				       DATA_BLOB response) 
+{
+	data_blob_free(&ntlmssp_state->stored_response);
+	ntlmssp_state->stored_response = response;
 	return NT_STATUS_OK;
 }
Index: libsmb/ntlmssp_parse.c
===================================================================
RCS file: /home/cvs/samba/source/libsmb/ntlmssp_parse.c,v
retrieving revision 1.3.2.1
diff -u -r1.3.2.1 ntlmssp_parse.c
--- libsmb/ntlmssp_parse.c	24 Feb 2003 02:55:00 -0000	1.3.2.1
+++ libsmb/ntlmssp_parse.c	13 Jul 2003 05:28:45 -0000
@@ -220,23 +220,27 @@
 			len2 = SVAL(blob->data, head_ofs); head_ofs += 2;
 			ptr =  IVAL(blob->data, head_ofs); head_ofs += 4;
 
-			/* make sure its in the right format - be strict */
-			if (len1 != len2 || ptr + len1 > blob->length) {
-				return False;
-			}
-			if (len1 & 1) {
-				/* if odd length and unicode */
-				return False;
-			}
-
 			ps = va_arg(ap, char **);
-			if (0 < len1) {
-				pull_string(NULL, p, blob->data + ptr, sizeof(p), 
-					    len1, 
-					    STR_UNICODE|STR_NOALIGN);
-				(*ps) = smb_xstrdup(p);
+			if (len1 == 0 && len2 == 0) {
+				*ps = smb_xstrdup("");
 			} else {
-				(*ps) = smb_xstrdup("");
+				/* make sure its in the right format - be strict */
+				if (len1 != len2 || ptr + len1 > blob->length) {
+					return False;
+				}
+				if (len1 & 1) {
+					/* if odd length and unicode */
+					return False;
+				}
+				
+				if (0 < len1) {
+					pull_string(NULL, p, blob->data + ptr, sizeof(p), 
+						    len1, 
+						    STR_UNICODE|STR_NOALIGN);
+					(*ps) = smb_xstrdup(p);
+				} else {
+					(*ps) = smb_xstrdup("");
+				}
 			}
 			break;
 		case 'A':
@@ -245,19 +249,23 @@
 			len2 = SVAL(blob->data, head_ofs); head_ofs += 2;
 			ptr =  IVAL(blob->data, head_ofs); head_ofs += 4;
 
-			/* make sure its in the right format - be strict */
-			if (len1 != len2 || ptr + len1 > blob->length) {
-				return False;
-			}
-
 			ps = va_arg(ap, char **);
-			if (0 < len1) {
-				pull_string(NULL, p, blob->data + ptr, sizeof(p), 
-					    len1, 
-					    STR_ASCII|STR_NOALIGN);
-				(*ps) = smb_xstrdup(p);
+			/* make sure its in the right format - be strict */
+			if (len1 == 0 && len2 == 0) {
+				*ps = smb_xstrdup("");
 			} else {
-				(*ps) = smb_xstrdup("");
+				if (len1 != len2 || ptr + len1 > blob->length) {
+					return False;
+				}
+				
+				if (0 < len1) {
+					pull_string(NULL, p, blob->data + ptr, sizeof(p), 
+						    len1, 
+						    STR_ASCII|STR_NOALIGN);
+					(*ps) = smb_xstrdup(p);
+				} else {
+					(*ps) = smb_xstrdup("");
+				}
 			}
 			break;
 		case 'B':
@@ -265,12 +273,17 @@
 			len1 = SVAL(blob->data, head_ofs); head_ofs += 2;
 			len2 = SVAL(blob->data, head_ofs); head_ofs += 2;
 			ptr =  IVAL(blob->data, head_ofs); head_ofs += 4;
-			/* make sure its in the right format - be strict */
-			if (len1 != len2 || ptr + len1 > blob->length) {
-				return False;
-			}
+
 			b = (DATA_BLOB *)va_arg(ap, void *);
-			*b = data_blob(blob->data + ptr, len1);
+			if (len1 == 0 && len2 == 0) {
+				*b = data_blob(NULL, 0);
+			} else {
+				/* make sure its in the right format - be strict */
+				if (len1 != len2 || ptr + len1 > blob->length) {
+					return False;
+				}
+				*b = data_blob(blob->data + ptr, len1);
+			}
 			break;
 		case 'b':
 			b = (DATA_BLOB *)va_arg(ap, void *);
Index: libsmb/ntlmssp_sign.c
===================================================================
RCS file: /home/cvs/samba/source/libsmb/ntlmssp_sign.c,v
retrieving revision 1.1.2.3
diff -u -r1.1.2.3 ntlmssp_sign.c
--- libsmb/ntlmssp_sign.c	21 Apr 2003 13:00:39 -0000	1.1.2.3
+++ libsmb/ntlmssp_sign.c	13 Jul 2003 05:28:46 -0000
@@ -79,13 +79,18 @@
 }
 
 static void calc_ntlmv2_hash(unsigned char hash[16], char digest[16],
-			     const char encrypted_response[16], 
+			     DATA_BLOB session_key, 
 			     const char *constant)
 {
 	struct MD5Context ctx3;
 
+	/* NOTE:  This code is currently complate fantasy - it's
+	   got more in common with reality than the previous code
+	   (the LM session key is not the right thing to use) but
+	   it still needs work */
+
 	MD5Init(&ctx3);
-	MD5Update(&ctx3, encrypted_response, 5);
+	MD5Update(&ctx3, session_key.data, session_key.length);
 	MD5Update(&ctx3, constant, strlen(constant));
 	MD5Final(digest, &ctx3);
 
@@ -113,25 +118,28 @@
 		hmac_md5_update(data, length, &ctx);
 		hmac_md5_final(digest, &ctx);
 
-		if (!msrpc_gen(sig, "Bd", digest, sizeof(digest), ntlmssp_state->ntlmssp_seq_num)) {
+		if (!msrpc_gen(sig, "dBd", NTLMSSP_SIGN_VERSION, digest, 8 /* only copy first 8 bytes */
+			       , ntlmssp_state->ntlmssp_seq_num)) {
 			return NT_STATUS_NO_MEMORY;
 		}
 		switch (direction) {
 		case NTLMSSP_SEND:
-			NTLMSSPcalc_ap(ntlmssp_state->cli_sign_hash,  sig->data, sig->length);
+			NTLMSSPcalc_ap(ntlmssp_state->cli_sign_hash,  sig->data+4, sig->length-4);
 			break;
 		case NTLMSSP_RECEIVE:
-			NTLMSSPcalc_ap(ntlmssp_state->srv_sign_hash,  sig->data, sig->length);
+			NTLMSSPcalc_ap(ntlmssp_state->srv_sign_hash,  sig->data+4, sig->length-4);
 			break;
 		}
 	} else {
 		uint32 crc;
 		crc = crc32_calc_buffer(data, length);
-		if (!msrpc_gen(sig, "ddd", 0, crc, ntlmssp_state->ntlmssp_seq_num)) {
+		if (!msrpc_gen(sig, "dddd", NTLMSSP_SIGN_VERSION, 0, crc, ntlmssp_state->ntlmssp_seq_num)) {
 			return NT_STATUS_NO_MEMORY;
 		}
 		
-		NTLMSSPcalc_ap(ntlmssp_state->ntlmssp_hash, sig->data, sig->length);
+		dump_data_pw("ntlmssp hash:\n", ntlmssp_state->ntlmssp_hash,
+			     sizeof(ntlmssp_state->ntlmssp_hash));
+		NTLMSSPcalc_ap(ntlmssp_state->ntlmssp_hash, sig->data+4, sig->length-4);
 	}
 	return NT_STATUS_OK;
 }
@@ -140,8 +148,11 @@
 					   const uchar *data, size_t length, 
 					   DATA_BLOB *sig) 
 {
+	NTSTATUS nt_status = ntlmssp_make_packet_signiture(ntlmssp_state, data, length, NTLMSSP_SEND, sig);
+
+	/* increment counter on send */
 	ntlmssp_state->ntlmssp_seq_num++;
-	return ntlmssp_make_packet_signiture(ntlmssp_state, data, length, NTLMSSP_SEND, sig);
+	return nt_status;
 }
 
 /**
@@ -151,8 +162,8 @@
  */
 
 NTSTATUS ntlmssp_client_check_packet(NTLMSSP_CLIENT_STATE *ntlmssp_state,
-					   const uchar *data, size_t length, 
-					   const DATA_BLOB *sig) 
+				     const uchar *data, size_t length, 
+				     const DATA_BLOB *sig) 
 {
 	DATA_BLOB local_sig;
 	NTSTATUS nt_status;
@@ -170,9 +181,7 @@
 		return nt_status;
 	}
 	
-	if (memcmp(sig->data, local_sig.data, MIN(sig->length, local_sig.length)) == 0) {
-		return NT_STATUS_OK;
-	} else {
+	if (memcmp(sig->data+sig->length - 8, local_sig.data+local_sig.length - 8, 8) != 0) {
 		DEBUG(5, ("BAD SIG: wanted signature of\n"));
 		dump_data(5, local_sig.data, local_sig.length);
 		
@@ -182,6 +191,93 @@
 		DEBUG(0, ("NTLMSSP packet check failed due to invalid signiture!\n"));
 		return NT_STATUS_ACCESS_DENIED;
 	}
+
+	/* increment counter on recieive */
+	ntlmssp_state->ntlmssp_seq_num++;
+
+	return NT_STATUS_OK;
+}
+
+
+/**
+ * Seal data with the NTLMSSP algorithm
+ *
+ */
+
+NTSTATUS ntlmssp_client_seal_packet(NTLMSSP_CLIENT_STATE *ntlmssp_state,
+				    uchar *data, size_t length,
+				    DATA_BLOB *sig)
+{	
+	DEBUG(10,("ntlmssp_client_seal_data: seal\n"));
+	dump_data_pw("ntlmssp clear data\n", data, length);
+	if (ntlmssp_state->neg_flags & NTLMSSP_NEGOTIATE_NTLM2) {
+		HMACMD5Context ctx;
+		char seq_num[4];
+		uchar digest[16];
+		SIVAL(seq_num, 0, ntlmssp_state->ntlmssp_seq_num);
+
+		hmac_md5_init_limK_to_64(ntlmssp_state->cli_sign_const, 16, &ctx);
+		hmac_md5_update(seq_num, 4, &ctx);
+		hmac_md5_update(data, length, &ctx);
+		hmac_md5_final(digest, &ctx);
+
+		if (!msrpc_gen(sig, "dBd", NTLMSSP_SIGN_VERSION, digest, 8 /* only copy first 8 bytes */
+			       , ntlmssp_state->ntlmssp_seq_num)) {
+			return NT_STATUS_NO_MEMORY;
+		}
+
+		dump_data_pw("ntlmssp client sealing hash:\n", 
+			     ntlmssp_state->cli_seal_hash,
+			     sizeof(ntlmssp_state->cli_seal_hash));
+		NTLMSSPcalc_ap(ntlmssp_state->cli_seal_hash, data, length);
+		dump_data_pw("ntlmssp client signing hash:\n", 
+			     ntlmssp_state->cli_sign_hash,
+			     sizeof(ntlmssp_state->cli_sign_hash));
+		NTLMSSPcalc_ap(ntlmssp_state->cli_sign_hash,  sig->data+4, sig->length-4);
+	} else {
+		uint32 crc;
+		crc = crc32_calc_buffer(data, length);
+		if (!msrpc_gen(sig, "dddd", NTLMSSP_SIGN_VERSION, 0, crc, ntlmssp_state->ntlmssp_seq_num)) {
+			return NT_STATUS_NO_MEMORY;
+		}
+		
+		dump_data_pw("ntlmssp hash:\n", ntlmssp_state->ntlmssp_hash,
+			     sizeof(ntlmssp_state->ntlmssp_hash));
+		NTLMSSPcalc_ap(ntlmssp_state->ntlmssp_hash, data, length);
+
+		dump_data_pw("ntlmssp hash:\n", ntlmssp_state->ntlmssp_hash,
+			     sizeof(ntlmssp_state->ntlmssp_hash));
+		NTLMSSPcalc_ap(ntlmssp_state->ntlmssp_hash, sig->data+4, sig->length-4);
+	}
+	dump_data_pw("ntlmssp sealed data\n", data, length);
+
+	/* increment counter on send */
+	ntlmssp_state->ntlmssp_seq_num++;
+
+	return NT_STATUS_OK;
+}
+
+/**
+ * Unseal data with the NTLMSSP algorithm
+ *
+ */
+
+NTSTATUS ntlmssp_client_unseal_packet(NTLMSSP_CLIENT_STATE *ntlmssp_state,
+				      uchar *data, size_t length,
+				      DATA_BLOB *sig)
+{
+	DEBUG(10,("ntlmssp_client_unseal_data: seal\n"));
+	dump_data_pw("ntlmssp sealed data\n", data, length);
+	if (ntlmssp_state->neg_flags & NTLMSSP_NEGOTIATE_NTLM2) {
+		NTLMSSPcalc_ap(ntlmssp_state->srv_seal_hash, data, length);
+	} else {
+		dump_data_pw("ntlmssp hash:\n", ntlmssp_state->ntlmssp_hash,
+			     sizeof(ntlmssp_state->ntlmssp_hash));
+		NTLMSSPcalc_ap(ntlmssp_state->ntlmssp_hash, data, length);
+	}
+	dump_data_pw("ntlmssp clear data\n", data, length);
+
+	return ntlmssp_client_check_packet(ntlmssp_state, data, length, sig);
 }
 
 /**
@@ -190,37 +286,69 @@
 NTSTATUS ntlmssp_client_sign_init(NTLMSSP_CLIENT_STATE *ntlmssp_state)
 {
 	unsigned char p24[24];
-	unsigned char lm_hash[16];
+	ZERO_STRUCT(p24);
+
+	DEBUG(3, ("NTLMSSP Sign/Seal - Initialising with flags:\n"));
+	debug_ntlmssp_flags(ntlmssp_state->neg_flags);
 
-	if (!ntlmssp_state->lm_resp.data) {
-		/* can't sign or check signitures yet */ 
-		return NT_STATUS_UNSUCCESSFUL;
-	}
-			    
-	E_deshash(ntlmssp_state->password, lm_hash);
-		
-	NTLMSSPOWFencrypt(lm_hash, ntlmssp_state->lm_resp.data, p24);
-	
 	if (ntlmssp_state->neg_flags & NTLMSSP_NEGOTIATE_NTLM2)
 	{
-		calc_ntlmv2_hash(ntlmssp_state->cli_sign_hash, ntlmssp_state->cli_sign_const, p24, CLI_SIGN);
-		calc_ntlmv2_hash(ntlmssp_state->cli_seal_hash, ntlmssp_state->cli_seal_const, p24, CLI_SEAL);
-		calc_ntlmv2_hash(ntlmssp_state->srv_sign_hash, ntlmssp_state->srv_sign_const, p24, SRV_SIGN);
-		calc_ntlmv2_hash(ntlmssp_state->srv_seal_hash, ntlmssp_state->srv_seal_const, p24, SRV_SEAL);
-	}
-	else
-	{
-		char k2[8];
-		memcpy(k2, p24, 5);
-		k2[5] = 0xe5;
-		k2[6] = 0x38;
-		k2[7] = 0xb0;
+
+		calc_ntlmv2_hash(ntlmssp_state->cli_sign_hash, 
+				 ntlmssp_state->cli_sign_const, 
+				 ntlmssp_state->session_key, CLI_SIGN);
+		dump_data_pw("NTLMSSP client sign hash:\n", 
+			     ntlmssp_state->cli_sign_hash, 
+			     sizeof(ntlmssp_state->cli_sign_hash));
+
+		calc_ntlmv2_hash(ntlmssp_state->cli_seal_hash, 
+				 ntlmssp_state->cli_seal_const, 
+				 ntlmssp_state->session_key, CLI_SEAL);
+		dump_data_pw("NTLMSSP client sesl hash:\n", 
+			     ntlmssp_state->cli_seal_hash, 
+			     sizeof(ntlmssp_state->cli_seal_hash));
+
+		calc_ntlmv2_hash(ntlmssp_state->srv_sign_hash, 
+				 ntlmssp_state->srv_sign_const, 
+				 ntlmssp_state->session_key, SRV_SIGN);
+		dump_data_pw("NTLMSSP server sign hash:\n", 
+			     ntlmssp_state->srv_sign_hash, 
+			     sizeof(ntlmssp_state->srv_sign_hash));
+
+		calc_ntlmv2_hash(ntlmssp_state->srv_seal_hash, 
+				 ntlmssp_state->srv_seal_const, 
+				 ntlmssp_state->session_key, SRV_SEAL);
+		dump_data_pw("NTLMSSP server seal hash:\n", 
+			     ntlmssp_state->cli_sign_hash, 
+			     sizeof(ntlmssp_state->cli_sign_hash));
+	} 
+	else if (ntlmssp_state->neg_flags & NTLMSSP_NEGOTIATE_LM_KEY) {
+		if (!ntlmssp_state->session_key.data || ntlmssp_state->session_key.length < 8) {
+			/* can't sign or check signitures yet */ 
+			DEBUG(5, ("NTLMSSP Sign/Seal - cannot use LM KEY yet\n"));	
+			return NT_STATUS_UNSUCCESSFUL;
+		}
+		
+		DEBUG(5, ("NTLMSSP Sign/Seal - using LM KEY\n"));
+
+		calc_hash(ntlmssp_state->ntlmssp_hash, ntlmssp_state->session_key.data, 8);
+		dump_data_pw("NTLMSSP hash:\n", ntlmssp_state->ntlmssp_hash,
+			     sizeof(ntlmssp_state->ntlmssp_hash));
+	} else {
+		if (!ntlmssp_state->session_key.data || ntlmssp_state->session_key.length < 16) {
+			/* can't sign or check signitures yet */ 
+			DEBUG(5, ("NTLMSSP Sign/Seal - cannot use NT KEY yet\n"));
+			return NT_STATUS_UNSUCCESSFUL;
+		}
 		
-		calc_hash(ntlmssp_state->ntlmssp_hash, k2, 8);
+		DEBUG(5, ("NTLMSSP Sign/Seal - using NT KEY\n"));
+
+		calc_hash(ntlmssp_state->ntlmssp_hash, ntlmssp_state->session_key.data, 16);
+		dump_data_pw("NTLMSSP hash:\n", ntlmssp_state->ntlmssp_hash,
+			     sizeof(ntlmssp_state->ntlmssp_hash));
 	}
 
 	ntlmssp_state->ntlmssp_seq_num = 0;
 
-	ZERO_STRUCT(lm_hash);
 	return NT_STATUS_OK;
 }
Index: libsmb/pwd_cache.c
===================================================================
RCS file: /home/cvs/samba/source/libsmb/pwd_cache.c,v
retrieving revision 1.24.2.2
diff -u -r1.24.2.2 pwd_cache.c
--- libsmb/pwd_cache.c	12 Nov 2002 23:20:45 -0000	1.24.2.2
+++ libsmb/pwd_cache.c	13 Jul 2003 05:28:46 -0000
@@ -43,15 +43,10 @@
 
 static void pwd_make_lm_nt_16(struct pwd_info *pwd, const char *clr)
 {
-	pstring dos_passwd;
-
 	pwd_init(pwd);
 
-	push_ascii_pstring(dos_passwd, clr);
-
-	nt_lm_owf_gen(dos_passwd, pwd->smb_nt_pwd, pwd->smb_lm_pwd);
+	nt_lm_owf_gen(clr, pwd->smb_nt_pwd, pwd->smb_lm_pwd);
 	pwd->null_pwd  = False;
-	pwd->cleartext = False;
 	pwd->crypted = False;
 }
 
@@ -61,12 +56,9 @@
 
 void pwd_set_cleartext(struct pwd_info *pwd, const char *clr)
 {
-	pwd_init(pwd);
-	push_ascii_fstring(pwd->password, clr);
-	pwd->cleartext = True;
-	pwd->null_pwd  = False;
-	pwd->crypted   = False;
 	pwd_make_lm_nt_16(pwd, clr);
+	fstrcpy(pwd->password, clr);
+	pwd->cleartext = True;
 }
 
 /****************************************************************************
Index: libsmb/smbencrypt.c
===================================================================
RCS file: /home/cvs/samba/source/libsmb/smbencrypt.c,v
retrieving revision 1.68.2.9
diff -u -r1.68.2.9 smbencrypt.c
--- libsmb/smbencrypt.c	9 May 2003 14:42:20 -0000	1.68.2.9
+++ libsmb/smbencrypt.c	13 Jul 2003 05:28:48 -0000
@@ -271,6 +271,8 @@
 void SMBsesskeygen_ntv2(const uchar kr[16],
 			const uchar * nt_resp, uint8 sess_key[16])
 {
+	/* a very nice, 128 bit, variable session key */
+	
 	HMACMD5Context ctx;
 
 	hmac_md5_init_limK_to_64(kr, 16, &ctx);
@@ -286,10 +288,39 @@
 void SMBsesskeygen_ntv1(const uchar kr[16],
 			const uchar * nt_resp, uint8 sess_key[16])
 {
+	/* yes, this session key does not change - yes, this 
+	   is a problem - but it is 128 bits */
+	
 	mdfour((unsigned char *)sess_key, kr, 16);
 
 #ifdef DEBUG_PASSWORD
 	DEBUG(100, ("SMBsesskeygen_ntv1:\n"));
+	dump_data(100, sess_key, 16);
+#endif
+}
+
+void SMBsesskeygen_lmv1(const uchar lm_hash[16],
+			const uchar lm_resp[24], /* only uses 8 */ 
+			uint8 sess_key[16])
+{
+	/* Calculate the LM session key (effective length 40 bits,
+	   but changes with each session) */
+
+	uchar p24[24];
+	uchar partial_lm_hash[16];
+	
+	memcpy(partial_lm_hash, lm_hash, 8);
+	memset(partial_lm_hash + 8, 0xbd, 8);    
+
+	SMBOWFencrypt(lm_hash, lm_resp, p24);
+	
+	memcpy(sess_key, p24, 16);
+	sess_key[5] = 0xe5;
+	sess_key[6] = 0x38;
+	sess_key[7] = 0xb0;
+
+#ifdef DEBUG_PASSWORD
+	DEBUG(100, ("SMBsesskeygen_lmv1:\n"));
 	dump_data(100, sess_key, 16);
 #endif
 }
Index: rpc_client/cli_pipe.c
===================================================================
RCS file: /home/cvs/samba/source/rpc_client/cli_pipe.c,v
retrieving revision 1.79.2.25
diff -u -r1.79.2.25 cli_pipe.c
--- rpc_client/cli_pipe.c	3 Jul 2003 19:11:29 -0000	1.79.2.25
+++ rpc_client/cli_pipe.c	13 Jul 2003 05:28:51 -0000
@@ -28,6 +28,23 @@
 
 extern struct pipe_id_info pipe_names[];
 
+void get_auth_type_level(int pipe_auth_flags, int *auth_type, int *auth_level) 
+{
+	*auth_type = 0;
+	*auth_level = 0;
+	if (pipe_auth_flags & AUTH_PIPE_SEAL) {
+		*auth_level = RPC_PIPE_AUTH_SEAL_LEVEL;
+	} else if (pipe_auth_flags & AUTH_PIPE_SIGN) {
+		*auth_level = RPC_PIPE_AUTH_SIGN_LEVEL;
+	}
+	
+	if (pipe_auth_flags & AUTH_PIPE_NETSEC) {
+		*auth_type = NETSEC_AUTH_TYPE;
+	} else if (pipe_auth_flags & AUTH_PIPE_NTLMSSP) {
+		*auth_type = NTLMSSP_AUTH_TYPE;
+	}
+}
+
 /********************************************************************
  Rpc pipe call id.
  ********************************************************************/
@@ -132,32 +149,6 @@
 	return (rhdr->pkt_type != RPC_FAULT);
 }
 
-static void NTLMSSPcalc_ap( struct cli_state *cli, unsigned char *data, uint32 len)
-{
-	unsigned char *hash = cli->ntlmssp_hash;
-	unsigned char index_i = hash[256];
-	unsigned char index_j = hash[257];
-	int ind;
-
-	for( ind = 0; ind < len; ind++) {
-		unsigned char tc;
-		unsigned char t;
-
-		index_i++;
-		index_j += hash[index_i];
-
-		tc = hash[index_i];
-		hash[index_i] = hash[index_j];
-		hash[index_j] = tc;
-
-		t = hash[index_i] + hash[index_j];
-		data[ind] = data[ind] ^ hash[t];
-	}
-
-	hash[256] = index_i;
-	hash[257] = index_j;
-}
-
 /****************************************************************************
  Verify data on an rpc pipe.
  The VERIFY & SEAL code is only executed on packets that look like this :
@@ -175,8 +166,10 @@
  ****************************************************************************/
 
 static BOOL rpc_auth_pipe(struct cli_state *cli, prs_struct *rdata,
-		uint32 fragment_start, int len, int auth_len, int *pauth_padding_len)
+			  uint32 fragment_start, int len, int auth_len, uint8 pkt_type,
+			  int *pauth_padding_len)
 {
+	
 	/*
 	 * The following is that length of the data we must sign or seal.
 	 * This doesn't include the RPC headers or the auth_len or the RPC_HDR_AUTH_LEN
@@ -190,180 +183,178 @@
 	 */
 	char *reply_data = prs_data_p(rdata) + fragment_start + RPC_HEADER_LEN + RPC_HDR_REQ_LEN;
 
-	BOOL auth_verify = ((cli->ntlmssp_srv_flgs & NTLMSSP_NEGOTIATE_SIGN) != 0);
-	BOOL auth_seal = ((cli->ntlmssp_srv_flgs & NTLMSSP_NEGOTIATE_SEAL) != 0);
-	BOOL auth_schannel = (cli->saved_netlogon_pipe_fnum != 0);
+	RPC_HDR_AUTH rhdr_auth; 
 
 	*pauth_padding_len = 0;
 
-	DEBUG(5,("rpc_auth_pipe: len: %d auth_len: %d verify %s seal %s schannel %s\n",
-	          len, auth_len, BOOLSTR(auth_verify), BOOLSTR(auth_seal), BOOLSTR(auth_schannel)));
-
-	/*
-	 * Unseal any sealed data in the PDU, not including the
-	 * 8 byte auth_header or the auth_data.
-	 */
+	if (auth_len == 0) {
+		if (cli->pipe_auth_flags == 0) {
+			/* move along, nothing to see here */
+			return True;
+		}
 
-	if (auth_seal) {
-		DEBUG(10,("rpc_auth_pipe: unseal\n"));
-		dump_data(100, reply_data, data_len);
-		NTLMSSPcalc_ap(cli, (uchar*)reply_data, data_len);
-		dump_data(100, reply_data, data_len);
+		DEBUG(2, ("No authenticaton header recienved on reply, but this pipe is authenticated\n"));
+		return False;
 	}
 
-	if (auth_verify || auth_seal) {
-		RPC_HDR_AUTH rhdr_auth; 
-		prs_struct auth_req;
-		char data[RPC_HDR_AUTH_LEN];
-		/*
-		 * We set dp to be the end of the packet, minus the auth_len
-		 * and the length of the header that preceeds the auth_data.
-		 */
-		char *dp = prs_data_p(rdata) + len - auth_len - RPC_HDR_AUTH_LEN;
+	DEBUG(5,("rpc_auth_pipe: pkt_type: %d len: %d auth_len: %d NTLMSSP %s schannel %s sign %s seal %s \n",
+		 pkt_type, len, auth_len, 
+		 BOOLSTR(cli->pipe_auth_flags & AUTH_PIPE_NTLMSSP), 
+		 BOOLSTR(cli->pipe_auth_flags & AUTH_PIPE_NETSEC), 
+		 BOOLSTR(cli->pipe_auth_flags & AUTH_PIPE_SIGN), 
+		 BOOLSTR(cli->pipe_auth_flags & AUTH_PIPE_SEAL)));
 
-		if(dp - prs_data_p(rdata) > prs_data_size(rdata)) {
-			DEBUG(0,("rpc_auth_pipe: auth data > data size !\n"));
+	{
+		int auth_type;
+		int auth_level;
+		char *dp = prs_data_p(rdata) + fragment_start + len -
+					RPC_HDR_AUTH_LEN - auth_len;
+		prs_struct auth_verf;
+
+		if (dp - prs_data_p(rdata) > prs_data_size(rdata)) {
+			DEBUG(0,("rpc_auth_pipe: schannel auth data > data size !\n"));
 			return False;
 		}
 
-		memcpy(data, dp, sizeof(data));
-		
-		prs_init(&auth_req , 0, cli->mem_ctx, UNMARSHALL);
+		DEBUG(10,("rpc_auth_pipe: packet:\n"));
+		dump_data(100, dp, auth_len);
 
-		/* The endianness must be preserved... JRA. */
+		prs_init(&auth_verf, RPC_HDR_AUTH_LEN, cli->mem_ctx, UNMARSHALL);
 
-		prs_set_endian_data(&auth_req, rdata->bigendian_data);
+		/* The endinness must be preserved. JRA. */
+		prs_set_endian_data( &auth_verf, rdata->bigendian_data);
 
-		prs_give_memory(&auth_req, data, RPC_HDR_AUTH_LEN, False);
+		prs_copy_data_in(&auth_verf, dp, RPC_HDR_AUTH_LEN);
+		prs_set_offset(&auth_verf, 0);
 
-		/*
-		 * Unmarshall the 8 byte auth_header that comes before the
-		 * auth data.
-		 */
 
-		if(!smb_io_rpc_hdr_auth("hdr_auth", &rhdr_auth, &auth_req, 0)) {
-			DEBUG(0,("rpc_auth_pipe: unmarshalling RPC_HDR_AUTH failed.\n"));
+		if (!smb_io_rpc_hdr_auth("auth_hdr", &rhdr_auth, &auth_verf, 0)) {
+			DEBUG(0, ("rpc_auth_pipe: Could not parse auth header\n"));
 			return False;
 		}
 
-		if (!rpc_hdr_auth_chk(&rhdr_auth)) {
-			DEBUG(0,("rpc_auth_pipe: rpc_hdr_auth_chk failed.\n"));
+		/* Let the caller know how much padding at the end of the data */
+		*pauth_padding_len = rhdr_auth.padding;
+		
+		/* Check it's the type of reply we were expecting to decode */
+
+		get_auth_type_level(cli->pipe_auth_flags, &auth_type, &auth_level);
+		if (rhdr_auth.auth_type != auth_type) {
+			DEBUG(0, ("BAD auth type %d (should be %d)\n",
+				  rhdr_auth.auth_type, auth_type));
 			return False;
 		}
-	}
-
-	/*
-	 * Now unseal and check the auth verifier in the auth_data at
-	 * then end of the packet. The 4 bytes skipped in the unseal
-	 * seem to be a buffer pointer preceeding the sealed data.
-	 */
-
-	if (auth_verify) {
-		RPC_AUTH_NTLMSSP_CHK chk;
-		uint32 crc32;
-		prs_struct auth_verf;
-		char data[RPC_AUTH_NTLMSSP_CHK_LEN];
-		char *dp = prs_data_p(rdata) + len - auth_len;
-
-		if(dp - prs_data_p(rdata) > prs_data_size(rdata)) {
-			DEBUG(0,("rpc_auth_pipe: auth data > data size !\n"));
+		
+		if (rhdr_auth.auth_level != auth_level) {
+			DEBUG(0, ("BAD auth level %d (should be %d)\n", 
+				  rhdr_auth.auth_level, auth_level));
 			return False;
 		}
+	}
 
-		DEBUG(10,("rpc_auth_pipe: verify\n"));
-		dump_data(100, dp, auth_len);
-		NTLMSSPcalc_ap(cli, (uchar*)(dp+4), auth_len - 4);
-
-		memcpy(data, dp, RPC_AUTH_NTLMSSP_CHK_LEN);
-		dump_data(100, data, auth_len);
-
-		prs_init(&auth_verf, 0, cli->mem_ctx, UNMARSHALL);
-
-		/* The endinness must be preserved. JRA. */
-		prs_set_endian_data( &auth_verf, rdata->bigendian_data);
+	if (pkt_type == RPC_BINDACK) {
+		if (cli->pipe_auth_flags & AUTH_PIPE_NTLMSSP) {
+			char *dp = prs_data_p(rdata) + len - auth_len;
+			
+			if(dp - prs_data_p(rdata) > prs_data_size(rdata)) {
+				DEBUG(0,("rpc_auth_pipe: auth data > data size !\n"));
+				return False;
+			}
+			
+			/* save the reply away, for use a little later */
+			return (NT_STATUS_IS_OK(ntlmssp_client_store_response(cli->ntlmssp_pipe_state, 
+									      data_blob(dp, auth_len))));
+		}
+		if (cli->pipe_auth_flags & AUTH_PIPE_NETSEC) {
+			/* nothing to do here - we don't seem to be able to validate the
+			   bindack based on VL's comments */
+			return True;
+		}
+	}
+	
+	if (cli->pipe_auth_flags & AUTH_PIPE_NTLMSSP) {
+		NTSTATUS nt_status;
+		DATA_BLOB sig;
+		if ((cli->pipe_auth_flags & AUTH_PIPE_SIGN) ||
+		    (cli->pipe_auth_flags & AUTH_PIPE_SEAL)) {
+			char *dp = prs_data_p(rdata) + len - auth_len;
+			
+			if(dp - prs_data_p(rdata) > prs_data_size(rdata)) {
+				DEBUG(0,("rpc_auth_pipe: auth data > data size !\n"));
+				return False;
+			}
+			
+			if (auth_len != RPC_AUTH_NTLMSSP_CHK_LEN) {
+				DEBUG(0,("rpc_auth_pipe: wrong ntlmssp auth len %d\n", auth_len));
+				return False;
+			}
+			
+			sig = data_blob(dp, auth_len);
+		}
+	
+		/*
+		 * Unseal any sealed data in the PDU, not including the
+		 * 8 byte auth_header or the auth_data.
+		 */
 
-		prs_give_memory(&auth_verf, data, RPC_AUTH_NTLMSSP_CHK_LEN, False);
+		/*
+		 * Now unseal and check the auth verifier in the auth_data at
+		 * the end of the packet. 
+		 */
 
-		if(!smb_io_rpc_auth_ntlmssp_chk("auth_sign", &chk, &auth_verf, 0)) {
-			DEBUG(0,("rpc_auth_pipe: unmarshalling RPC_AUTH_NTLMSSP_CHK failed.\n"));
-			return False;
+		if (cli->pipe_auth_flags & AUTH_PIPE_SEAL) {
+			if (data_len < 0) {
+				DEBUG(1, ("Can't unseal - data_len < 0!!\n"));
+				return False;
+			}
+			nt_status = ntlmssp_client_unseal_packet(cli->ntlmssp_pipe_state, 
+						     reply_data, data_len,
+						     &sig);
+		} 
+		else if (cli->pipe_auth_flags & AUTH_PIPE_SIGN) {
+			nt_status = ntlmssp_client_check_packet(cli->ntlmssp_pipe_state, 
+								reply_data, data_len,
+								&sig);
 		}
 
-		crc32 = crc32_calc_buffer(reply_data, data_len);
+		data_blob_free(&sig);
 
-		if (!rpc_auth_ntlmssp_chk(&chk, crc32 , cli->ntlmssp_seq_num)) {
-			DEBUG(0,("rpc_auth_pipe: rpc_auth_ntlmssp_chk failed.\n"));
+		if (!NT_STATUS_IS_OK(nt_status)) {
+			DEBUG(0, ("rpc_auth_pipe: could not validate "
+				  "incoming NTLMSSP packet!\n"));
 			return False;
 		}
-		cli->ntlmssp_seq_num++;
 	}
 
-	if (auth_schannel) {
+	if (cli->pipe_auth_flags & AUTH_PIPE_NETSEC) {
 		RPC_AUTH_NETSEC_CHK chk;
-		RPC_HDR_AUTH rhdr_auth;
-		char data[RPC_HDR_AUTH_LEN+RPC_AUTH_NETSEC_CHK_LEN];
-		char *dp = prs_data_p(rdata) + fragment_start + len -
-					RPC_HDR_AUTH_LEN - RPC_AUTH_NETSEC_CHK_LEN;
-		prs_struct auth_verf;
-
-		if (auth_len != RPC_AUTH_NETSEC_CHK_LEN) {
-
-			if ( (auth_len == 12) &&
-			     (cli->auth_info.seq_num == 0) ) {
-
-				/* This is the reply to our bind. Ok,
-                                   the sequence number can wrap
-                                   around. But this only means that
-                                   every 4 billion request we
-                                   misdetect a wrong length in a
-                                   reply. This is an error condition
-                                   which will lead to failure anyway
-                                   later.
-
-				   The reply contains a
-				   RPC_AUTH_VERIFIER with no content
-				   (12 bytes), so ignore it.
-				*/
-				return True;
-			}
+		prs_struct netsec_verf;
 
-			DEBUG(0,("rpc_auth_pipe: wrong schannel auth len %d\n", auth_len));
+		char *dp = prs_data_p(rdata) + len - auth_len;
+		
+		if(dp - prs_data_p(rdata) > prs_data_size(rdata)) {
+			DEBUG(0,("rpc_auth_pipe: auth data > data size !\n"));
 			return False;
 		}
 
-		if (dp - prs_data_p(rdata) > prs_data_size(rdata)) {
-			DEBUG(0,("rpc_auth_pipe: schannel auth data > data size !\n"));
+		if (auth_len != RPC_AUTH_NETSEC_CHK_LEN) {
+			DEBUG(0,("rpc_auth_pipe: wrong schannel auth len %d\n", auth_len));
 			return False;
 		}
 
-		DEBUG(10,("rpc_auth_pipe: schannel verify netsec\n"));
-		dump_data(100, dp, auth_len);
-
-		memcpy(data, dp, sizeof(data));
-		dump_data(100, data, sizeof(data));
-
-		prs_init(&auth_verf, 0, cli->mem_ctx, UNMARSHALL);
+		prs_init(&netsec_verf, RPC_AUTH_NETSEC_CHK_LEN, cli->mem_ctx, UNMARSHALL);
 
 		/* The endinness must be preserved. JRA. */
-		prs_set_endian_data( &auth_verf, rdata->bigendian_data);
-
-		prs_give_memory(&auth_verf, data, sizeof(data), False);
+		prs_set_endian_data( &netsec_verf, rdata->bigendian_data);
 
-		if (!smb_io_rpc_hdr_auth("auth_hdr", &rhdr_auth, &auth_verf, 0)) {
-			DEBUG(0, ("rpc_auth_pipe: Could not parse schannel auth header\n"));
-			return False;
-		}
+		prs_copy_data_in(&netsec_verf, dp, auth_len);
+		prs_set_offset(&netsec_verf, 0);
 
-		if ((rhdr_auth.auth_type != NETSEC_AUTH_TYPE) ||
-				(rhdr_auth.auth_level != NETSEC_AUTH_LEVEL)) {
-			DEBUG(0, ("rpc_auth_pipe: Got wrong schannel auth type/level: %d/%d\n",
-				rhdr_auth.auth_type, rhdr_auth.auth_level));
-			return False;
-		}
-
-		if (!smb_io_rpc_auth_netsec_chk("schannel_auth_sign", &chk, &auth_verf, 0)) {
+		if (!smb_io_rpc_auth_netsec_chk("schannel_auth_sign", 
+						&chk, &netsec_verf, 0)) {
 			DEBUG(0, ("rpc_auth_pipe: schannel unmarshalling "
 				  "RPC_AUTH_NETSECK_CHK failed\n"));
+			prs_mem_free(&netsec_verf);
 			return False;
 		}
 
@@ -371,9 +362,10 @@
 
 		if (!netsec_decode(&cli->auth_info, &chk, reply_data, data_len)) {
 			DEBUG(0, ("rpc_auth_pipe: Could not decode schannel\n"));
+			prs_mem_free(&netsec_verf);
 			return False;
 		}
-		*pauth_padding_len = rhdr_auth.padding;
+		prs_mem_free(&netsec_verf);
 	}
 	return True;
 }
@@ -403,7 +395,8 @@
 
  ****************************************************************************/
 
-static BOOL rpc_api_pipe(struct cli_state *cli, prs_struct *data, prs_struct *rdata)
+static BOOL rpc_api_pipe(struct cli_state *cli, prs_struct *data, prs_struct *rdata,
+			 uint8 expected_pkt_type)
 {
 	uint32 len;
 	char *rparam = NULL;
@@ -419,6 +412,7 @@
 	uint32 current_offset = 0;
 	uint32 fragment_start = 0;
 	uint32 max_data = cli->max_xmit_frag ? cli->max_xmit_frag : 1024;
+	int auth_padding_len = 0;
 
 	/* Create setup parameters - must be in native byte order. */
 
@@ -476,6 +470,12 @@
 		}
 	}
 
+	if (rhdr.pkt_type == RPC_BINDNACK) {
+		DEBUG(3, ("Bind NACK received on