[Patch] Support for LDAP with GSSAPI/NTLMSSP auth scheme decoding in wireshark

Matthieu Patou mat at matws.net
Mon Apr 27 06:44:19 GMT 2009


On 04/25/2009 05:48 PM, Matthieu Patou wrote:
> Hello Metze, and the samba team,
>
> I finally finished my patch to support NTLMSSP auth in LDAP.
> As metze proposed I add the option that read all the keytab that were 
> provided, and try all the encoded password inside it.
>
> It seems to work quite well, I tried with a few keytab generated for 
> pure "traditional" LDAP with kerberos auth and I've been able to 
> decode (well if the keytab contains the md4(password) of the user 
> trying to authenticate himself).
> I'm quite surprised that when "extracting" crypted password in a 
> keytab they are only stored by using md4(unicode(password))) even if 
> we ask keytab to use arc4_hmac (but I'm far from being well aware of 
> all in kerberos ...).
>
> Concerning protocols, I tested NTLM v1 and NTLM v2, for NTLM v1 I 
> tested mostly with extended security flags so for less secure (and 
> maybe not anymore really used ?) scheme (like pure lan manager auth or 
> simple nt auth) problems might still exist.
>
> It would be just great if you can provide me some feedback, in anycase 
> my goal is to submit it to wireshark devs soon.
>
> Matthieu
>
I attached an updated version that correct some other problems.

-------------- next part --------------
--- epan/dissectors/packet-ntlmssp.c	2009-02-08 19:13:59.000000000 +0300
+++ ../wireshark-1.1.3-SVN-27393/epan/dissectors/packet-ntlmssp.c	2009-04-26 23:57:04.579060397 +0400
@@ -27,7 +27,7 @@
 #ifdef HAVE_CONFIG_H
 # include "config.h"
 #endif
-
+#include <unistd.h>
 #include <string.h>
 #include <ctype.h>
 
@@ -37,14 +37,18 @@
 #include "packet-windows-common.h"
 #include "packet-smb-common.h"
 #include "packet-frame.h"
+#include <epan/asn1.h>
+#include "packet-kerberos.h"
 #include <epan/prefs.h>
 #include <epan/emem.h>
 #include <epan/tap.h>
 #include <epan/crypt/crypt-rc4.h>
 #include <epan/crypt/crypt-md4.h>
+#include <epan/crypt/crypt-md5.h>
 #include <epan/crypt/crypt-des.h>
 #include "packet-dcerpc.h"
 #include "packet-gssapi.h"
+#include <epan/crc32.h>
 
 #include "packet-ntlmssp.h"
 
@@ -56,6 +60,10 @@
 #define NTLMSSP_CHALLENGE 2
 #define NTLMSSP_AUTH      3
 #define NTLMSSP_UNKNOWN   4
+#define CLIENT_SIGN_TEXT "session key to client-to-server signing key magic constant"
+#define CLIENT_SEAL_TEXT "session key to client-to-server sealing key magic constant"
+#define SERVER_SIGN_TEXT "session key to server-to-client signing key magic constant"
+#define SERVER_SEAL_TEXT "session key to server-to-client sealing key magic constant"
 
 static const value_string ntlmssp_message_types[] = {
   { NTLMSSP_NEGOTIATE, "NTLMSSP_NEGOTIATE" },
@@ -65,6 +73,13 @@
   { 0, NULL }
 };
 
