[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 pipe %x!\n", (int)cli->nt_pipe_fnum));
+		prs_mem_free(rdata);
+		return False;
+	}
+
 	if (rhdr.pkt_type == RPC_RESPONSE) {
 		RPC_HDR_RESP rhdr_resp;
 		if(!smb_io_rpc_hdr_resp("rpc_hdr_resp", &rhdr_resp, rdata, 0)) {
@@ -485,6 +485,12 @@
 		}
 	}
 
+	if (rhdr.pkt_type != expected_pkt_type) {
+		DEBUG(3, ("Connection to pipe %x got an unexpected RPC packet type - %d, not %d\n", (int)cli->nt_pipe_fnum, rhdr.pkt_type, expected_pkt_type));
+		prs_mem_free(rdata);
+		return False;
+	}
+
 	DEBUG(5,("rpc_api_pipe: len left: %u smbtrans read: %u\n",
 	          (unsigned int)len, (unsigned int)rdata_len ));
 
@@ -507,12 +513,13 @@
 	 * Now we have a complete PDU, check the auth struct if any was sent.
 	 */
 
-	if (rhdr.auth_len != 0) {
-		int auth_padding_len = 0;
+	if(!rpc_auth_pipe(cli, rdata, fragment_start, rhdr.frag_len,
+			  rhdr.auth_len, rhdr.pkt_type, &auth_padding_len)) {
+		prs_mem_free(rdata);
+		return False;
+	}
 
-		if(!rpc_auth_pipe(cli, rdata, fragment_start, rhdr.frag_len,
-					rhdr.auth_len, &auth_padding_len))
-			return False;
+	if (rhdr.auth_len != 0) {
 		/*
 		 * Drop the auth footers from the current offset.
 		 * We need this if there are more fragments.
@@ -543,7 +550,7 @@
 		prs_struct hps;
 		uint8 eclass;
 		uint32 ecode;
-
+		
 		/*
 		 * First read the header of the next PDU.
 		 */
@@ -596,8 +603,10 @@
 		 * Now read the rest of the PDU.
 		 */
 
-		if (!rpc_read(cli, rdata, len, &current_offset))
+		if (!rpc_read(cli, rdata, len, &current_offset)) {
+			prs_mem_free(rdata);
 			return False;
+		}
 
 		fragment_start = current_offset - len - RPC_HEADER_LEN - RPC_HDR_RESP_LEN;
 
@@ -605,12 +614,15 @@
 		 * Verify any authentication footer.
 		 */
 
+		
+		if(!rpc_auth_pipe(cli, rdata, fragment_start, rhdr.frag_len,
+				  rhdr.auth_len, rhdr.pkt_type, &auth_padding_len)) {
+			prs_mem_free(rdata);
+			return False;
+		}
+		
 		if (rhdr.auth_len != 0 ) {
-			int auth_padding_len = 0;
-
-			if(!rpc_auth_pipe(cli, rdata, fragment_start, rhdr.frag_len,
-						rhdr.auth_len, &auth_padding_len))
-				return False;
+			
 			/*
 			 * Drop the auth footers from the current offset.
 			 * The auth footers consist of the auth_data and the
@@ -633,70 +645,72 @@
 
  ********************************************************************/
 
-static BOOL create_rpc_bind_req(prs_struct *rpc_out, BOOL do_auth, BOOL do_netsec, uint32 rpc_call_id,
-                                RPC_IFACE *abstract, RPC_IFACE *transfer,
-                                const char *my_name, const char *domain, uint32 neg_flags)
+static NTSTATUS create_rpc_bind_req(struct cli_state *cli, prs_struct *rpc_out, 
+				    uint32 rpc_call_id,
+				    RPC_IFACE *abstract, RPC_IFACE *transfer,
+				    const char *my_name, const char *domain)
 {
 	RPC_HDR hdr;
 	RPC_HDR_RB hdr_rb;
-	char buffer[4096];
-	prs_struct auth_info;
+	RPC_HDR_AUTH hdr_auth;
 	int auth_len = 0;
+	int auth_type, auth_level;
+	size_t saved_hdr_offset;
 
-	prs_init(&auth_info, 0, prs_get_mem_context(rpc_out), MARSHALL);
-
-	if (do_auth) {
-		RPC_HDR_AUTH hdr_auth;
-		RPC_AUTH_VERIFIER auth_verifier;
-		RPC_AUTH_NTLMSSP_NEG ntlmssp_neg;
+	prs_struct auth_info;
+	prs_init(&auth_info, RPC_HDR_AUTH_LEN, /* we will need at least this much */
+		prs_get_mem_context(rpc_out), MARSHALL);
 
+	if (cli->pipe_auth_flags) {
+		get_auth_type_level(cli->pipe_auth_flags, &auth_type, &auth_level);
+		
 		/*
 		 * Create the auth structs we will marshall.
 		 */
-
-		init_rpc_hdr_auth(&hdr_auth, NTLMSSP_AUTH_TYPE, NTLMSSP_AUTH_LEVEL, 0x00, 1);
-		init_rpc_auth_verifier(&auth_verifier, "NTLMSSP", NTLMSSP_NEGOTIATE);
-		init_rpc_auth_ntlmssp_neg(&ntlmssp_neg, neg_flags, my_name, domain);
-
-		/*
-		 * Use the 4k buffer to store the auth info.
-		 */
-
-		prs_give_memory( &auth_info, buffer, sizeof(buffer), False);
-
+		
+		init_rpc_hdr_auth(&hdr_auth, auth_type, auth_level, 0x00, 1);
+		
 		/*
 		 * Now marshall the data into the temporary parse_struct.
 		 */
-
+		
 		if(!smb_io_rpc_hdr_auth("hdr_auth", &hdr_auth, &auth_info, 0)) {
 			DEBUG(0,("create_rpc_bind_req: failed to marshall RPC_HDR_AUTH.\n"));
-			return False;
-		}
-
-		if(!smb_io_rpc_auth_verifier("auth_verifier", &auth_verifier, &auth_info, 0)) {
-			DEBUG(0,("create_rpc_bind_req: failed to marshall RPC_AUTH_VERIFIER.\n"));
-			return False;
+			prs_mem_free(&auth_info);
+			return NT_STATUS_NO_MEMORY;
 		}
+		saved_hdr_offset = prs_offset(&auth_info);
+	}
+	
+	if (cli->pipe_auth_flags & AUTH_PIPE_NTLMSSP) {
 
-		if(!smb_io_rpc_auth_ntlmssp_neg("ntlmssp_neg", &ntlmssp_neg, &auth_info, 0)) {
-			DEBUG(0,("create_rpc_bind_req: failed to marshall RPC_AUTH_NTLMSSP_NEG.\n"));
-			return False;
+		NTSTATUS nt_status;
+		DATA_BLOB null_blob = data_blob(NULL, 0);
+		DATA_BLOB request;
+
+		DEBUG(5, ("Processing NTLMSSP Negotiate\n"));
+		nt_status = ntlmssp_client_update(cli->ntlmssp_pipe_state,
+						  null_blob,
+						  &request);
+
+		if (!NT_STATUS_EQUAL(nt_status, 
+				     NT_STATUS_MORE_PROCESSING_REQUIRED)) {
+			prs_mem_free(&auth_info);
+			return nt_status;
 		}
 
 		/* Auth len in the rpc header doesn't include auth_header. */
-		auth_len = prs_offset(&auth_info) - RPC_HDR_AUTH_LEN;
-	}
+		auth_len = request.length;
+		prs_copy_data_in(&auth_info, request.data, request.length);
 
-	if (do_netsec) {
-		RPC_HDR_AUTH hdr_auth;
-		RPC_AUTH_NETSEC_NEG netsec_neg;
+		DEBUG(5, ("NTLMSSP Negotiate:\n"));
+		dump_data(5, request.data, request.length);
 
-		/*
-		 * Create the auth structs we will marshall.
-		 */
+		data_blob_free(&request);
 
-		init_rpc_hdr_auth(&hdr_auth, NETSEC_AUTH_TYPE, NETSEC_AUTH_LEVEL,
-				  0x00, 1);
+	} 
+	else if (cli->pipe_auth_flags & AUTH_PIPE_NETSEC) {
+		RPC_AUTH_NETSEC_NEG netsec_neg;
 
 		/* Use lp_workgroup() if domain not specified */
 
@@ -706,30 +720,19 @@
 		init_rpc_auth_netsec_neg(&netsec_neg, domain, my_name);
 
 		/*
-		 * Use the 4k buffer to store the auth info.
-		 */
-
-		prs_give_memory( &auth_info, buffer, sizeof(buffer), False);
-
-		/*
 		 * Now marshall the data into the temporary parse_struct.
 		 */
 
-		if(!smb_io_rpc_hdr_auth("hdr_auth", &hdr_auth, &auth_info, 0)) {
-			DEBUG(0,("Failed to marshall RPC_HDR_AUTH.\n"));
-			return False;
-		}
-
 		if(!smb_io_rpc_auth_netsec_neg("netsec_neg",
 					       &netsec_neg, &auth_info, 0)) {
 			DEBUG(0,("Failed to marshall RPC_AUTH_NETSEC_NEG.\n"));
-			return False;
+			prs_mem_free(&auth_info);
+			return NT_STATUS_NO_MEMORY;
 		}
 
 		/* Auth len in the rpc header doesn't include auth_header. */
-		auth_len = prs_offset(&auth_info) - RPC_HDR_AUTH_LEN;
+		auth_len = prs_offset(&auth_info) - saved_hdr_offset;
 	}
-
 	/* create the request RPC_HDR */
 	init_rpc_hdr(&hdr, RPC_BIND, 0x3, rpc_call_id, 
 		RPC_HEADER_LEN + RPC_HDR_RB_LEN + prs_offset(&auth_info),
@@ -737,7 +740,8 @@
 
 	if(!smb_io_rpc_hdr("hdr"   , &hdr, rpc_out, 0)) {
 		DEBUG(0,("create_rpc_bind_req: failed to marshall RPC_HDR.\n"));
-		return False;
+		prs_mem_free(&auth_info);
+		return NT_STATUS_NO_MEMORY;
 	}
 
 	/* create the bind request RPC_HDR_RB */
@@ -747,21 +751,22 @@
 	/* Marshall the bind request data */
 	if(!smb_io_rpc_hdr_rb("", &hdr_rb, rpc_out, 0)) {
 		DEBUG(0,("create_rpc_bind_req: failed to marshall RPC_HDR_RB.\n"));
-		return False;
+		prs_mem_free(&auth_info);
+		return NT_STATUS_NO_MEMORY;
 	}
 
 	/*
 	 * Grow the outgoing buffer to store any auth info.
 	 */
 
-	if(hdr.auth_len != 0) {
+	if(auth_len != 0) {
 		if(!prs_append_prs_data( rpc_out, &auth_info)) {
 			DEBUG(0,("create_rpc_bind_req: failed to grow parse struct to add auth.\n"));
-			return False;
+			prs_mem_free(&auth_info);
+			return NT_STATUS_NO_MEMORY;
 		}
 	}
-
-	return True;
+	return NT_STATUS_OK;
 }
 
 /*******************************************************************
@@ -771,90 +776,71 @@
  the authentication handshake.
  ********************************************************************/
 
-static BOOL create_rpc_bind_resp(struct pwd_info *pwd,
-				const char *domain, const char *user_name, const char *my_name,
-				uint32 ntlmssp_cli_flgs,
-				uint32 rpc_call_id,
-				prs_struct *rpc_out)
+static NTSTATUS create_rpc_bind_resp(struct cli_state *cli,
+				 uint32 rpc_call_id,
+				 prs_struct *rpc_out)
 {
-	unsigned char lm_owf[24];
-	unsigned char nt_owf[24];
+	NTSTATUS nt_status;
 	RPC_HDR hdr;
 	RPC_HDR_AUTHA hdr_autha;
-	RPC_AUTH_VERIFIER auth_verifier;
-	RPC_AUTH_NTLMSSP_RESP ntlmssp_resp;
-	char buffer[4096];
-	prs_struct auth_info;
-
-	/*
-	 * Marshall the variable length data into a temporary parse
-	 * struct, pointing into a 4k local buffer.
-	 */
-	prs_init(&auth_info, 0, prs_get_mem_context(rpc_out), MARSHALL);
-
-	/*
-	 * Use the 4k buffer to store the auth info.
-	 */
-
-	prs_give_memory( &auth_info, buffer, sizeof(buffer), False);
-
-	/*
-	 * Create the variable length auth_data.
-	 */
-
- 	init_rpc_auth_verifier(&auth_verifier, "NTLMSSP", NTLMSSP_AUTH);
-
-	pwd_get_lm_nt_owf(pwd, lm_owf, nt_owf);
-			
-	init_rpc_auth_ntlmssp_resp(&ntlmssp_resp,
-			         lm_owf, nt_owf,
-			         domain, user_name, my_name,
-			         ntlmssp_cli_flgs);
-
-	/*
-	 * Marshall the variable length auth_data into a temp parse_struct.
-	 */
-
-	if(!smb_io_rpc_auth_verifier("auth_verifier", &auth_verifier, &auth_info, 0)) {
-		DEBUG(0,("create_rpc_bind_resp: failed to marshall RPC_AUTH_VERIFIER.\n"));
-		return False;
-	}
-
-	if(!smb_io_rpc_auth_ntlmssp_resp("ntlmssp_resp", &ntlmssp_resp, &auth_info, 0)) {
-		DEBUG(0,("create_rpc_bind_resp: failed to marshall RPC_AUTH_NTLMSSP_RESP.\n"));
-		return False;
+	DATA_BLOB ntlmssp_null_response = data_blob(NULL, 0);
+	DATA_BLOB ntlmssp_reply;
+	int auth_type, auth_level;
+
+	/* The response is picked up from the internal cache,
+	   where it was placed by the rpc_auth_pipe() code */
+	nt_status = ntlmssp_client_update(cli->ntlmssp_pipe_state,
+					  ntlmssp_null_response,
+					  &ntlmssp_reply);
+	
+	if (!NT_STATUS_EQUAL(nt_status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
+		return nt_status;
 	}
 
 	/* Create the request RPC_HDR */
 	init_rpc_hdr(&hdr, RPC_BINDRESP, 0x0, rpc_call_id,
-			RPC_HEADER_LEN + RPC_HDR_AUTHA_LEN + prs_offset(&auth_info),
-			prs_offset(&auth_info) );
-
+		     RPC_HEADER_LEN + RPC_HDR_AUTHA_LEN + ntlmssp_reply.length,
+		     ntlmssp_reply.length );
+	
 	/* Marshall it. */
 	if(!smb_io_rpc_hdr("hdr", &hdr, rpc_out, 0)) {
 		DEBUG(0,("create_rpc_bind_resp: failed to marshall RPC_HDR.\n"));
-		return False;
+		data_blob_free(&ntlmssp_reply);
+		return NT_STATUS_NO_MEMORY;
 	}
 
+	get_auth_type_level(cli->pipe_auth_flags, &auth_type, &auth_level);
+	
 	/* Create the request RPC_HDR_AUTHA */
 	init_rpc_hdr_autha(&hdr_autha, MAX_PDU_FRAG_LEN, MAX_PDU_FRAG_LEN,
-			NTLMSSP_AUTH_TYPE, NTLMSSP_AUTH_LEVEL, 0x00);
+			   auth_type, auth_level, 0x00);
 
 	if(!smb_io_rpc_hdr_autha("hdr_autha", &hdr_autha, rpc_out, 0)) {
 		DEBUG(0,("create_rpc_bind_resp: failed to marshall RPC_HDR_AUTHA.\n"));
-		return False;
+		data_blob_free(&ntlmssp_reply);
+		return NT_STATUS_NO_MEMORY;
 	}
 
 	/*
 	 * Append the auth data to the outgoing buffer.
 	 */
 
-	if(!prs_append_prs_data(rpc_out, &auth_info)) {
+	if(!prs_copy_data_in(rpc_out, ntlmssp_reply.data, ntlmssp_reply.length)) {
 		DEBUG(0,("create_rpc_bind_req: failed to grow parse struct to add auth.\n"));
-		return False;
+		data_blob_free(&ntlmssp_reply);
+		return NT_STATUS_NO_MEMORY;
 	}
 
-	return True;
+	if (cli->pipe_auth_flags & AUTH_PIPE_SIGN) {
+		nt_status = ntlmssp_client_sign_init(cli->ntlmssp_pipe_state);
+		
+		if (!NT_STATUS_IS_OK(nt_status)) {
+			return nt_status;
+		}
+	}
+
+	data_blob_free(&ntlmssp_reply);
+	return NT_STATUS_OK;
 }
 
 
@@ -905,34 +891,17 @@
 }
 
 /*******************************************************************
- Puts an NTLMSSP auth header into an rpc request.
- ********************************************************************/
-
-static BOOL create_ntlmssp_auth_hdr(prs_struct *outgoing_packet, BOOL auth_verify)
-{
-	RPC_HDR_AUTH hdr_auth;
-
-	init_rpc_hdr_auth(&hdr_auth, NTLMSSP_AUTH_TYPE,
-			  NTLMSSP_AUTH_LEVEL, 0x08, 
-			  (auth_verify ? 1 : 0));
-	if(!smb_io_rpc_hdr_auth("hdr_auth", &hdr_auth, 
-				outgoing_packet, 0)) {
-		DEBUG(0,("create_auth_hdr:Failed to marshal RPC_HDR_AUTH.\n"));
-		return False;
-	}
-	return True;
-}
-
-/*******************************************************************
- Puts a NETLOGON schannel auth header into an rpc request.
+ Puts an auth header into an rpc request.
  ********************************************************************/
 
-static BOOL create_netsec_auth_hdr(prs_struct *outgoing_packet, int padding)
+static BOOL create_auth_hdr(prs_struct *outgoing_packet, 
+			    int auth_type, 
+			    int auth_level, int padding)
 {
 	RPC_HDR_AUTH hdr_auth;
 
-	init_rpc_hdr_auth(&hdr_auth, NETSEC_AUTH_TYPE,
-			  NETSEC_AUTH_LEVEL, padding, 1);
+	init_rpc_hdr_auth(&hdr_auth, auth_type, auth_level,
+			  padding, 1);
 	if(!smb_io_rpc_hdr_auth("hdr_auth", &hdr_auth, 
 				outgoing_packet, 0)) {
 		DEBUG(0,("create_auth_hdr:Failed to marshal RPC_HDR_AUTH.\n"));
@@ -941,30 +910,6 @@
 	return True;
 }
 
-/*******************************************************************
- Puts auth data into an rpc request.
- ********************************************************************/
-
-static BOOL create_auth_data(struct cli_state *cli, uint32 crc32, 
-			     prs_struct *outgoing_packet)
-{
-	char *pdata_out = prs_data_p(outgoing_packet);
-	RPC_AUTH_NTLMSSP_CHK chk;
-	uint32 current_offset = prs_offset(outgoing_packet);
-
-	init_rpc_auth_ntlmssp_chk(&chk, NTLMSSP_SIGN_VERSION, 
-				  crc32, cli->ntlmssp_seq_num++);
-	if(!smb_io_rpc_auth_ntlmssp_chk("auth_sign", &chk, 
-					outgoing_packet, 0)) {
-		DEBUG(0,("create_auth_data: Failed to marshal RPC_AUTH_NTLMSSP_CHK.\n"));
-		return False;
-	}
-	NTLMSSPcalc_ap(cli, (unsigned char*)
-		       &pdata_out[current_offset+4], 
-		       RPC_AUTH_NTLMSSP_CHK_LEN - 4);
-	return True;
-}
-
 /**
  * Send a request on an RPC pipe and get a response.
  *
@@ -975,43 +920,60 @@
 BOOL rpc_api_pipe_req(struct cli_state *cli, uint8 op_num,
                       prs_struct *data, prs_struct *rdata)
 {
-	uint32 auth_len, max_data, data_left, data_sent;
+	uint32 auth_len, real_auth_len, auth_hdr_len, max_data, data_left, data_sent;
+	NTSTATUS nt_status;
 	BOOL ret = False;
-	BOOL auth_verify, auth_seal, auth_schannel;
 	uint32 callid = 0;
 	fstring dump_name;
 
-	auth_verify = ((cli->ntlmssp_srv_flgs & NTLMSSP_NEGOTIATE_SIGN) != 0);
-	auth_seal   = ((cli->ntlmssp_srv_flgs & NTLMSSP_NEGOTIATE_SEAL) != 0);
-	auth_schannel = (cli->saved_netlogon_pipe_fnum != 0);
-
 	auth_len = 0;
+	real_auth_len = 0;
+	auth_hdr_len = 0;
 
-	if (auth_verify)
-		auth_len = RPC_AUTH_NTLMSSP_CHK_LEN;
-
-	if (auth_schannel)
-		auth_len = RPC_AUTH_NETSEC_CHK_LEN;
+	if (cli->pipe_auth_flags & AUTH_PIPE_SIGN) {	
+		if (cli->pipe_auth_flags & AUTH_PIPE_NTLMSSP) {	
+			auth_len = RPC_AUTH_NTLMSSP_CHK_LEN;
+		}
+		if (cli->pipe_auth_flags & AUTH_PIPE_NETSEC) {	
+			auth_len = RPC_AUTH_NETSEC_CHK_LEN;
+		}
+		auth_hdr_len = RPC_HDR_AUTH_LEN;
+	}
 
 	/*
 	 * calc how much actual data we can send in a PDU fragment
 	 */
 	max_data = cli->max_xmit_frag - RPC_HEADER_LEN - RPC_HDR_REQ_LEN -
-		(auth_verify ? RPC_HDR_AUTH_LEN : 0) - auth_len - 8;
-
+		auth_hdr_len - auth_len - 8;
+	
 	for (data_left = prs_offset(data), data_sent = 0; data_left > 0;) {
 		prs_struct outgoing_packet;
+		prs_struct sec_blob;
 		uint32 data_len, send_size;
 		uint8 flags = 0;
-		uint32 crc32 = 0;
 		uint32 auth_padding = 0;
 		RPC_AUTH_NETSEC_CHK verf;
+		DATA_BLOB sign_blob;
 
 		/*
 		 * how much will we send this time
 		 */
 		send_size = MIN(data_left, max_data);
 
+		if (!prs_init(&sec_blob, send_size, /* will need at least this much */
+			      cli->mem_ctx, MARSHALL)) {
+			DEBUG(0,("Could not malloc %u bytes",
+				 send_size+auth_padding));
+			return False;
+		}
+
+		if(!prs_append_some_prs_data(&sec_blob, data, 
+					     data_sent, send_size)) {
+			DEBUG(0,("Failed to append data to netsec blob\n"));
+			prs_mem_free(&sec_blob);
+			return False;
+		}
+
 		/*
 		 * NT expects the data that is sealed to be 8-byte
 		 * aligned. The padding must be encrypted as well and
@@ -1020,14 +982,106 @@
 		 * be stored in the auth header.
 		 */
 
-		if (auth_schannel) {
-			if (send_size % 8)
-				auth_padding = 8 - (send_size % 8);
+		if (cli->pipe_auth_flags) {
+			size_t data_and_padding_size;
+			prs_align_uint64(&sec_blob);
+			int auth_type = 0;
+			int auth_level = 0;
+
+			if (cli->pipe_auth_flags & AUTH_PIPE_SEAL) {
+				auth_level = RPC_PIPE_AUTH_SEAL_LEVEL;
+			} else if (cli->pipe_auth_flags & AUTH_PIPE_SIGN) {
+				auth_level = RPC_PIPE_AUTH_SIGN_LEVEL;
+			}
+
+			if (cli->pipe_auth_flags & AUTH_PIPE_NETSEC) {
+				auth_type = NETSEC_AUTH_TYPE;
+			} else if (cli->pipe_auth_flags & AUTH_PIPE_NTLMSSP) {
+				auth_type = NTLMSSP_AUTH_TYPE;
+			}
+
+			data_and_padding_size = prs_offset(&sec_blob);
+			auth_padding = data_and_padding_size - send_size;
+
+			/* insert the auth header */
+			
+			if(!create_auth_hdr(&sec_blob, auth_type, auth_level, auth_padding)) {
+				prs_mem_free(&sec_blob);
+				return False;
+			}
+			
+			/* create an NTLMSSP signature */
+			if (cli->pipe_auth_flags & AUTH_PIPE_NTLMSSP) {
+				/*
+				 * Seal the outgoing data if requested.
+				 */
+				if (cli->pipe_auth_flags & AUTH_PIPE_SEAL) {
+					
+					nt_status = ntlmssp_client_seal_packet(cli->ntlmssp_pipe_state,
+									       (unsigned char*)prs_data_p(&sec_blob),
+									       data_and_padding_size,
+									       &sign_blob);
+					if (!NT_STATUS_IS_OK(nt_status)) {
+						prs_mem_free(&sec_blob);
+						return False;
+					}
+				} 
+				else if (cli->pipe_auth_flags & AUTH_PIPE_SIGN) {
+					
+					nt_status = ntlmssp_client_sign_packet(cli->ntlmssp_pipe_state,
+									       (unsigned char*)prs_data_p(&sec_blob),
+									       data_and_padding_size, &sign_blob);
+					if (!NT_STATUS_IS_OK(nt_status)) {
+						prs_mem_free(&sec_blob);
+						return False;
+					}
+				}
+				
+
+				/* write auth footer onto the packet */
+				real_auth_len = sign_blob.length;
+				
+				prs_copy_data_in(&sec_blob, sign_blob.data, sign_blob.length);
+				data_blob_free(&sign_blob);
+
+			}
+			else if (cli->pipe_auth_flags & AUTH_PIPE_NETSEC) {	
+				static const uchar netsec_sig[8] = NETSEC_SIGNATURE;
+				static const uchar nullbytes[8] = { 0,0,0,0,0,0,0,0 };
+				uchar sign[8];
+				size_t parse_offset_marker;
+				if ((cli->auth_info.seq_num & 1) != 0) {
+					DEBUG(0,("SCHANNEL ERROR: seq_num must be even in client (seq_num=%d)\n",
+						 cli->auth_info.seq_num));
+				}
+				
+				DEBUG(10,("SCHANNEL seq_num=%d\n", cli->auth_info.seq_num));
+				
+				RSIVAL(sign, 0, cli->auth_info.seq_num);
+				SIVAL(sign, 4, 0x80);
+				
+				init_rpc_auth_netsec_chk(&verf, netsec_sig, nullbytes,
+							 sign, nullbytes);
+				
+				netsec_encode(&cli->auth_info, &verf,
+					      prs_data_p(&sec_blob),
+					      data_and_padding_size);
+
+				cli->auth_info.seq_num++;
+
+				/* write auth footer onto the packet */
+				
+				parse_offset_marker = prs_offset(&sec_blob);
+				if (!smb_io_rpc_auth_netsec_chk("", &verf,
+								&sec_blob, 0)) {
+					prs_mem_free(&sec_blob);
+					return False;
+				}
+				real_auth_len = prs_offset(&sec_blob) - parse_offset_marker;
+			}
 		}
 
-		data_len = RPC_HEADER_LEN + RPC_HDR_REQ_LEN + send_size +
-			((auth_verify|auth_schannel) ? RPC_HDR_AUTH_LEN : 0) +
-			auth_len + auth_padding;
+		data_len = RPC_HEADER_LEN + RPC_HDR_REQ_LEN + prs_offset(&sec_blob);
 
 		/*
 		 * Malloc parse struct to hold it (and enough for alignments).
@@ -1047,128 +1101,23 @@
 		 * Write out the RPC header and the request header.
 		 */
 		if(!(callid = create_rpc_request(&outgoing_packet, op_num, 
-						 data_len, auth_len, flags, 
+						 data_len, real_auth_len, flags, 
 						 callid, data_left))) {
 			DEBUG(0,("rpc_api_pipe_req: Failed to create RPC request.\n"));
 			prs_mem_free(&outgoing_packet);
+			prs_mem_free(&sec_blob);
 			return False;
 		}
 
-		/*
-		 * Seal the outgoing data if requested.
-		 */
-		if (auth_seal) {
-			crc32 = crc32_calc_buffer(prs_data_p(data) + data_sent,
-						  send_size);
-			NTLMSSPcalc_ap(cli, (unsigned char*)prs_data_p(data) +
-				       data_sent, send_size);
-		}
-
-		/*
-		 * Now copy the data into the outgoing packet.
-		 */
-
-		if (auth_schannel) {
-			static const uchar netsec_sig[8] = NETSEC_SIGNATURE;
-			static const uchar nullbytes[8] = { 0,0,0,0,0,0,0,0 };
-			uchar sign[8];
-			prs_struct netsec_blob;
-
-			if ((cli->auth_info.seq_num & 1) != 0) {
-				DEBUG(0,("SCHANNEL ERROR: seq_num must be even in client (seq_num=%d)\n",
-					cli->auth_info.seq_num));
-			}
-
-			DEBUG(10,("SCHANNEL seq_num=%d\n", cli->auth_info.seq_num));
-
-			RSIVAL(sign, 0, cli->auth_info.seq_num);
-			SIVAL(sign, 4, 0x80);
-
-			if (!prs_init(&netsec_blob, send_size+auth_padding,
-				      cli->mem_ctx, MARSHALL)) {
-				DEBUG(0,("Could not malloc %u bytes",
-					 send_size+auth_padding));
-				prs_mem_free(&outgoing_packet);
-				return False;
-			}
-
-			if(!prs_append_some_prs_data(&netsec_blob, data, 
-						     data_sent, send_size)) {
-				DEBUG(0,("Failed to append data to netsec blob\n"));
-				prs_mem_free(&outgoing_packet);
-				return False;
-			}
-
-			netsec_blob.align = 8;
-
-			if (!prs_align(&netsec_blob)) {
-				DEBUG(0,("Could not align netsec blob\n"));
-				prs_mem_free(&outgoing_packet);
-				return False;
-			}
-
-			init_rpc_auth_netsec_chk(&verf, netsec_sig, nullbytes,
-						 sign, nullbytes);
-
-			netsec_encode(&cli->auth_info, &verf,
-				      prs_data_p(&netsec_blob),
-				      prs_data_size(&netsec_blob));
-
-			prs_append_prs_data(&outgoing_packet, &netsec_blob);
-			prs_mem_free(&netsec_blob);
-
-			cli->auth_info.seq_num++;
-
-		} else {
-			if(!prs_append_some_prs_data(&outgoing_packet, data, 
-						     data_sent, send_size)) {
-				DEBUG(0,("rpc_api_pipe_req: Failed to append "
-					 "data to outgoing packet.\n"));
-				prs_mem_free(&outgoing_packet);
-				return False;
-			}
-		}
-
-		/*
-		 * Add a trailing auth_verifier if needed.
-		 */
-		if (auth_seal || auth_verify) {
-			if(!create_ntlmssp_auth_hdr(&outgoing_packet, auth_verify)) {
-				prs_mem_free(&outgoing_packet);
-				return False;
-			}
-		}
-
-		/*
-		 * Finally the auth data itself.
-		 */
-		if (auth_verify) {
-			if (!create_auth_data(cli, crc32, &outgoing_packet)) {
-				prs_mem_free(&outgoing_packet);
-				return False;
-			}
-		}
-
-		if (auth_schannel) {
-
-			if (!create_netsec_auth_hdr(&outgoing_packet,
-						    auth_padding)) {
-				prs_mem_free(&outgoing_packet);
-				return False;
-			}
-
-			if (!smb_io_rpc_auth_netsec_chk("", &verf,
-							&outgoing_packet, 0)) {
-				prs_mem_free(&outgoing_packet);
-				return False;
-			}
-		}
+		prs_append_prs_data(&outgoing_packet, &sec_blob);
+		prs_mem_free(&sec_blob);
 
 		DEBUG(100,("data_len: %x data_calc_len: %x\n", data_len, 
 			   prs_offset(&outgoing_packet)));
 		
 		if (flags & RPC_FLG_LAST)
-			ret = rpc_api_pipe(cli, &outgoing_packet, rdata);
+			ret = rpc_api_pipe(cli, &outgoing_packet, 
+					   rdata, RPC_RESPONSE);
 		else {
 			cli_write(cli, cli->nt_pipe_fnum, 0x0008,
 				   prs_data_p(&outgoing_packet),
@@ -1352,84 +1301,23 @@
 
 static BOOL rpc_send_auth_reply(struct cli_state *cli, prs_struct *rdata, uint32 rpc_call_id)
 {
-	RPC_HDR_AUTH rhdr_auth;
-	RPC_AUTH_VERIFIER rhdr_verf;
-	RPC_AUTH_NTLMSSP_CHAL rhdr_chal;
-	char buffer[MAX_PDU_FRAG_LEN];
 	prs_struct rpc_out;
 	ssize_t ret;
 
-	unsigned char p24[24];
-	unsigned char lm_owf[24];
-	unsigned char lm_hash[16];
-
-	if(!smb_io_rpc_hdr_auth("", &rhdr_auth, rdata, 0)) {
-		DEBUG(0,("rpc_send_auth_reply: Failed to unmarshall RPC_HDR_AUTH.\n"));
-		return False;
-	}
-	if(!smb_io_rpc_auth_verifier("", &rhdr_verf, rdata, 0)) {
-		DEBUG(0,("rpc_send_auth_reply: Failed to unmarshall RPC_AUTH_VERIFIER.\n"));
-		return False;
-	}
-	if(!smb_io_rpc_auth_ntlmssp_chal("", &rhdr_chal, rdata, 0)) {
-		DEBUG(0,("rpc_send_auth_reply: Failed to unmarshall RPC_AUTH_NTLMSSP_CHAL.\n"));
-		return False;
-	}
-
-	cli->ntlmssp_cli_flgs = rhdr_chal.neg_flags;
-
-	pwd_make_lm_nt_owf(&cli->pwd, rhdr_chal.challenge);
-
-	prs_init(&rpc_out, 0, cli->mem_ctx, MARSHALL);
-
-	prs_give_memory( &rpc_out, buffer, sizeof(buffer), False);
+	prs_init(&rpc_out, RPC_HEADER_LEN + RPC_HDR_AUTHA_LEN, /* need at least this much */ 
+		 cli->mem_ctx, MARSHALL);
 
-	create_rpc_bind_resp(&cli->pwd, cli->domain,
-	                     cli->user_name, global_myname(), 
-	                     cli->ntlmssp_cli_flgs, rpc_call_id,
+	create_rpc_bind_resp(cli, rpc_call_id,
 	                     &rpc_out);
-			                    
-	pwd_get_lm_nt_owf(&cli->pwd, lm_owf, NULL);
-	pwd_get_lm_nt_16(&cli->pwd, lm_hash, NULL);
-
-	NTLMSSPOWFencrypt(lm_hash, lm_owf, p24);
-
-	{
-		unsigned char j = 0;
-		int ind;
-		unsigned char k2[8];
-
-		memcpy(k2, p24, 5);
-		k2[5] = 0xe5;
-		k2[6] = 0x38;
-		k2[7] = 0xb0;
-
-		for (ind = 0; ind < 256; ind++)
-			cli->ntlmssp_hash[ind] = (unsigned char)ind;
-
-		for( ind = 0; ind < 256; ind++) {
-			unsigned char tc;
-
-			j += (cli->ntlmssp_hash[ind] + k2[ind%8]);
-
-			tc = cli->ntlmssp_hash[ind];
-			cli->ntlmssp_hash[ind] = cli->ntlmssp_hash[j];
-			cli->ntlmssp_hash[j] = tc;
-		}
-
-		cli->ntlmssp_hash[256] = 0;
-		cli->ntlmssp_hash[257] = 0;
-	}
-
-	memset((char *)lm_hash, '\0', sizeof(lm_hash));
 
 	if ((ret = cli_write(cli, cli->nt_pipe_fnum, 0x8, prs_data_p(&rpc_out), 
 			0, (size_t)prs_offset(&rpc_out))) != (ssize_t)prs_offset(&rpc_out)) {
 		DEBUG(0,("rpc_send_auth_reply: cli_write failed. Return was %d\n", (int)ret));
+		prs_mem_free(&rpc_out);
 		return False;
 	}
 
-	cli->ntlmssp_srv_flgs = rhdr_chal.neg_flags;
+	prs_mem_free(&rpc_out);
 	return True;
 }
 
@@ -1437,14 +1325,12 @@
  Do an rpc bind.
 ****************************************************************************/
 
-static BOOL rpc_pipe_bind(struct cli_state *cli, int pipe_idx, const char *my_name,
-			  BOOL do_netsec)
+static BOOL rpc_pipe_bind(struct cli_state *cli, int pipe_idx, const char *my_name)
 {
 	RPC_IFACE abstract;
 	RPC_IFACE transfer;
 	prs_struct rpc_out;
 	prs_struct rdata;
-	BOOL do_auth = (cli->ntlmssp_cli_flgs != 0);
 	uint32 rpc_call_id;
 	char buffer[MAX_PDU_FRAG_LEN];
 
@@ -1466,16 +1352,53 @@
 
 	rpc_call_id = get_rpc_call_id();
 
+	if (cli->pipe_auth_flags & AUTH_PIPE_NTLMSSP) {
+		NTSTATUS nt_status;
+		fstring password;
+
+		DEBUG(5, ("NTLMSSP authenticated pipe selected\n"));
+
+		nt_status = ntlmssp_client_start(&cli->ntlmssp_pipe_state);
+		
+		if (!NT_STATUS_IS_OK(nt_status))
+			return False;
+
+		nt_status = ntlmssp_set_username(cli->ntlmssp_pipe_state, 
+						 cli->user_name);
+		if (!NT_STATUS_IS_OK(nt_status))
+			return False;
+
+		nt_status = ntlmssp_set_domain(cli->ntlmssp_pipe_state, 
+					       cli->domain);	
+		if (!NT_STATUS_IS_OK(nt_status))
+			return False;
+
+		pwd_get_cleartext(&cli->pwd, password);
+		nt_status = ntlmssp_set_password(cli->ntlmssp_pipe_state, 
+						 password);
+		if (!NT_STATUS_IS_OK(nt_status))
+			return False;
+
+		if (cli->pipe_auth_flags & AUTH_PIPE_SIGN) {
+			cli->ntlmssp_pipe_state->neg_flags |= NTLMSSP_NEGOTIATE_SIGN;
+		}
+
+		if (cli->pipe_auth_flags & AUTH_PIPE_SEAL) {
+			cli->ntlmssp_pipe_state->neg_flags |= NTLMSSP_NEGOTIATE_SEAL;
+		}
+	}
+
+
 	/* Marshall the outgoing data. */
-	create_rpc_bind_req(&rpc_out, do_auth, do_netsec, rpc_call_id,
+	create_rpc_bind_req(cli, &rpc_out, rpc_call_id,
 	                    &abstract, &transfer,
-	                    global_myname(), cli->domain, cli->ntlmssp_cli_flgs);
+	                    global_myname(), cli->domain);
 
 	/* Initialize the incoming data struct. */
 	prs_init(&rdata, 0, cli->mem_ctx, UNMARSHALL);
 
 	/* send data on \PIPE\.  receive a response */
-	if (rpc_api_pipe(cli, &rpc_out, &rdata)) {
+	if (rpc_api_pipe(cli, &rpc_out, &rdata, RPC_BINDACK)) {
 		RPC_HDR_BA   hdr_ba;
 
 		DEBUG(5, ("rpc_pipe_bind: rpc_api_pipe returned OK.\n"));
@@ -1501,15 +1424,17 @@
 		 * handshake.
 		 */
 
-		if (do_auth && !rpc_send_auth_reply(cli, &rdata, rpc_call_id)) {
+		if ((cli->pipe_auth_flags & AUTH_PIPE_NTLMSSP) 
+		    && !rpc_send_auth_reply(cli, &rdata, rpc_call_id)) {
 			DEBUG(0,("rpc_pipe_bind: rpc_send_auth_reply failed.\n"));
 			prs_mem_free(&rdata);
 			return False;
 		}
+		prs_mem_free(&rdata);
+		return True;
 	}
 
-	prs_mem_free(&rdata);
-	return True;
+	return False;
 }
 
 /****************************************************************************
@@ -1557,7 +1482,7 @@
 
 	/******************* bind request on pipe *****************/
 
-	if (!rpc_pipe_bind(cli, pipe_idx, global_myname(), False)) {
+	if (!rpc_pipe_bind(cli, pipe_idx, global_myname())) {
 		DEBUG(2,("cli_nt_session_open: rpc bind to %s failed\n",
 			 get_pipe_name_from_index(pipe_idx)));
 		cli_close(cli, cli->nt_pipe_fnum);
@@ -1635,7 +1560,6 @@
 		/* The secure channel connection must be opened on the same 
                    session (TCP connection) as the one the challenge was
                    requested from. */
-
 		if ((fnum = cli_nt_create(cli, PIPE_NETLOGON_PLAIN,
 					  DESIRED_ACCESS_PIPE)) == -1) {
 			DEBUG(0,("cli_nt_create failed to %s machine %s. "
@@ -1666,8 +1590,11 @@
 			return NT_STATUS_UNSUCCESSFUL;
 		}
 	}
-
-	if (!rpc_pipe_bind(cli, PI_NETLOGON, global_myname(), True)) {
+	
+	/* doing schannel, not per-user auth */
+	cli->pipe_auth_flags = AUTH_PIPE_NETSEC | AUTH_PIPE_SEAL;
+	
+	if (!rpc_pipe_bind(cli, PI_NETLOGON, global_myname())) {
 		DEBUG(2,("rpc bind to %s failed\n", PIPE_NETLOGON));
 		cli_close(cli, cli->nt_pipe_fnum);
 		return NT_STATUS_UNSUCCESSFUL;
Index: rpc_parse/parse_prs.c
===================================================================
RCS file: /home/cvs/samba/source/rpc_parse/parse_prs.c,v
retrieving revision 1.75.2.12
diff -u -r1.75.2.12 parse_prs.c
--- rpc_parse/parse_prs.c	26 May 2003 06:55:24 -0000	1.75.2.12
+++ rpc_parse/parse_prs.c	13 Jul 2003 05:28:54 -0000
@@ -1378,17 +1378,6 @@
 	}
 }
 
-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
-}
-
 void netsec_encode(struct netsec_auth_struct *a,
 		   RPC_AUTH_NETSEC_CHK * verf, char *data, size_t data_len)
 {
Index: rpc_parse/parse_rpc.c
===================================================================
RCS file: /home/cvs/samba/source/rpc_parse/parse_rpc.c,v
retrieving revision 1.45.2.11
diff -u -r1.45.2.11 parse_rpc.c
--- rpc_parse/parse_rpc.c	22 Apr 2003 15:54:36 -0000	1.45.2.11
+++ rpc_parse/parse_rpc.c	13 Jul 2003 05:28:55 -0000
@@ -603,15 +603,6 @@
 }
 
 /*******************************************************************
- Checks an RPC_HDR_AUTH structure.
-********************************************************************/
-
-BOOL rpc_hdr_auth_chk(RPC_HDR_AUTH *rai)
-{
-	return (rai->auth_type == NTLMSSP_AUTH_TYPE && rai->auth_level == NTLMSSP_AUTH_LEVEL);
-}
-
-/*******************************************************************
  Inits an RPC_HDR_AUTH structure.
 ********************************************************************/
 
@@ -1088,9 +1079,10 @@
 	    chk->seq_num != seq_num)
 	{
 		DEBUG(5,("verify failed - crc %x ver %x seq %d\n",
-			crc32, NTLMSSP_SIGN_VERSION, seq_num));
+			 chk->crc32, chk->ver, chk->seq_num));
+			
 		DEBUG(5,("verify expect - crc %x ver %x seq %d\n",
-			chk->crc32, chk->ver, chk->seq_num));
+			crc32, NTLMSSP_SIGN_VERSION, seq_num));
 		return False;
 	}
 	return True;
Index: rpc_server/srv_pipe.c
===================================================================
RCS file: /home/cvs/samba/source/rpc_server/srv_pipe.c,v
retrieving revision 1.93.2.16
diff -u -r1.93.2.16 srv_pipe.c
--- rpc_server/srv_pipe.c	3 Jul 2003 14:36:42 -0000	1.93.2.16
+++ rpc_server/srv_pipe.c	13 Jul 2003 05:29:00 -0000
@@ -227,7 +227,7 @@
 		if (auth_seal || auth_verify) {
 			RPC_HDR_AUTH auth_info;
 
-			init_rpc_hdr_auth(&auth_info, NTLMSSP_AUTH_TYPE, NTLMSSP_AUTH_LEVEL, 
+			init_rpc_hdr_auth(&auth_info, NTLMSSP_AUTH_TYPE, RPC_PIPE_AUTH_SEAL_LEVEL, 
 					(auth_verify ? RPC_HDR_AUTH_LEN : 0), (auth_verify ? 1 : 0));
 			if(!smb_io_rpc_hdr_auth("hdr_auth", &auth_info, &outgoing_pdu, 0)) {
 				DEBUG(0,("create_next_pdu: failed to marshall RPC_HDR_AUTH.\n"));
@@ -267,7 +267,7 @@
 
 		data = prs_data_p(&outgoing_pdu) + data_pos;
 
-		init_rpc_hdr_auth(&auth_info, NETSEC_AUTH_TYPE, NETSEC_AUTH_LEVEL, 
+		init_rpc_hdr_auth(&auth_info, NETSEC_AUTH_TYPE, RPC_PIPE_AUTH_SEAL_LEVEL, 
 				  RPC_HDR_AUTH_LEN, 1);
 
 		if(!smb_io_rpc_hdr_auth("hdr_auth", &auth_info, &outgoing_pdu, 0)) {
@@ -458,6 +458,10 @@
 			p->ntlmssp_hash[256] = 0;
 			p->ntlmssp_hash[257] = 0;
 		}
+
+		dump_data_pw("NTLMSSP hash (v1)\n", p->ntlmssp_hash, 
+			     sizeof(p->ntlmssp_hash));
+
 /*		NTLMSSPhash(p->ntlmssp_hash, p24); */
 		p->ntlmssp_seq_num = 0;
 
@@ -546,7 +550,7 @@
 		return False;
 	}
 
-	if (autha_info.auth_type != NTLMSSP_AUTH_TYPE || autha_info.auth_level != NTLMSSP_AUTH_LEVEL) {
+	if (autha_info.auth_type != NTLMSSP_AUTH_TYPE || autha_info.auth_level != RPC_PIPE_AUTH_SEAL_LEVEL) {
 		DEBUG(0,("api_pipe_bind_auth_resp: incorrect auth type (%d) or level (%d).\n",
 			(int)autha_info.auth_type, (int)autha_info.auth_level ));
 		return False;
@@ -1070,7 +1074,7 @@
 
 		/*** Authentication info ***/
 
-		init_rpc_hdr_auth(&auth_info, NTLMSSP_AUTH_TYPE, NTLMSSP_AUTH_LEVEL, RPC_HDR_AUTH_LEN, 1);
+		init_rpc_hdr_auth(&auth_info, NTLMSSP_AUTH_TYPE, RPC_PIPE_AUTH_SEAL_LEVEL, RPC_HDR_AUTH_LEN, 1);
 		if(!smb_io_rpc_hdr_auth("", &auth_info, &out_auth, 0)) {
 			DEBUG(0,("api_pipe_bind_req: marshalling of RPC_HDR_AUTH failed.\n"));
 			goto err_exit;
@@ -1105,7 +1109,7 @@
                    re-used from the auth2 the client did before. */
 		p->dc = last_dcinfo;
 
-		init_rpc_hdr_auth(&auth_info, NETSEC_AUTH_TYPE, NETSEC_AUTH_LEVEL, RPC_HDR_AUTH_LEN, 1);
+		init_rpc_hdr_auth(&auth_info, NETSEC_AUTH_TYPE, RPC_PIPE_AUTH_SEAL_LEVEL, RPC_HDR_AUTH_LEN, 1);
 		if(!smb_io_rpc_hdr_auth("", &auth_info, &out_auth, 0)) {
 			DEBUG(0,("api_pipe_bind_req: marshalling of RPC_HDR_AUTH failed.\n"));
 			goto err_exit;
@@ -1226,7 +1230,14 @@
 		 * has already been consumed.
 		 */
 		char *data = prs_data_p(rpc_in) + RPC_HDR_REQ_LEN;
+		dump_data_pw("NTLMSSP hash (v1)\n", p->ntlmssp_hash, 
+			     sizeof(p->ntlmssp_hash));
+
+		dump_data_pw("Incoming RPC PDU (NTLMSSP sealed)\n", 
+			     data, data_len);
 		NTLMSSPcalc_p(p, (uchar*)data, data_len);
+		dump_data_pw("Incoming RPC PDU (NTLMSSP unsealed)\n", 
+			     data, data_len);
 		crc32 = crc32_calc_buffer(data, data_len);
 	}
 
@@ -1335,7 +1346,7 @@
 	}
 
 	if ((auth_info.auth_type != NETSEC_AUTH_TYPE) ||
-	    (auth_info.auth_level != NETSEC_AUTH_LEVEL)) {
+	    (auth_info.auth_level != RPC_PIPE_AUTH_SEAL_LEVEL)) {
 		DEBUG(0,("Invalid auth info %d or level %d on schannel\n",
 			 auth_info.auth_type, auth_info.auth_level));
 		return False;
Index: rpcclient/rpcclient.c
===================================================================
RCS file: /home/cvs/samba/source/rpcclient/rpcclient.c,v
retrieving revision 1.180.2.23
diff -u -r1.180.2.23 rpcclient.c
--- rpcclient/rpcclient.c	9 Jul 2003 03:32:07 -0000	1.180.2.23
+++ rpcclient/rpcclient.c	13 Jul 2003 05:29:00 -0000
@@ -319,6 +319,41 @@
 	return NT_STATUS_OK; /* NOTREACHED */
 }
 
+static NTSTATUS cmd_auth(struct cli_state *cli, TALLOC_CTX *mem_ctx,
+                         int argc, const char **argv)
+{
+	cli->pipe_auth_flags = AUTH_PIPE_NTLMSSP;
+
+	return NT_STATUS_OK; 
+}
+
+static NTSTATUS cmd_sign(struct cli_state *cli, TALLOC_CTX *mem_ctx,
+                         int argc, const char **argv)
+{
+	cli->pipe_auth_flags = AUTH_PIPE_NTLMSSP;
+	cli->pipe_auth_flags |= AUTH_PIPE_SIGN;
+
+	return NT_STATUS_OK; 
+}
+
+static NTSTATUS cmd_seal(struct cli_state *cli, TALLOC_CTX *mem_ctx,
+                         int argc, const char **argv)
+{
+	cli->pipe_auth_flags = AUTH_PIPE_NTLMSSP;
+	cli->pipe_auth_flags |= AUTH_PIPE_SIGN;
+	cli->pipe_auth_flags |= AUTH_PIPE_SEAL;
+
+	return NT_STATUS_OK; 
+}
+
+static NTSTATUS cmd_none(struct cli_state *cli, TALLOC_CTX *mem_ctx,
+                         int argc, const char **argv)
+{
+	cli->pipe_auth_flags = 0;
+
+	return NT_STATUS_OK; 
+}
+
 /* Built in rpcclient commands */
 
 static struct cmd_set rpcclient_commands[] = {
@@ -331,6 +366,9 @@
 	{ "list",	RPC_RTYPE_NTSTATUS, cmd_listcommands, NULL, -1,	"List available commands on <pipe>", "pipe" },
 	{ "exit", RPC_RTYPE_NTSTATUS, cmd_quit, NULL,   -1,	"Exit program", "" },
 	{ "quit", RPC_RTYPE_NTSTATUS, cmd_quit, NULL,	  -1,	"Exit program", "" },
+	{ "sign", RPC_RTYPE_NTSTATUS, cmd_sign, NULL,	  -1,	"Force RPC pipe connections to be signed", "" },
+	{ "seal", RPC_RTYPE_NTSTATUS, cmd_seal, NULL,	  -1,	"Force RPC pipe connections to be sealed", "" },
+	{ "none", RPC_RTYPE_NTSTATUS, cmd_none, NULL,	  -1,	"Force RPC pipe connections to have no special properties", "" },
 
 	{ NULL }
 };


More information about the samba-technical mailing list