+typedef struct _md4_pass {
+  guint32 md4[16];
+} md4_pass;
+
+static unsigned char zeros[24] = "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0";
+static GHashTable* hash_packet = NULL;
+
 /*
  * NTLMSSP negotiation flags
  * Taken from Samba
@@ -108,7 +123,7 @@
 #define NTLMSSP_TARGET_TYPE_DOMAIN         0x00010000
 #define NTLMSSP_TARGET_TYPE_SERVER         0x00020000
 #define NTLMSSP_TARGET_TYPE_SHARE          0x00040000
-#define NTLMSSP_NEGOTIATE_NTLM2            0x00080000
+#define NTLMSSP_NEGOTIATE_EXTENDED_SECURITY 0x00080000
 #define NTLMSSP_NEGOTIATE_IDENTIFY         0x00100000
 #define NTLMSSP_NEGOTIATE_00200000         0x00200000
 #define NTLMSSP_REQUEST_NON_NT_SESSION     0x00400000
@@ -167,7 +182,8 @@
 static int hf_ntlmssp_negotiate_domain_maxlen = -1;
 static int hf_ntlmssp_negotiate_domain_buffer = -1;
 static int hf_ntlmssp_negotiate_domain = -1;
-static int hf_ntlmssp_ntlm_challenge = -1;
+static int hf_ntlmssp_ntlm_server_challenge = -1;
+static int hf_ntlmssp_ntlm_client_challenge = -1;
 static int hf_ntlmssp_reserved = -1;
 static int hf_ntlmssp_challenge_domain = -1;
 static int hf_ntlmssp_auth_username = -1;
@@ -197,7 +213,8 @@
 static int hf_ntlmssp_verf = -1;
 static int hf_ntlmssp_verf_vers = -1;
 static int hf_ntlmssp_verf_body = -1;
-static int hf_ntlmssp_verf_unknown1 = -1;
+static int hf_ntlmssp_verf_randompad = -1;
+static int hf_ntlmssp_verf_hmacmd5 = -1;
 static int hf_ntlmssp_verf_crc32 = -1;
 static int hf_ntlmssp_verf_sequence = -1;
 static int hf_ntlmssp_decrypted_payload = -1;
@@ -211,6 +228,7 @@
 static int hf_ntlmssp_ntlmv2_response_name = -1;
 static int hf_ntlmssp_ntlmv2_response_name_type = -1;
 static int hf_ntlmssp_ntlmv2_response_name_len = -1;
+static int hf_ntlmssp_ntlmv2_response_restriction = -1;
 static int hf_ntlmssp_ntlmv2_response_client_time = -1;
 
 static gint ett_ntlmssp = -1;
@@ -234,9 +252,12 @@
 /* Used in the conversation function */
 typedef struct _ntlmssp_info {
   guint32 flags;
-  rc4_state_struct rc4_state_peer1;
-  rc4_state_struct rc4_state_peer2;
-  guint32 peer1_dest_port;
+  int is_auth_ntlm_v2;
+  rc4_state_struct rc4_state_client;
+  rc4_state_struct rc4_state_server;
+  guint32 server_dest_port;
+  unsigned char server_challenge[8];
+  unsigned char client_challenge[8];
   int rc4_state_initialized;
   ntlmssp_blob ntlm_response;
   ntlmssp_blob lm_response;
@@ -245,20 +266,63 @@
 /* If this struct exists in the payload_decrypt, then we have already
    decrypted it once */
 typedef struct _ntlmssp_packet_info {
-  guint32 flags;
   guint8 *decrypted_payload;
   guint8 verifier[16];
   gboolean payload_decrypted;
   gboolean verifier_decrypted;
 } ntlmssp_packet_info;
 
-
+static void printnbyte(const guint8* tab,int nb,char* txt,char* txt2)
+{
+  int i=0;
+  fprintf(stderr,"%s ",txt);
+  for(i=0;i<nb;i++)
+  {
+    fprintf(stderr,"%02hhX ",*(tab+i));
+  }
+  fprintf(stderr,"%s",txt2);
+}
+/*
+ static void printnchar(const guint8* tab,int nb,char* txt,char* txt2)
+{
+  int i=0;
+  fprintf(stderr,"%s ",txt);
+  for(i=0;i<nb;i++)
+  {
+    fprintf(stderr,"%c",*(tab+i));
+  }
+  fprintf(stderr,"%s",txt2);
+}
+*/
 /*
  * GSlist of decrypted payloads.
  */
 static GSList *decrypted_payloads;
 
 /*
+  Perform a DES encryption with a 16 bit key and 8bit data item.
+  It's in fact 3 susbsequent call to crypt_des_ecb with a 7 bit key.
+  Missing bits for the key are replaced by 0;
+  Returns output in response, which is expected to be 24 bytes.
+*/
+static int crypt_des_ecb_long(guint8 *response,
+					       const guint8 *key,
+					       const guint8 *data)
+{
+  guint8 pw21[21]; /* 21 bytes place for the needed key */
+
+  memset(pw21, 0, sizeof(pw21));
+  memcpy(pw21, key, 16);
+
+  memset(response, 0, 24);
+  /* crypt_des_ecb(data,key)*/
+  crypt_des_ecb(response, data, pw21, 1);
+  crypt_des_ecb(response + 8, data, pw21 + 7, 1);
+  crypt_des_ecb(response + 16, data, pw21 + 14, 1);
+
+  return 1;
+}
+/*
   Generate a challenge response, given an eight byte challenge and
   either the NT or the Lan Manager password hash (16 bytes).
   Returns output in response, which is expected to be 24 bytes.
@@ -281,31 +345,257 @@
   return 1;
 }
 
-/* Create an NTLMSSP version 1 key.
+
+/* Ultra simple ainsi to unicode converter, will only work for ascii password ...*/
+static void str_to_unicode(const char *nt_password, char *nt_password_unicode)
+{
+  int password_len = 0;
+  int i;
+  
+  password_len = strlen(nt_password);
+  if(nt_password_unicode != NULL)
+  {
+   for(i=0;i<(password_len);i++)
+   {
+     nt_password_unicode[i*2]=nt_password[i];
+     nt_password_unicode[i*2+1]=0;
+   }
+  }
+  nt_password_unicode[2*password_len]='\0';
+}
+
+/* This function generate the Key Exchange Key 
+ * Depending on the flags this key will either be used to crypt the exported session key
+ * or will be used directly as exported session key.
+ * Exported session key is the key that will be used for sealing and signing communication*/
+
+static void 
+get_keyexchange_key(unsigned char keyexchangekey[16],const unsigned char sessionbasekey[16],const unsigned char lm_challenge_response[24],int flags)
+{
+  guint8 basekey[16];
+  guint8 zeros[24];
+
+  memset(keyexchangekey,0,16);
+  memset(basekey,0,16);
+  /* sessionbasekey is either derived from lm_password_hash or from nt_password_hash depending on the key type negotiated */
+  memcpy(basekey,sessionbasekey,8);
+  memset(basekey,0xBD,8);
+  if(flags&NTLMSSP_NEGOTIATE_LM_KEY)
+  {
+    /*data,key*/
+    crypt_des_ecb(keyexchangekey,lm_challenge_response,basekey,1);
+    crypt_des_ecb(keyexchangekey+8,lm_challenge_response,basekey+7,1);
+  }
+  else
+  {
+    if(flags&NTLMSSP_REQUEST_NON_NT_SESSION)
+    {
+      /*People from samba tends to use the same function in this case than in the previous one but with 0 data 
+       * it's not clear that it produce the good result 
+       * memcpy(keyexchangekey,lm_hash,8);
+       * Let's trust samba implementation it mights seem weird but they are more often rights than the spec !
+       */
+      memset(zeros,0,24); 
+      crypt_des_ecb(keyexchangekey,zeros,basekey,3);
+      crypt_des_ecb(keyexchangekey+8,zeros,basekey+7,1);
+    }
+    else
+    {
+      /* it is stated page 65 of NTLM SSP spec that sessionbasekey should be encrypted with hmac_md5 using the concact of both challenge 
+       * when it's NTLM v1 + extended security but it turns out to be wrong !
+       */
+      memcpy(keyexchangekey,sessionbasekey,16);
+    }
+  }
+}
+static guint32
+get_md4pass_list(md4_pass** p_pass_list,const char* nt_password) {
+  guint32 nb_pass = 0;
+  enc_key_t *ek;
+  unsigned char nt_password_hash[16];
+  int password_len = 0;
+  char nt_password_unicode[256];
+  md4_pass* pass_list;
+  int i = 0;
+
+  for(ek=enc_key_list;ek;ek=ek->next){
+    if( ek->keylength == 16 ) {
+      nb_pass++;
+    }
+  }
+  memset(nt_password_hash,0,16);
+  if (nt_password[0] != '\0' && ( strlen(nt_password) < 129 )) {
+    nb_pass++;
+    password_len = strlen(nt_password);
+    str_to_unicode(nt_password,nt_password_unicode);
+    crypt_md4(nt_password_hash,nt_password_unicode,password_len*2);
+  }
+  if( nb_pass == 0 ) {
+    /* Unable to calculate the session key without a password  or if password is more than 128 char ......*/
+    return 0;
+  }
+  i = 0;
+  *p_pass_list = ep_alloc(nb_pass*sizeof(md4_pass));
+  pass_list=*p_pass_list;
+
+  if( memcmp(nt_password_hash,zeros,16) != 0 ) {
+    memcpy(pass_list[i].md4,nt_password_hash,16);
+    i = 1;
+  }
+  for(ek=enc_key_list;ek;ek=ek->next){
+    if( ek->keylength == 16 ) {
+      memcpy(pass_list[i].md4,ek->keyvalue,16);
+      i++;
+    }
+  }
+  return nb_pass;
+}
+/* Create an NTLMSSP version 2
+ */
+static void
+create_ntlmssp_v2_key(const char *nt_password, const guint8 *serverchallenge , const guint8 *clientchallenge ,
+		      guint8 *sessionkey ,const  guint8 *encryptedsessionkey , int flags , ntlmssp_blob ntlm_response, ntlmssp_blob lm_response _U_, ntlmssp_header_t *ntlmssph ) {
+  char domain_name_unicode[256];
+  char user_uppercase[256];
+  char buf[512];
+  /*guint8 md4[16];*/
+  unsigned char nt_password_hash[16];
+  unsigned char nt_proof[16];
+  unsigned char ntowf[16];
+  guint8 sessionbasekey[16];
+  guint8 keyexchangekey[16];
+  guint8 lm_challenge_response[24];
+  guint32 i;
+  guint32 j;
+  rc4_state_struct rc4state;
+  guint32  user_len;
+  guint32 domain_len;
+  md4_pass *pass_list;
+  guint32 nb_pass = 0;
+  int found = 0;
+
+  /* We are going to try password encrypted in keytab as well, it's an idean of Stepan Metzmacher <metze at samba.org> 
+   * The idea is to be able to test all the key of domain in once and to be able to decode the NTLM dialogs */
+
+  memset(sessionkey, 0, 16);
+  nb_pass = get_md4pass_list(&pass_list,nt_password);
+  fprintf(stderr,"Working with %d keys\n",nb_pass);
+  i=0;
+  memset(user_uppercase,0,256);
+  user_len = strlen(ntlmssph->acct_name);
+  if( user_len < 129 ) {
+     memset(buf,0,512);
+     str_to_unicode(ntlmssph->acct_name,buf);
+     for (j = 0; j < (2*user_len); j++) {
+       if( buf[j] != '\0' ) {
+         user_uppercase[j] = toupper(buf[j]);
+       }  
+     }
+  }
+  else {
+     /* Unable to calculate the session not enought space in buffer, note this is unlikely to happen but ......*/
+     return;
+  }  
+  domain_len = strlen(ntlmssph->domain_name);
+  if( domain_len < 129 ) {
+    str_to_unicode(ntlmssph->domain_name,domain_name_unicode);
+  }
+  else {
+    /* Unable to calculate the session not enought space in buffer, note this is unlikely to happen but ......*/
+    return;
+  }
+  while (i < nb_pass ) {
+    fprintf(stderr,"Turn %d, ",i);
+    memcpy(nt_password_hash,pass_list[i].md4,16);
+    printnbyte(nt_password_hash,16,"Current NT password hash: ","\n");
+    i++;
+    /* ntowf computation */ 
+    memset(buf,0,512);
+    memcpy(buf,user_uppercase,user_len*2);
+    memcpy(buf+user_len*2,domain_name_unicode,domain_len*2);
+    md5_hmac(buf,domain_len*2+user_len*2,nt_password_hash,16,ntowf);
+    /* LM response */
+    memset(buf,0,512);
+    memcpy(buf,serverchallenge,8);
+    memcpy(buf+8,clientchallenge,8);
+    md5_hmac(buf,16,ntowf,16,lm_challenge_response);
+    memcpy(lm_challenge_response+16,clientchallenge,8);
+    printnbyte(lm_challenge_response,24,"LM Response: ","\n");
+  
+    /* NT proof = First 16 bytes of NT response */
+    memset(buf,0,512);
+    memcpy(buf,serverchallenge,8);
+    memcpy(buf+8,ntlm_response.contents+16,ntlm_response.length-16);
+    md5_hmac(buf,ntlm_response.length-8,ntowf,16,nt_proof);
+    printnbyte(nt_proof,16,"NT proof: ","\n");
+    if( !memcmp(nt_proof,ntlm_response.contents,16) ) {
+      fprintf(stderr,"Found a matching password\n");
+      found = 1;
+      break;
+    }
+
+  }
+  if( found == 0 ) {
+    fprintf(stderr,"Unable to find a matching password, give up decoding\n");
+
+    return;
+  }
+  
+  md5_hmac(nt_proof,16,ntowf,16,sessionbasekey);
+  get_keyexchange_key(keyexchangekey,sessionbasekey,lm_challenge_response,flags);
+  /* now decrypt session key if needed and setup sessionkey for decrypting further communications */ 
+  if (flags & NTLMSSP_NEGOTIATE_KEY_EXCH)
+  {
+    memcpy(sessionkey,encryptedsessionkey,16);
+    crypt_rc4_init(&rc4state,keyexchangekey,16);
+    crypt_rc4(&rc4state,sessionkey,16);
+  }
+  else
+  {
+    memcpy(sessionkey,keyexchangekey,16);
+  }
+
+}
+ /* Create an NTLMSSP version 1 key 
+ * That is more complicated logic and methods and user challenge as well.
  * password points to the ANSI password to encrypt, challenge points to
- * the 8 octet challenge string, key128 will do a 128 bit key if set to 1,
- * otherwise it will do a 40 bit key.  The result is stored in
- * sspkey (expected to be 16 octets)
+ * the 8 octet challenge string
  */
 static void
-create_ntlmssp_v1_key(const char *nt_password, const guint8 *challenge,
-		      int use_key_128, guint8 *sspkey)
+create_ntlmssp_v1_key(const char *nt_password, const guint8 *serverchallenge, const guint8 *clientchallenge,
+		      guint8 *sessionkey,const  guint8 *encryptedsessionkey, int flags, const guint8 *ref_nt_challenge_response,const guint8 *ref_lm_challenge_response)
 {
   unsigned char lm_password_upper[16];
   unsigned char lm_password_hash[16];
+  unsigned char nt_password_hash[16];
+  unsigned char challenges_hash[16];
+  unsigned char challenges_hash_first8[8];
+  unsigned char challenges[16];
+  guint8 md4[16];
+  guint8 nb_pass = 0;
+  guint8 sessionbasekey[16];
+  guint8 keyexchangekey[16];
   guint8 lm_challenge_response[24];
-  guint8 rc4key[24];
-  guint8 pw21[21]; /* Password hash padded to 21 bytes */
+  guint8 nt_challenge_response[24];
+  rc4_state_struct rc4state;
+  md5_state_t md5state; 
+  char nt_password_unicode[256];
   size_t password_len;
   unsigned int i;
+  int found = 0;
+  md4_pass *pass_list;
   unsigned char lmhash_key[] =
     {0x4b, 0x47, 0x53, 0x21, 0x40, 0x23, 0x24, 0x25};
-
+  
+  memset(sessionkey, 0, 16);
   memset(lm_password_upper, 0, sizeof(lm_password_upper));
-
+  /* lm auth/lm session == (!NTLM_NEGOTIATE_NT_ONLY && NTLMSSP_NEGOTIATE_LM_KEY) || ! (EXTENDED_SECURITY) || ! NTLMSSP_NEGOTIATE_NTLM*/
   /* Create a Lan Manager hash of the input password */
   if (nt_password[0] != '\0') {
     password_len = strlen(nt_password);
+    /*Do not forget to free nt_password_nt*/
+    str_to_unicode(nt_password,nt_password_unicode);
+    crypt_md4(nt_password_hash,nt_password_unicode,password_len*2);
     /* Truncate password if too long */
     if (password_len > 16)
       password_len = 16;
@@ -313,42 +603,168 @@
       lm_password_upper[i] = toupper(nt_password[i]);
     }
   }
+  else
+  {
+    /* Unable to calculate the session key without a password ... and we will not use one for a keytab*/
+    if( !(flags & NTLMSSP_NEGOTIATE_EXTENDED_SECURITY )) {
+      return;
+    }
+  }
+  if((flags & NTLMSSP_NEGOTIATE_LM_KEY && !(flags & NTLMSSP_NEGOTIATE_NT_ONLY)) || !(flags & NTLMSSP_NEGOTIATE_EXTENDED_SECURITY)  || !(flags & NTLMSSP_NEGOTIATE_NTLM)) {
+    crypt_des_ecb(lm_password_hash, lmhash_key, lm_password_upper, 1);
+    crypt_des_ecb(lm_password_hash+8, lmhash_key, lm_password_upper+7, 1);
+    ntlmssp_generate_challenge_response(lm_challenge_response,
+				      lm_password_hash, serverchallenge);
+    memcpy(sessionbasekey,lm_password_hash,16);
+  }
+  else {
+    
+    memset(lm_challenge_response,0,24);
+    if( flags & NTLMSSP_NEGOTIATE_EXTENDED_SECURITY ) {
+      nb_pass = get_md4pass_list(&pass_list,nt_password);
+      fprintf(stderr,"Working with %d keys\n",nb_pass);
+      i=0;
+      while (i < nb_pass ) {
+        fprintf(stderr,"Turn %d, ",i);
+        memcpy(nt_password_hash,pass_list[i].md4,16);
+        printnbyte(nt_password_hash,16,"Current NT password hash: ","\n");
+        i++;
+        memcpy(lm_challenge_response,clientchallenge,8);
+        md5_init(&md5state); 
+        md5_append(&md5state,serverchallenge,8);
+        md5_append(&md5state,clientchallenge,8);
+        md5_finish(&md5state,challenges_hash);
+        memcpy(challenges_hash_first8,challenges_hash,8);
+        crypt_des_ecb_long(nt_challenge_response,nt_password_hash,challenges_hash_first8);
+        if( !memcmp(ref_nt_challenge_response,nt_challenge_response,24) ) {
+          fprintf(stderr,"Found a matching password\n");
+          found = 1;
+          break;
+        }
+      }
+    }
+    else {
+      crypt_des_ecb_long(nt_challenge_response,nt_password_hash,serverchallenge);
+      if( flags & NTLMSSP_NEGOTIATE_NT_ONLY ) {
+        memcpy(lm_challenge_response,nt_challenge_response,24);
+      }
+      else {
+        crypt_des_ecb_long(lm_challenge_response,lm_password_hash,serverchallenge);
+      }
+      if( !memcmp(ref_nt_challenge_response,nt_challenge_response,24) && !memcmp(ref_lm_challenge_response,lm_challenge_response,24) ) {
+          fprintf(stderr,"Found a matching password\n");
+          found = 1;
+      }    
+    }
+    /* So it's clearly not like this that's put into NTLMSSP doc but after some digging into samba code I'm quite confident
+     * that sessionbasekey should be based md4(nt_password_hash) only in the case of some NT auth
+     * Otherwise it should be lm_password_hash ...*/
+    crypt_md4(md4,nt_password_hash,16);
+    if (flags & NTLMSSP_NEGOTIATE_EXTENDED_SECURITY) {
+     memcpy(challenges,serverchallenge,8);
+     memcpy(challenges+8,clientchallenge,8);
+     /*md5_hmac(text,text_len,key,key_len,digest);*/
+     md5_hmac(challenges,16,md4,16,sessionbasekey);
+    }
+    else {
+     memcpy(sessionbasekey,md4,16);
+    }  
+  } 
 
-  crypt_des_ecb(lm_password_hash, lmhash_key, lm_password_upper, 1);
-  crypt_des_ecb(lm_password_hash+8, lmhash_key, lm_password_upper+7, 1);
+  if( found == 0 ) {
+    fprintf(stderr,"Unable to find a matching password, give up decoding\n");
+
+    return;
+  }
 
-  /* Generate the LanMan Challenge Response */
-  ntlmssp_generate_challenge_response(lm_challenge_response,
-				      lm_password_hash, challenge);
-
-  /* Generate the NTLMSSP-v1 RC4 Key.
-   * The RC4 key is derived from the Lan Manager Hash.
-   * See lkcl "DCE/RPC over SMB" page 254 for the algorithm.
-   */
-  memset(pw21, 0xBD, sizeof(pw21));
-  memcpy(pw21, lm_password_hash, sizeof(lm_password_hash));
 
-  /* Only the first eight bytes of challenge_response is used */
-  crypt_des_ecb(rc4key, lm_challenge_response, pw21, 1);
-  crypt_des_ecb(rc4key + 8, lm_challenge_response, pw21 + 7, 1);
-  crypt_des_ecb(rc4key + 16, lm_challenge_response, pw21 + 14, 1);
-
-  /* Create the SSP Key */
-  memset(sspkey, 0, sizeof(sspkey));
-  if (use_key_128) {
-    /* Create 128 bit key */
-    memcpy(sspkey, rc4key, 16);
+  get_keyexchange_key(keyexchangekey,sessionbasekey,lm_challenge_response,flags);
+  memset(sessionkey, 0, 16);
+  printnbyte(nt_challenge_response,24,"NT challenge response","\n");
+  printnbyte(lm_challenge_response,24,"LM challenge response","\n");
+  /* now decrypt session key if needed and setup sessionkey for decrypting further communications */ 
+  if (flags & NTLMSSP_NEGOTIATE_KEY_EXCH)
+  {
+    memcpy(sessionkey,encryptedsessionkey,16);
+    crypt_rc4_init(&rc4state,keyexchangekey,16);
+    crypt_rc4(&rc4state,sessionkey,16);
+  }
+  else
+  {
+    memcpy(sessionkey,keyexchangekey,16);
   }
-  else {
-    /* Create 40 bit key */
-    memcpy(sspkey, rc4key, 5);
-    sspkey[5]=0xe5;
-    sspkey[6]=0x38;
-    sspkey[7]=0xb0;
+}
+/* We return either a 128 or 64 bit key
+ */
+static void 
+get_sealing_rc4key(const guint8 exportedsessionkey[16] ,const int flags ,int *keylen ,guint8 *clientsealkey ,guint8 *serversealkey)
+{
+  md5_state_t md5state; 
+  md5_state_t md5state2; 
+  memset(clientsealkey,0,16);
+  memset(serversealkey,0,16);
+  memcpy(clientsealkey,exportedsessionkey,16);
+  if (flags & NTLMSSP_NEGOTIATE_EXTENDED_SECURITY)
+  {
+    if (flags & NTLMSSP_NEGOTIATE_128)
+    {
+      /* The exportedsessionkey has already the good length just update the length*/
+      *keylen = 16;
+    }
+    else
+    {
+      if (flags & NTLMSSP_NEGOTIATE_56)
+      {
+        memset(clientsealkey+7,0,9);
+        *keylen = 7;
+      }
+      else
+      {
+        memset(clientsealkey+5,0,11);
+        *keylen = 5;
+      }
+    }
+    memcpy(serversealkey,clientsealkey,16);
+    md5_init(&md5state); 
+    md5_append(&md5state,clientsealkey,*keylen);
+    md5_append(&md5state,CLIENT_SEAL_TEXT,strlen(CLIENT_SEAL_TEXT)+1);
+    md5_finish(&md5state,clientsealkey);
+    md5_init(&md5state2); 
+    md5_append(&md5state2,serversealkey,*keylen);
+    md5_append(&md5state2,SERVER_SEAL_TEXT,strlen(SERVER_SEAL_TEXT)+1);
+    md5_finish(&md5state2,serversealkey);
+  }
+  else
+  {
+    if (flags & NTLMSSP_NEGOTIATE_128)
+    {
+      /* The exportedsessionkey has already the good length just update the length*/
+      *keylen = 16;
+    }
+    else
+    {
+      *keylen = 8;
+      if (flags & NTLMSSP_NEGOTIATE_56)
+      {
+        memset(clientsealkey+7,0,9);
+      }
+      else
+      {
+        memset(clientsealkey+5,0,11);
+        clientsealkey[5]=0xe5;
+        clientsealkey[6]=0x38;
+        clientsealkey[7]=0xb0;
+      }
+    }  
+    serversealkey = memcpy(serversealkey,clientsealkey,*keylen);
   }
-  return;
 }
-
+/* Create an NTLMSSP version 1 key.
+ * password points to the ANSI password to encrypt, challenge points to
+ * the 8 octet challenge string, key128 will do a 128 bit key if set to 1,
+ * otherwise it will do a 40 bit key.  The result is stored in
+ * sspkey (expected to be 16 octets)
+ */
 /* dissect a string - header area contains:
      two byte len
      two byte maxlen
@@ -457,14 +873,27 @@
     result->length = blob_length;
     memset(result->contents, 0, MAX_BLOB_SIZE);
     if (blob_length < MAX_BLOB_SIZE)
+    {
       tvb_memcpy(tvb, result->contents, blob_offset, blob_length);
+      if (blob_hf == hf_ntlmssp_auth_lmresponse && !(memcmp(tvb->real_data+blob_offset+8,"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0",16)))
+      {
+        proto_tree_add_item (ntlmssp_tree,
+		       hf_ntlmssp_ntlm_client_challenge,
+		       tvb, blob_offset, 8, FALSE);
+      }
+    }
   }
 
   /* If we are dissecting the NTLM response and it is a NTLMv2
      response call the appropriate dissector. */
 
   if (blob_hf == hf_ntlmssp_auth_ntresponse && blob_length > 24)
+  {
+    proto_tree_add_item (ntlmssp_tree,
+	    hf_ntlmssp_ntlm_client_challenge,
+	    tvb, blob_offset+32, 8, FALSE);
 	  dissect_ntlmv2_response(tvb, tree, blob_offset, blob_length);
+  }
 
   return offset;
 }
@@ -601,6 +1030,9 @@
 #define NTLM_NAME_DNS_HOST   0x0003
 #define NTLM_NAME_DNS_DOMAIN 0x0004
 #define NTLM_NAME_CLIENT_TIME 0x0007
+#define NTLM_NAME_RESTRICTION 0x0008
+
+
 
 static const value_string ntlm_name_types[] = {
 	{ NTLM_NAME_END, "End of list" },
@@ -608,7 +1040,9 @@
 	{ NTLM_NAME_NB_DOMAIN, "NetBIOS domain name" },
 	{ NTLM_NAME_DNS_HOST, "DNS host name" },
 	{ NTLM_NAME_DNS_DOMAIN, "DNS domain name" },
+
 	{ NTLM_NAME_CLIENT_TIME, "Client Time" },
+	{ NTLM_NAME_RESTRICTION, "Encoding restriction" },
 	{ 0, NULL }
 };
 
@@ -617,7 +1051,7 @@
 {
 	proto_item *ntlmv2_item = NULL;
 	proto_tree *ntlmv2_tree = NULL;
-
+  const guint8 *restriction_bytes;
 	/* Dissect NTLMv2 bits&pieces */
 
 	if (tree) {
@@ -709,6 +1143,14 @@
 			proto_item_append_text(
 				name_item, "Client Time");
 			break;
+    case NTLM_NAME_RESTRICTION:
+			proto_item_append_text(
+				name_item, "%s",
+				val_to_str(name_type, ntlm_name_types,
+					   "Unknown"));
+      restriction_bytes = tvb_get_ptr(tvb, offset,name_len);
+      proto_tree_add_bytes (name_tree,hf_ntlmssp_ntlmv2_response_restriction,tvb,offset,name_len,restriction_bytes);
+  break;
 		case NTLM_NAME_NB_HOST:
 		case NTLM_NAME_NB_DOMAIN:
 		case NTLM_NAME_DNS_HOST:
@@ -716,10 +1158,9 @@
 		default:
 			name = tvb_get_ephemeral_faked_unicode(
 				tvb, offset, name_len / 2, TRUE);
-
 			proto_tree_add_text(
 				name_tree, tvb, offset, name_len,
-				"Name: %s", name);
+				"Value: %s", name);
 			proto_item_append_text(
 				name_item, "%s, %s",
 				val_to_str(name_type, ntlm_name_types,
@@ -911,12 +1352,14 @@
   guint32 negotiate_flags;
   int item_start, item_end;
   int data_start, data_end;
+  guint8 clientkey[16]; /* NTLMSSP cipher key for client */
+  guint8 serverkey[16]; /* NTLMSSP cipher key for server*/
   ntlmssp_info *conv_ntlmssp_info;
   conversation_t *conversation;
   gboolean unicode_strings = FALSE;
   guint8 challenge[8];
   guint8 sspkey[16]; /* NTLMSSP cipher key */
-  guint8 ssp_key_len; /* Either 8 or 16 (40 bit or 128) */
+  int ssp_key_len; /* Either 8 or 16 (40 bit or 128) */
 
   /* need to find unicode flag */
   negotiate_flags = tvb_get_letohl (tvb, offset+8);
@@ -940,7 +1383,7 @@
 
   /* NTLMSSP NT Lan Manager Challenge */
   proto_tree_add_item (ntlmssp_tree,
-		       hf_ntlmssp_ntlm_challenge,
+		       hf_ntlmssp_ntlm_server_challenge,
 		       tvb, offset, 8, FALSE);
 
   /*
@@ -961,22 +1404,26 @@
     conv_ntlmssp_info->flags = negotiate_flags;
     /* Insert the RC4 state information into the conversation */
     tvb_memcpy(tvb, challenge, offset, 8);
-
+    tvb_memcpy(tvb, conv_ntlmssp_info->server_challenge, offset, 8);
+    conv_ntlmssp_info->is_auth_ntlm_v2=0;
     /* Between the challenge and the user provided password, we can build the
-       NTLMSSP key and initialize the cipher */
-    if (conv_ntlmssp_info->flags & NTLMSSP_NEGOTIATE_128) {
-      create_ntlmssp_v1_key(nt_password, challenge, 1, sspkey);
-      ssp_key_len = 16;
-    }
-    else {
-      create_ntlmssp_v1_key(nt_password, challenge, 0, sspkey);
-      ssp_key_len = 8;
+       NTLMSSP key and initialize the cipher if we are not in EXTENDED SECURITY 
+       in this case we need the client challenge as well*/
+    /* BTW this is true just if we are in LM Authentification if not the logic is a bit different.
+     * Right now it's not very clear what is LM Authentification it __seems__ to be when 
+     * NEGOTIATE NT ONLY is not set and NEGOSIATE EXTENDED SECURITY is not set as well*/
+    if (!(conv_ntlmssp_info->flags & NTLMSSP_NEGOTIATE_EXTENDED_SECURITY))
+    {
+      create_ntlmssp_v1_key(nt_password, conv_ntlmssp_info->server_challenge,NULL, sspkey,NULL,conv_ntlmssp_info->flags,conv_ntlmssp_info->ntlm_response.contents,conv_ntlmssp_info->lm_response.contents);
+      if( memcmp(sspkey,zeros,16) != 0 ) {
+        get_sealing_rc4key(sspkey,conv_ntlmssp_info->flags,&ssp_key_len,clientkey,serverkey);
+        crypt_rc4_init(&conv_ntlmssp_info->rc4_state_client, sspkey, ssp_key_len);
+        crypt_rc4_init(&conv_ntlmssp_info->rc4_state_server, sspkey, ssp_key_len);
+        conv_ntlmssp_info->server_dest_port = pinfo->destport;
+        conv_ntlmssp_info->rc4_state_initialized = 1;
+      }
+  
     }
-    crypt_rc4_init(&conv_ntlmssp_info->rc4_state_peer1, sspkey, ssp_key_len);
-    crypt_rc4_init(&conv_ntlmssp_info->rc4_state_peer2, sspkey, ssp_key_len);
-    conv_ntlmssp_info->peer1_dest_port = pinfo->destport;
-    conv_ntlmssp_info->rc4_state_initialized = 1;
-
     conversation_add_proto_data(conversation, proto_ntlmssp, conv_ntlmssp_info);
   }
   offset += 8;
@@ -1023,15 +1470,27 @@
   int item_start, item_end;
   int data_start, data_end = 0;
   guint32 negotiate_flags;
+  guint8 sspkey[16]; /* exported session key */
+  guint8 clientkey[16]; /* NTLMSSP cipher key for client */
+  guint8 serverkey[16]; /* NTLMSSP cipher key for server*/
+  guint8 encryptedsessionkey[16];
+  ntlmssp_blob sessionblob;
   gboolean unicode_strings = FALSE;
-  ntlmssp_info *conv_ntlmssp_info;
+  ntlmssp_info *conv_ntlmssp_info = NULL;
   conversation_t *conversation;
-
+  int ssp_key_len;
   /*
    * Get flag info from the original negotiate message, if any.
    * This is because the flag information is sometimes missing from
    * the AUTHENTICATE message, so we can't figure out whether
    * strings are Unicode or not by looking at *our* flags.
+   * XXX it seems it's more from the CHALLENGE message, which is more clever in fact
+   * because the server can change some flags.
+   * But according to MS NTLMSSP doc it's not that simple. 
+   * In case of Conection less mode AUTHENTICATE flags should be used because they
+   * reprensent the choice of the client after having been informed of options of the 
+   * server in the CHALLENGE message.
+   * In Connection mode then the CHALLENGE flags should (must ?) be used
    */
   conv_ntlmssp_info = p_get_proto_data(pinfo->fd, proto_ntlmssp);
   if (conv_ntlmssp_info == NULL) {
@@ -1060,7 +1519,10 @@
 
   /*
    * Sometimes the session key and flags are missing.
-   * Sometimes the session key is present but the flags are missing.
+   * Sometimes the session key is present but the flags are missing. 
+   * XXX Who stay so ? Reading spec I would rather say the opposite: flags are 
+   * always present, session information are always there as well but sometime 
+   * session information could be null (in case of no session)
    * Sometimes they're both present.
    *
    * This does not correlate with any flags in the previous CHALLENGE
@@ -1082,7 +1544,7 @@
 				conv_ntlmssp_info == NULL ? NULL :
 				    &conv_ntlmssp_info->lm_response);
   data_end = MAX(data_end, item_end);
-
+  
   /* NTLM response */
   item_start = tvb_get_letohl(tvb, offset+4);
   offset = dissect_ntlmssp_blob(tvb, offset, ntlmssp_tree,
@@ -1090,8 +1552,18 @@
 				&item_end,
 				conv_ntlmssp_info == NULL ? NULL :
 				&conv_ntlmssp_info->ntlm_response);
+  if( conv_ntlmssp_info != NULL && conv_ntlmssp_info->ntlm_response.length > 24 ) {
+    memcpy(conv_ntlmssp_info->client_challenge,conv_ntlmssp_info->ntlm_response.contents+32,8);
+  }
   data_start = MIN(data_start, item_start);
   data_end = MAX(data_end, item_end);
+  if( conv_ntlmssp_info != NULL )
+  {
+    if( conv_ntlmssp_info->ntlm_response.length > 24 )
+    {
+      conv_ntlmssp_info->is_auth_ntlm_v2=1;
+    }
+  }
 
   /* domain name */
   item_start = tvb_get_letohl(tvb, offset+4);
@@ -1099,6 +1571,7 @@
 				  unicode_strings,
 				  hf_ntlmssp_auth_domain,
 				  &item_start, &item_end, &(ntlmssph->domain_name));
+  /*ntlmssph->domain_name_len=item_end-item_start;*/
   data_start = MIN(data_start, item_start);
   data_end = MAX(data_end, item_end);
 
@@ -1108,6 +1581,7 @@
 				  unicode_strings,
 				  hf_ntlmssp_auth_username,
 				  &item_start, &item_end, &(ntlmssph->acct_name));
+  /*ntlmssph->acct_name_len=item_end-item_start;*/
   data_start = MIN(data_start, item_start);
   data_end = MAX(data_end, item_end);
 
@@ -1128,20 +1602,274 @@
     /* Session Key */
     offset = dissect_ntlmssp_blob(tvb, offset, ntlmssp_tree,
 				  hf_ntlmssp_auth_sesskey,
-				  &item_end, NULL);
+				  &item_end, &sessionblob);
     data_end = MAX(data_end, item_end);
   }
-
+  memcpy(encryptedsessionkey,sessionblob.contents,sessionblob.length);
   if (offset < data_start) {
     /* NTLMSSP Negotiate Flags */
     negotiate_flags = tvb_get_letohl (tvb, offset);
     offset = dissect_ntlmssp_negotiate_flags (tvb, offset, ntlmssp_tree,
 					      negotiate_flags);
   }
-
+  /* Try to attach to an existing conversation if not then it's useless to try to do so
+   * because we are missing important information (ie. server challenge)
+   */
+  if (conv_ntlmssp_info) {
+    /* If we are in EXTENDED SECURITY then we can now initialize cipher */
+    if ((conv_ntlmssp_info->flags & NTLMSSP_NEGOTIATE_EXTENDED_SECURITY))
+    {
+      if( conv_ntlmssp_info->is_auth_ntlm_v2 ) {
+        create_ntlmssp_v2_key(nt_password, conv_ntlmssp_info->server_challenge,conv_ntlmssp_info->client_challenge, sspkey,encryptedsessionkey,conv_ntlmssp_info->flags,conv_ntlmssp_info->ntlm_response,conv_ntlmssp_info->lm_response,ntlmssph);
+      }
+      else
+      {
+        memcpy(conv_ntlmssp_info->client_challenge,conv_ntlmssp_info->lm_response.contents,8);
+        create_ntlmssp_v1_key(nt_password, conv_ntlmssp_info->server_challenge,conv_ntlmssp_info->client_challenge, sspkey,encryptedsessionkey,conv_ntlmssp_info->flags,conv_ntlmssp_info->ntlm_response.contents,conv_ntlmssp_info->lm_response.contents);
+      }
+      /* ssp is the exported session key */
+      if( memcmp(sspkey,zeros,16) != 0) {
+        get_sealing_rc4key(sspkey,conv_ntlmssp_info->flags,&ssp_key_len,clientkey,serverkey);
+        crypt_rc4_init(&conv_ntlmssp_info->rc4_state_server, serverkey, ssp_key_len);
+        crypt_rc4_init(&conv_ntlmssp_info->rc4_state_client, clientkey, ssp_key_len); 
+        conv_ntlmssp_info->server_dest_port = pinfo->destport;
+        conv_ntlmssp_info->rc4_state_initialized = 1;
+      }
+    }
+   }
   return MAX(offset, data_end);
 }
+/*
+ * Get the encryption state tied to this conversation.  cryptpeer indicates
+ * whether to retrieve the client key (1) or the server key (0) 
+ */
+static rc4_state_struct *
+get_encrypted_state(packet_info *pinfo, int cryptpeer)
+{
+  conversation_t *conversation;
+  ntlmssp_info *conv_ntlmssp_info;
+
+  conversation = find_conversation(pinfo->fd->num, &pinfo->src, &pinfo->dst,
+				   pinfo->ptype, pinfo->srcport,
+				   pinfo->destport, 0);
+  if (conversation == NULL) {
+    /* We don't have a conversation.  In this case, stop processing
+       because we do not have enough info to decrypt the payload */
+    return NULL;
+  }
+  else {
+    /* We have a conversation, check for encryption state */
+    conv_ntlmssp_info = conversation_get_proto_data(conversation,
+						    proto_ntlmssp);
+    if (conv_ntlmssp_info == NULL) {
+      /* No encryption state tied to the conversation.  Therefore, we
+	 cannot decrypt the payload */
+      return NULL;
+    }
+    else {
+      /* We have the encryption state in the conversation.  So return the
+	 crypt state tied to the requested peer
+       */
+      if (cryptpeer == 1) {
+	      return &conv_ntlmssp_info->rc4_state_client;
+      } else {
+	      return &conv_ntlmssp_info->rc4_state_server;
+      }
+    }
+  }
+}
+void 
+decrypt_data_payload(tvbuff_t *tvb, int offset, guint32 encrypted_block_length,
+		 packet_info *pinfo, proto_tree *tree _U_,gpointer key);
+static void
+decrypt_verifier(tvbuff_t *tvb, int offset, guint32 encrypted_block_length,
+		 packet_info *pinfo, proto_tree *tree,gpointer key);
+
+/*
+tvbuff_t *
+dissect_ntlmssp_encrypted_payload(tvbuff_t *data_tvb,
+				  tvbuff_t *auth_tvb _U_,
+				  int offset,
+				  packet_info *pinfo,
+				  dcerpc_auth_info *auth_info _U_)*/
+
+int
+dissect_ntlmssp_payload(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree )
+{
+  volatile int offset = 0;
+  proto_tree *volatile ntlmssp_tree = NULL;
+  proto_item *tf = NULL;
+  guint32 length;
+  guint32 encrypted_block_length;
+  guint8 key[16];
+  /* the magic ntlm is the identifier of a NTLMSSP packet that's 00 00 00 01
+   */
+  guint32 ntlm_magic_size = 4;
+  guint32 ntlm_signature_size = 8;
+  guint32 ntlm_seq_size = 4;
+  length = tvb_length (tvb);
+  /* signature + seq + real payload */
+  encrypted_block_length = length - ntlm_magic_size;
+
+  if (encrypted_block_length < (ntlm_signature_size + ntlm_seq_size)) {
+    /* Don't know why this would happen, but if it does, don't even bother
+       attempting decryption/dissection */
+    return offset + length;
+  }
+
+  /* Setup a new tree for the NTLMSSP payload */
+  if (tree) {
+    tf = proto_tree_add_item (tree,
+			      hf_ntlmssp_verf,
+			      tvb, offset, -1, FALSE);
+
+    ntlmssp_tree = proto_item_add_subtree (tf,
+					   ett_ntlmssp);
+  }
+
+  /*
+   * Catch the ReportedBoundsError exception; the stuff we've been
+   * handed doesn't necessarily run to the end of the packet, it's
+   * an item inside a packet, so if it happens to be malformed (or
+   * we, or a dissector we call, has a bug), so that an exception
+   * is thrown, we want to report the error, but return and let
+   * our caller dissect the rest of the packet.
+   *
+   * If it gets a BoundsError, we can stop, as there's nothing more
+   * in the packet after our blob to see, so we just re-throw the
+   * exception.
+   */
+  TRY {
+    /* Version number */
+    proto_tree_add_item (ntlmssp_tree, hf_ntlmssp_verf_vers,
+			 tvb, offset, 4, TRUE);
+    offset += 4;
+
+    /* Encrypted body */
+    proto_tree_add_item (ntlmssp_tree, hf_ntlmssp_verf_body,
+			 tvb, offset, ntlm_signature_size + ntlm_seq_size, TRUE);
+    tvb_memcpy(tvb, key, offset, ntlm_signature_size + ntlm_seq_size);
+    /* Try to decrypt */
+    decrypt_data_payload (tvb, offset+(ntlm_signature_size + ntlm_seq_size), encrypted_block_length-(ntlm_signature_size + ntlm_seq_size), pinfo, ntlmssp_tree,key);
+    decrypt_verifier (tvb, offset, ntlm_signature_size + ntlm_seq_size, pinfo, ntlmssp_tree,key);
+    /* let's try to hook ourselves here */
+
+    offset += 12;
+  } CATCH(BoundsError) {
+    RETHROW;
+  } CATCH(ReportedBoundsError) {
+    show_reported_bounds_error(tvb, pinfo, tree);
+  } ENDTRY;
+
+  return offset;
+}
+void 
+decrypt_data_payload(tvbuff_t *tvb, int offset, guint32 encrypted_block_length,
+		 packet_info *pinfo, proto_tree *tree _U_,gpointer key)
+{
+  tvbuff_t *decr_tvb; /* Used to display decrypted buffer */
+  guint8 *peer_block;
+  conversation_t *conversation;
+  rc4_state_struct *rc4_state;
+  rc4_state_struct *rc4_state_peer;
+  ntlmssp_info *conv_ntlmssp_info = NULL;
+  ntlmssp_packet_info *packet_ntlmssp_info = NULL;
+  ntlmssp_packet_info *stored_packet_ntlmssp_info = NULL;
+
 
+  /* Check to see if we already have state for this packet */
+  packet_ntlmssp_info = p_get_proto_data(pinfo->fd, proto_ntlmssp);
+  if (packet_ntlmssp_info == NULL) {
+    /* We don't have any packet state, so create one */
+    packet_ntlmssp_info = se_alloc(sizeof(ntlmssp_packet_info));
+    memset(packet_ntlmssp_info, 0, sizeof(ntlmssp_packet_info));
+    p_add_proto_data(pinfo->fd, proto_ntlmssp, packet_ntlmssp_info);
+  }
+  if (!packet_ntlmssp_info->payload_decrypted) {
+    /* Pull the challenge info from the conversation */
+    conversation = find_conversation(pinfo->fd->num, &pinfo->src, &pinfo->dst,
+				     pinfo->ptype, pinfo->srcport,
+				     pinfo->destport, 0);
+    if (conversation == NULL) {
+      /* There is no conversation, thus no encryption state */
+      return ;
+    }
+
+    conv_ntlmssp_info = conversation_get_proto_data(conversation,
+						    proto_ntlmssp);
+    if (conv_ntlmssp_info == NULL) {
+      /* There is no NTLMSSP state tied to the conversation */
+	    return ;
+    }
+    if (conv_ntlmssp_info->rc4_state_initialized != 1 ) {
+       /* The crypto sybsystem is not initialized.  This means that either
+	         the conversation did not include a challenge, or that we do not have the right password */
+       return;
+    }
+    stored_packet_ntlmssp_info = g_hash_table_lookup(hash_packet,key);
+    if( stored_packet_ntlmssp_info != NULL && stored_packet_ntlmssp_info->payload_decrypted == TRUE)
+    {
+      /* Mat TBD fprintf(stderr,"Found a already decrypted packet\n");*/
+      memcpy(packet_ntlmssp_info,stored_packet_ntlmssp_info,sizeof(ntlmssp_packet_info));
+      /* Mat TBD printnbyte(packet_ntlmssp_info->decrypted_payload,encrypted_block_length,"Data: ","\n");*/
+    }
+    else
+    {
+      /* Get the pair of RC4 state structures.  One is used for to decrypt the
+         payload.  The other is used to re-encrypt the payload to represent
+         the peer */
+      if (conv_ntlmssp_info->server_dest_port == pinfo->destport) {
+        /* client */
+        rc4_state = get_encrypted_state(pinfo, 1);
+        rc4_state_peer = get_encrypted_state(pinfo, 0);
+      } else {
+        /* server */
+        rc4_state = get_encrypted_state(pinfo, 0);
+        rc4_state_peer = get_encrypted_state(pinfo, 1);
+      }
+  
+      if (rc4_state == NULL ) {
+        /* There is no encryption state, so we cannot decrypt */
+        return ;
+      }
+  
+      /* Store the decrypted contents in the packet state struct
+         (of course at this point, they aren't decrypted yet) */
+      packet_ntlmssp_info->decrypted_payload = tvb_memdup(tvb, offset,
+                                                          encrypted_block_length);
+      decrypted_payloads = g_slist_prepend(decrypted_payloads,
+                                           packet_ntlmssp_info->decrypted_payload);
+      g_hash_table_insert(hash_packet,key,packet_ntlmssp_info);
+  
+      /* Do the decryption of the payload */
+      crypt_rc4(rc4_state, packet_ntlmssp_info->decrypted_payload,
+  	      encrypted_block_length);
+      /* decrypt the verifier */
+  
+      /* We setup a temporary buffer so we can re-encrypt the payload after
+         decryption.  This is to update the opposite peer's RC4 state 
+         it's usefull when we have only one key for both conversation
+         in case of KEY_EXCH we have independant key so this is not needed*/
+      if( !(NTLMSSP_NEGOTIATE_KEY_EXCH & conv_ntlmssp_info->flags)) {
+        peer_block = g_malloc(encrypted_block_length);
+        memcpy(peer_block, packet_ntlmssp_info->decrypted_payload,
+  	      encrypted_block_length);
+        crypt_rc4(rc4_state_peer, peer_block, encrypted_block_length);
+        g_free(peer_block);
+      } 
+    
+      packet_ntlmssp_info->payload_decrypted = TRUE;
+    }
+  }
+
+ /* Show the decrypted buffer in a new window */
+  decr_tvb = tvb_new_real_data(packet_ntlmssp_info->decrypted_payload,
+			       encrypted_block_length,
+			       encrypted_block_length);
+
+  tvb_set_child_real_data_tvbuff(tvb, decr_tvb);
+  pinfo->gssapi_decrypted_tvb =  decr_tvb;
+}
 static void
 dissect_ntlmssp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
 {
@@ -1226,52 +1954,14 @@
   tap_queue_packet(ntlmssp_tap, pinfo, ntlmssph);
 }
 
-/*
- * Get the encryption state tied to this conversation.  cryptpeer indicates
- * whether to retrieve the data for peer1 or peer2.
- */
-static rc4_state_struct *
-get_encrypted_state(packet_info *pinfo, int cryptpeer)
-{
-  conversation_t *conversation;
-  ntlmssp_info *conv_ntlmssp_info;
 
-  conversation = find_conversation(pinfo->fd->num, &pinfo->src, &pinfo->dst,
-				   pinfo->ptype, pinfo->srcport,
-				   pinfo->destport, 0);
-  if (conversation == NULL) {
-    /* We don't have a conversation.  In this case, stop processing
-       because we do not have enough info to decrypt the payload */
-    return NULL;
-  }
-  else {
-    /* We have a conversation, check for encryption state */
-    conv_ntlmssp_info = conversation_get_proto_data(conversation,
-						    proto_ntlmssp);
-    if (conv_ntlmssp_info == NULL) {
-      /* No encryption state tied to the conversation.  Therefore, we
-	 cannot decrypt the payload */
-      return NULL;
-    }
-    else {
-      /* We have the encryption state in the conversation.  So return the
-	 crypt state tied to the requested peer
-       */
-      if (cryptpeer == 1) {
-	return &conv_ntlmssp_info->rc4_state_peer1;
-      } else {
-	return &conv_ntlmssp_info->rc4_state_peer2;
-      }
-    }
-  }
-}
 
 /*
  * See page 45 of "DCE/RPC over SMB" by Luke Kenneth Casson Leighton.
  */
 static void
 decrypt_verifier(tvbuff_t *tvb, int offset, guint32 encrypted_block_length,
-		 packet_info *pinfo, proto_tree *tree)
+		 packet_info *pinfo, proto_tree *tree,gpointer key)
 {
   proto_tree *decr_tree = NULL;
   proto_item *tf = NULL;
@@ -1283,69 +1973,97 @@
   ntlmssp_info *conv_ntlmssp_info = NULL;
   ntlmssp_packet_info *packet_ntlmssp_info = NULL;
   int decrypted_offset = 0;
-
+  ntlmssp_packet_info *stored_packet_ntlmssp_info = NULL;
   packet_ntlmssp_info = p_get_proto_data(pinfo->fd, proto_ntlmssp);
   if (packet_ntlmssp_info == NULL) {
     /* We don't have data for this packet */
     return;
   }
-  if (!packet_ntlmssp_info->verifier_decrypted) {
-    conversation = find_conversation(pinfo->fd->num, &pinfo->src, &pinfo->dst,
-				     pinfo->ptype, pinfo->srcport,
-				     pinfo->destport, 0);
-    if (conversation == NULL) {
-      /* There is no conversation, thus no encryption state */
-      return;
-    }
-
-    conv_ntlmssp_info = conversation_get_proto_data(conversation,
+  conversation = find_conversation(pinfo->fd->num, &pinfo->src, &pinfo->dst,
+		     pinfo->ptype, pinfo->srcport,
+		     pinfo->destport, 0);
+  if (conversation == NULL) {
+    /* There is no conversation, thus no encryption state */
+    return;
+  }
+  conv_ntlmssp_info = conversation_get_proto_data(conversation,
 						    proto_ntlmssp);
-    if (conv_ntlmssp_info == NULL) {
-      /* There is no NTLMSSP state tied to the conversation */
-      return;
-    }
-    if (conv_ntlmssp_info->rc4_state_initialized != 1 ) {
-      /* The crypto sybsystem is not initialized.  This means that either
-	 the conversation did not include a challenge, or we are doing
-	 something other than NTLMSSP v1 */
-      return;
-    }
-
-    if (conv_ntlmssp_info->peer1_dest_port == pinfo->destport) {
-      rc4_state = get_encrypted_state(pinfo, 1);
-      rc4_state_peer = get_encrypted_state(pinfo, 0);
-    } else {
-      rc4_state = get_encrypted_state(pinfo, 0);
-      rc4_state_peer = get_encrypted_state(pinfo, 1);
-    }
+  if (conv_ntlmssp_info == NULL) {
+  /* There is no NTLMSSP state tied to the conversation */
+    return;
+  }
 
-    if (rc4_state == NULL || rc4_state_peer == NULL) {
-      /* There is no encryption state, so we cannot decrypt */
-      return;
+  if( key != NULL ){
+    stored_packet_ntlmssp_info = g_hash_table_lookup(hash_packet,key);
+  }
+  if( stored_packet_ntlmssp_info != NULL && stored_packet_ntlmssp_info->verifier_decrypted == TRUE) {
+      /* Mat TBD fprintf(stderr,"Found a already decrypted packet\n");*/
+      /* In Theory it's aleady the case, and we should be more clever ... like just copying buffers ...*/
+      packet_ntlmssp_info = stored_packet_ntlmssp_info;
+  }
+  else {
+    if (!packet_ntlmssp_info->verifier_decrypted) {
+      if (conv_ntlmssp_info->rc4_state_initialized != 1 ) {
+        /* The crypto sybsystem is not initialized.  This means that either
+  	 the conversation did not include a challenge, or we are doing
+  	 something other than NTLMSSP v1 */
+        return;
+      }
+      if (conv_ntlmssp_info->server_dest_port == pinfo->destport) {
+        /* client talk to server */
+        rc4_state = get_encrypted_state(pinfo, 1);
+        rc4_state_peer = get_encrypted_state(pinfo, 0);
+      } else {
+        rc4_state = get_encrypted_state(pinfo, 0);
+        rc4_state_peer = get_encrypted_state(pinfo, 1);
+      }
+  
+      if (rc4_state == NULL || rc4_state_peer == NULL) {
+        /* There is no encryption state, so we cannot decrypt */
+        return;
+      }
+  
+      /* Setup the buffer to decrypt to */
+      tvb_memcpy(tvb, packet_ntlmssp_info->verifier,
+  	       offset, encrypted_block_length);
+      
+      /*if( !(NTLMSSP_NEGOTIATE_KEY_EXCH & packet_ntlmssp_info->flags)) {*/
+      if( conv_ntlmssp_info->flags & NTLMSSP_NEGOTIATE_EXTENDED_SECURITY ) {
+        if( (NTLMSSP_NEGOTIATE_KEY_EXCH & conv_ntlmssp_info->flags)) {
+          /* The spec says that if we have have a key exchange then we have a the signature that is crypted 
+           * otherwise it's just a hmac_md5(keysign,concat(message,sequence))[0..7]
+           */
+          crypt_rc4(rc4_state, packet_ntlmssp_info->verifier,
+  	        8);
+        }
+      }
+      else {
+        /* The packet has a PAD then a checksum then a sequence and they are encoded in this order so we can decrypt all at once */
+        /* Do the actual decryption of the verifier */
+        crypt_rc4(rc4_state, packet_ntlmssp_info->verifier,
+  	        encrypted_block_length);
+      }
+  
+  
+  
+      /* We setup a temporary buffer so we can re-encrypt the payload after
+         decryption.  This is to update the opposite peer's RC4 state 
+         This is not needed when we just have EXTENDED SECURITY because the signature is not crypted
+         and it's also not needed when we have key exchange because server and client have independant keys */
+      if( !(NTLMSSP_NEGOTIATE_KEY_EXCH & conv_ntlmssp_info->flags) && !(NTLMSSP_NEGOTIATE_EXTENDED_SECURITY & conv_ntlmssp_info->flags)) {
+        peer_block = g_malloc(encrypted_block_length);
+        memcpy(peer_block, packet_ntlmssp_info->verifier,
+  	      encrypted_block_length);
+        crypt_rc4(rc4_state_peer, peer_block, encrypted_block_length);
+        g_free(peer_block);
+      }
+  
+      /* Mark the packet as decrypted so that subsequent attempts to dissect
+         the packet use the already decrypted payload instead of attempting
+         to decrypt again */
+      packet_ntlmssp_info->verifier_decrypted = TRUE;
     }
-
-    /* Setup the buffer to decrypt to */
-    tvb_memcpy(tvb, packet_ntlmssp_info->verifier,
-	       offset, encrypted_block_length);
-
-    /* Do the actual decryption of the verifier */
-    crypt_rc4(rc4_state, packet_ntlmssp_info->verifier,
-	      encrypted_block_length);
-
-    /* We setup a temporary buffer so we can re-encrypt the payload after
-       decryption.  This is to update the opposite peer's RC4 state */
-    peer_block = g_malloc(encrypted_block_length);
-    memcpy(peer_block, packet_ntlmssp_info->verifier,
-	   encrypted_block_length);
-    crypt_rc4(rc4_state_peer, peer_block, encrypted_block_length);
-    g_free(peer_block);
-
-    /* Mark the packet as decrypted so that subsequent attempts to dissect
-       the packet use the already decrypted payload instead of attempting
-       to decrypt again */
-    packet_ntlmssp_info->verifier_decrypted = TRUE;
   }
-
   /* Show the decrypted buffer in a new window */
   decr_tvb = tvb_new_real_data(packet_ntlmssp_info->verifier,
 			       encrypted_block_length,
@@ -1360,23 +2078,36 @@
 			   encrypted_block_length,
 			   plurality(encrypted_block_length, "", "s"));
   decr_tree = proto_item_add_subtree (tf, ett_ntlmssp);
+  
+  if(( conv_ntlmssp_info->flags & NTLMSSP_NEGOTIATE_EXTENDED_SECURITY )) {
+    proto_tree_add_item (decr_tree, hf_ntlmssp_verf_hmacmd5,
+	  	       decr_tvb, decrypted_offset, 8,TRUE);
+    decrypted_offset += 8;
+
+
+
+    /* Incrementing sequence number of DCE conversation */
+   proto_tree_add_item (decr_tree, hf_ntlmssp_verf_sequence,
+		         decr_tvb, decrypted_offset, 4, TRUE);
+    decrypted_offset += 4;
+  }
+  else {
 
-  /* LKCL page 45 says this is a "reserved" field.  I'm not sure if it's
-     garbage because it's some sort of nonce, or because there is a problem
-     with the verifier decryption routine.  */
-  proto_tree_add_item (decr_tree, hf_ntlmssp_verf_unknown1,
-		       decr_tvb, decrypted_offset, 4, TRUE);
-  decrypted_offset += 4;
-
-  /* CRC32 of the DCE fragment data */
-  proto_tree_add_item (decr_tree, hf_ntlmssp_verf_crc32,
-		       decr_tvb, decrypted_offset, 4, TRUE);
-  decrypted_offset += 4;
-
-  /* Incrementing sequence number of DCE conversation */
-  proto_tree_add_item (decr_tree, hf_ntlmssp_verf_sequence,
-		       decr_tvb, decrypted_offset, 4, TRUE);
-  decrypted_offset += 4;
+    /* RANDOM PAD usually it's 0 */
+    proto_tree_add_item (decr_tree, hf_ntlmssp_verf_randompad,
+	  	       decr_tvb, decrypted_offset, 4, TRUE);
+    decrypted_offset += 4;
+
+    /* CRC32 of the DCE fragment data */
+    proto_tree_add_item (decr_tree, hf_ntlmssp_verf_crc32,
+	  	       decr_tvb, decrypted_offset, 4, TRUE);
+    decrypted_offset += 4;
+
+    /* Incrementing sequence number of DCE conversation */
+   proto_tree_add_item (decr_tree, hf_ntlmssp_verf_sequence,
+		         decr_tvb, decrypted_offset, 4, TRUE);
+    decrypted_offset += 4;
+  }
 }
 
 static int
@@ -1430,8 +2161,10 @@
 			 tvb, offset, encrypted_block_length, TRUE);
 
     /* Try to decrypt */
-    decrypt_verifier (tvb, offset, encrypted_block_length, pinfo, ntlmssp_tree);
+    decrypt_verifier (tvb, offset, encrypted_block_length, pinfo, ntlmssp_tree,NULL);
+    /* let's try to hook ourselves here */
 
+    offset += 12;
     offset += encrypted_block_length;
   } CATCH(BoundsError) {
     RETHROW;
@@ -1442,13 +2175,14 @@
   return offset;
 }
 
-static tvbuff_t *
+tvbuff_t *
 dissect_ntlmssp_encrypted_payload(tvbuff_t *data_tvb,
 				  tvbuff_t *auth_tvb _U_,
 				  int offset,
 				  packet_info *pinfo,
 				  dcerpc_auth_info *auth_info _U_)
 {
+  /* gssapi_decrypted_tvb=NULL */
   tvbuff_t *decr_tvb; /* Used to display decrypted buffer */
   guint8 *peer_block;
   conversation_t *conversation;
@@ -1457,7 +2191,6 @@
   rc4_state_struct *rc4_state_peer;
   ntlmssp_info *conv_ntlmssp_info = NULL;
   ntlmssp_packet_info *packet_ntlmssp_info = NULL;
-
   encrypted_block_length = tvb_length_remaining (data_tvb, offset);
 
   /* Check to see if we already have state for this packet */
@@ -1477,19 +2210,18 @@
     if (conversation == NULL) {
       /* There is no conversation, thus no encryption state */
       return NULL;
-    }
 
+    }
     conv_ntlmssp_info = conversation_get_proto_data(conversation,
 						    proto_ntlmssp);
     if (conv_ntlmssp_info == NULL) {
-      /* There is no NTLMSSP state tied to the conversation */
-	    return NULL;
+    /* There is no NTLMSSP state tied to the conversation */
+    return NULL;
     }
-
     /* Get the pair of RC4 state structures.  One is used for to decrypt the
        payload.  The other is used to re-encrypt the payload to represent
        the peer */
-    if (conv_ntlmssp_info->peer1_dest_port == pinfo->destport) {
+    if (conv_ntlmssp_info->server_dest_port == pinfo->destport) {
       rc4_state = get_encrypted_state(pinfo, 1);
       rc4_state_peer = get_encrypted_state(pinfo, 0);
     } else {
@@ -1542,6 +2274,21 @@
 	g_free(decrypted_payload);
 }
 
+guint g_header_hash(gconstpointer pointer) {
+  guint32 crc =  ~calculate_crc32c(pointer,16,CRC32C_PRELOAD);
+  /* Mat TBD fprintf(stderr,"Val: %u\n",crc);*/
+  return crc;
+}
+
+gboolean g_header_equal(gconstpointer pointer1, gconstpointer pointer2) {
+  if(!memcmp(pointer1,pointer2,16)) {
+    return TRUE;
+  }
+  else {
+    return FALSE;
+  }
+}
+  
 static void
 ntlmssp_init_protocol(void)
 {
@@ -1555,8 +2302,14 @@
 		decrypted_payloads = NULL;
 	}
 
+  if(hash_packet == NULL) {
+    hash_packet = g_hash_table_new(g_header_hash,g_header_equal);
+  }
+
 }
 
+
+
 void
 proto_register_ntlmssp(void)
 {
@@ -1609,7 +2362,7 @@
     { &hf_ntlmssp_negotiate_flags_40000,
       { "Target Type Share", "ntlmssp.targettypeshare", FT_BOOLEAN, 32, TFS (&flags_set_truth), NTLMSSP_TARGET_TYPE_SHARE, "", HFILL }},
     { &hf_ntlmssp_negotiate_flags_80000,
-      { "Negotiate NTLM2 key", "ntlmssp.negotiatentlm2", FT_BOOLEAN, 32, TFS (&flags_set_truth), NTLMSSP_NEGOTIATE_NTLM2, "", HFILL }},
+      { "Negotiate Extended Security", "ntlmssp.negotiatentlm2", FT_BOOLEAN, 32, TFS (&flags_set_truth), NTLMSSP_NEGOTIATE_EXTENDED_SECURITY, "", HFILL }},
     { &hf_ntlmssp_negotiate_flags_100000,
       { "Negotiate Identify", "ntlmssp.negotiateidentify", FT_BOOLEAN, 32, TFS (&flags_set_truth), NTLMSSP_NEGOTIATE_IDENTIFY, "", HFILL }},
     { &hf_ntlmssp_negotiate_flags_200000,
@@ -1650,8 +2403,10 @@
       { "Calling workstation domain buffer", "ntlmssp.negotiate.domain.buffer", FT_UINT32, BASE_HEX, NULL, 0x0, "", HFILL }},
     { &hf_ntlmssp_negotiate_domain,
       { "Calling workstation domain", "ntlmssp.negotiate.domain", FT_STRING, BASE_NONE, NULL, 0x0, "", HFILL }},
-    { &hf_ntlmssp_ntlm_challenge,
-      { "NTLM Challenge", "ntlmssp.ntlmchallenge", FT_BYTES, BASE_HEX, NULL, 0x0, "", HFILL }},
+    { &hf_ntlmssp_ntlm_client_challenge,
+      { "NTLM Client Challenge", "ntlmssp.ntlmclientchallenge", FT_BYTES, BASE_HEX, NULL, 0x0, "", HFILL }},
+    { &hf_ntlmssp_ntlm_server_challenge,
+      { "NTLM Server Challenge", "ntlmssp.ntlmserverchallenge", FT_BYTES, BASE_HEX, NULL, 0x0, "", HFILL }},
     { &hf_ntlmssp_reserved,
       { "Reserved", "ntlmssp.reserved", FT_BYTES, BASE_HEX, NULL, 0x0, "", HFILL }},
     { &hf_ntlmssp_challenge_domain,
@@ -1712,12 +2467,14 @@
       { "Verifier Body", "ntlmssp.verf.body", FT_BYTES, BASE_NONE, NULL, 0x0, "", HFILL }},
     { &hf_ntlmssp_decrypted_payload,
       { "NTLM Decrypted Payload", "ntlmssp.decrypted_payload", FT_BYTES, BASE_HEX, NULL, 0x0, "", HFILL }},
-    { &hf_ntlmssp_verf_unknown1,
-      { "Unknown 1", "ntlmssp.verf.unknown1", FT_UINT32, BASE_HEX, NULL, 0x0, "", HFILL }},
+    { &hf_ntlmssp_verf_randompad,
+      { "Random Pad", "ntlmssp.verf.randompad", FT_UINT32, BASE_HEX, NULL, 0x0, "", HFILL }},
     { &hf_ntlmssp_verf_crc32,
       { "Verifier CRC32", "ntlmssp.verf.crc32", FT_UINT32, BASE_HEX, NULL, 0x0, "", HFILL }},
     { &hf_ntlmssp_verf_sequence,
       { "Verifier Sequence Number", "ntlmssp.verf.sequence", FT_UINT32, BASE_DEC, NULL, 0x0, "", HFILL }},
+    { &hf_ntlmssp_verf_hmacmd5,
+      { "HMAC MD5", "ntlmssp.verf.hmacmd5", FT_BYTES, BASE_HEX, NULL, 0x0, "", HFILL }},
     { &hf_ntlmssp_ntlmv2_response,
       { "NTLMv2 Response", "ntlmssp.ntlmv2response", FT_BYTES, BASE_HEX, NULL, 0x0, "", HFILL }},
     { &hf_ntlmssp_ntlmv2_response_hmac,
@@ -1733,11 +2490,13 @@
     { &hf_ntlmssp_ntlmv2_response_unknown,
       { "Unknown", "ntlmssp.ntlmv2response.unknown", FT_UINT32, BASE_HEX, NULL, 0x0, "", HFILL }},
     { &hf_ntlmssp_ntlmv2_response_name,
-      { "Name", "ntlmssp.ntlmv2response.name", FT_STRING, BASE_NONE, NULL, 0x0, "", HFILL }},
+      { "Attribute", "ntlmssp.ntlmv2response.name", FT_STRING, BASE_NONE, NULL, 0x0, "", HFILL }},
     { &hf_ntlmssp_ntlmv2_response_name_type,
-      { "Name type", "ntlmssp.ntlmv2response.name.type", FT_UINT32, BASE_DEC, VALS(ntlm_name_types), 0x0, "", HFILL }},
+      { "Attribute type", "ntlmssp.ntlmv2response.name.type", FT_UINT32, BASE_DEC, VALS(ntlm_name_types), 0x0, "", HFILL }},
     { &hf_ntlmssp_ntlmv2_response_name_len,
-      { "Name len", "ntlmssp.ntlmv2response.name.len", FT_UINT32, BASE_DEC, NULL, 0x0, "", HFILL }},
+      { "Value len", "ntlmssp.ntlmv2response.name.len", FT_UINT32, BASE_DEC, NULL, 0x0, "", HFILL }},
+    { &hf_ntlmssp_ntlmv2_response_restriction,
+      { "Encoding restrictions", "ntlmssp.ntlmv2response.name.restrictions", FT_BYTES, BASE_HEX, NULL, 0x0, "", HFILL }},
     { &hf_ntlmssp_ntlmv2_response_client_time,
       { "Client Time", "ntlmssp.ntlmv2response.client_time", FT_ABSOLUTE_TIME, BASE_NONE, NULL, 0, "", HFILL }}
   };
@@ -1772,6 +2531,7 @@
 				   &nt_password);
 
   register_dissector("ntlmssp", dissect_ntlmssp, proto_ntlmssp);
+  new_register_dissector("ntlmssp_payload", dissect_ntlmssp_payload, proto_ntlmssp);
   new_register_dissector("ntlmssp_verf", dissect_ntlmssp_verf, proto_ntlmssp);
 }
 
--- epan/dissectors/packet-gssapi.c	2009-02-08 19:13:58.000000000 +0300
+++ ../wireshark-1.1.3-SVN-27393/epan/dissectors/packet-gssapi.c	2009-02-25 20:58:16.171352121 +0300
@@ -112,6 +112,7 @@
  */
 
 static dissector_handle_t ntlmssp_handle;
+static dissector_handle_t ntlmssp_payload_handle;
 static dissector_handle_t spnego_krb5_wrap_handle;
 
 static GHashTable *gssapi_oids;
@@ -315,6 +316,15 @@
 						   pinfo, subtree);
 		    goto done;
 		  }
+		  /* Maybe it's new NTLMSSP payload */
+		  if ((tvb_length_remaining(gss_tvb, start_offset)>16) &&
+		      ((tvb_memeql(gss_tvb, start_offset, "\x01\x00\x00\x00", 4) == 0))) {
+		    return_offset = call_dissector(ntlmssp_payload_handle,
+						   tvb_new_subset(gss_tvb, start_offset, -1, -1),
+						   pinfo, subtree);
+        pinfo->gssapi_data_encrypted = TRUE;
+		    goto done;
+		  }
 
 		  /* Maybe it's new GSSKRB5 CFX Wrapping */
 		  if ((tvb_length_remaining(gss_tvb, start_offset)>2) &&
@@ -630,6 +640,7 @@
 	dissector_handle_t gssapi_handle;
 
 	ntlmssp_handle = find_dissector("ntlmssp");
+	ntlmssp_payload_handle = find_dissector("ntlmssp_payload");
 	spnego_krb5_wrap_handle = find_dissector("spnego-krb5-wrap");
 
 	register_dcerpc_auth_subdissector(DCE_C_AUTHN_LEVEL_CONNECT,


More information about the samba-technical mailing list