Don't remove a preference, make it obsolete instead.
[obnox/wireshark/wip.git] / asn1 / ldap / packet-ldap-template.c
index e13b0a7445a83c841df26bf58b4fb9dab32c7292..fe301370dda6517680e8dd1edfe40647b1c4610f 100644 (file)
 #include <epan/oid_resolv.h>
 #include <epan/strutil.h>
 #include <epan/dissectors/packet-tcp.h>
+#include <epan/dissectors/packet-windows-common.h>
+#include <epan/dissectors/packet-dcerpc.h>
 
 #include "packet-frame.h"
 #include "packet-ldap.h"
+#include "packet-ntlmssp.h"
 
 #include "packet-ber.h"
 #include "packet-per.h"
@@ -105,6 +108,7 @@ static int hf_ldap_sasl_buffer_length = -1;
 static int hf_ldap_response_in = -1;
 static int hf_ldap_response_to = -1;
 static int hf_ldap_time = -1;
+static int hf_ldap_guid = -1;
 
 static int hf_mscldap_netlogon_type = -1;
 static int hf_mscldap_netlogon_flags = -1;
@@ -130,6 +134,16 @@ static int hf_mscldap_clientsitename = -1;
 static int hf_mscldap_netlogon_version = -1;
 static int hf_mscldap_netlogon_lm_token = -1;
 static int hf_mscldap_netlogon_nt_token = -1;
+static int hf_ldap_sid = -1;
+static int hf_ldap_AccessMask_ADS_CREATE_CHILD = -1;
+static int hf_ldap_AccessMask_ADS_DELETE_CHILD = -1;
+static int hf_ldap_AccessMask_ADS_LIST = -1;
+static int hf_ldap_AccessMask_ADS_SELF_WRITE = -1;
+static int hf_ldap_AccessMask_ADS_READ_PROP = -1;
+static int hf_ldap_AccessMask_ADS_WRITE_PROP = -1;
+static int hf_ldap_AccessMask_ADS_DELETE_TREE = -1;
+static int hf_ldap_AccessMask_ADS_LIST_OBJECT = -1;
+static int hf_ldap_AccessMask_ADS_CONTROL_ACCESS = -1;
 
 #include "packet-ldap-hf.c"
 
@@ -143,10 +157,12 @@ static gint ett_mscldap_netlogon_flags = -1;
 #include "packet-ldap-ett.c"
 
 static dissector_table_t ldap_name_dissector_table=NULL;
+static const char *object_identifier_id = NULL; /* LDAP OID */
 
 /* desegmentation of LDAP */
 static gboolean ldap_desegment = TRUE;
 static guint    ldap_tcp_port = 389;
+
 static gboolean do_protocolop = FALSE;
 static gchar    *attr_type = NULL;
 static gboolean is_binary_attr_type = FALSE;
@@ -157,6 +173,7 @@ static gboolean is_binary_attr_type = FALSE;
 
 static dissector_handle_t gssapi_handle;
 static dissector_handle_t gssapi_wrap_handle;
+static dissector_handle_t ntlmssp_handle = NULL;
 
 
 /* different types of rpc calls ontop of ms cldap */
@@ -200,7 +217,6 @@ typedef struct ldap_conv_info_t {
   GHashTable *unmatched;
   GHashTable *matched;
   gboolean is_mscldap;
-  gboolean first_time;
   guint32  num_results;
 } ldap_conv_info_t;
 static ldap_conv_info_t *ldap_info_items;
@@ -248,8 +264,12 @@ ldap_info_equal_unmatched(gconstpointer k1, gconstpointer k2)
   return key1->messageId==key2->messageId;
 }
 
+/* This string contains the last LDAPString that was decoded */
+static char *attributedesc_string=NULL;
+
 /* This string contains the last AssertionValue that was decoded */
-static char *assertionvalue_string=NULL;
+static char *ldapvalue_string=NULL;
+
 /* if the octet string contain all printable ASCII characters, then
  * display it as a string, othervise just display it in hex.
  */
@@ -273,12 +293,55 @@ dissect_ldap_AssertionValue(gboolean implicit_tag, tvbuff_t *tvb, int offset, pa
                return offset;
        }
 
+
        /*
-        * Check whether the string is printable ASCII or binary.
+        * Some special/wellknown attributes in common LDAP (read AD)
+        * are neither ascii strings nor blobs of hex data.
+        * Special case these attributes and decode them more nicely.
+        *
+        * Add more special cases as required to prettify further
+        * (there cant be that many ones that are truly interesting)
+        */
+       if(attributedesc_string && !strncmp("DomainSid", attributedesc_string, 9)){
+               tvbuff_t *sid_tvb;
+               char *tmpstr;
+
+               /* this octet string contains an NT SID */
+               sid_tvb=tvb_new_subset(tvb, offset, len, len);
+               dissect_nt_sid(sid_tvb, 0, tree, "SID", &tmpstr, hf_index);
+               ldapvalue_string=tmpstr;
+
+               goto finished;
+       } else if ( (len==16) /* GUIDs are always 16 bytes */
+       && (attributedesc_string && !strncmp("DomainGuid", attributedesc_string, 10))) {
+               guint8 drep[4] = { 0x10, 0x00, 0x00, 0x00}; /* fake DREP struct */
+               e_uuid_t uuid;
+
+               /* This octet string contained a GUID */
+               dissect_dcerpc_uuid_t(tvb, offset, pinfo, tree, drep, hf_ldap_guid, &uuid);
+
+               ldapvalue_string=ep_alloc(1024);
+               g_snprintf(ldapvalue_string, 1023, "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
+                          uuid.Data1, uuid.Data2, uuid.Data3,
+                          uuid.Data4[0], uuid.Data4[1],
+                          uuid.Data4[2], uuid.Data4[3],
+                          uuid.Data4[4], uuid.Data4[5],
+                          uuid.Data4[6], uuid.Data4[7]);
+
+               goto finished;
+       }
+
+       /*
+        * It was not one of our "wellknown" attributes so make the best
+        * we can and just try to see if it is an ascii string or if it
+        * is a binary blob.
         *
         * XXX - should we support reading RFC 2252-style schemas
         * for LDAP, and using that to determine how to display
         * attribute values and assertion values?
+        *
+        * -- I dont think there are full schemas available that describe the
+        *  interesting cases i.e. AD -- ronnie
         */
        str=tvb_get_ptr(tvb, offset, len);
        is_ascii=TRUE;
@@ -291,27 +354,26 @@ dissect_ldap_AssertionValue(gboolean implicit_tag, tvbuff_t *tvb, int offset, pa
 
        /* convert the string into a printable string */
        if(is_ascii){
-               assertionvalue_string=ep_alloc(len+1);
-               memcpy(assertionvalue_string,str,len);
-               assertionvalue_string[i]=0;
+               ldapvalue_string=ep_alloc(len+1);
+               memcpy(ldapvalue_string,str,len);
+               ldapvalue_string[i]=0;
        } else {
-               assertionvalue_string=ep_alloc(3*len);
+               ldapvalue_string=ep_alloc(3*len);
                for(i=0;i<len;i++){
-                       g_snprintf(assertionvalue_string+i*3,3,"%02x",str[i]&0xff);
-                       assertionvalue_string[3*i+2]=':';
+                       g_snprintf(ldapvalue_string+i*3,3,"%02x",str[i]&0xff);
+                       ldapvalue_string[3*i+2]=':';
                }
-               assertionvalue_string[3*len-1]=0;
+               ldapvalue_string[3*len-1]=0;
        }
 
-       proto_tree_add_string(tree, hf_index, tvb, offset, len, assertionvalue_string);
-       offset+=len;
+       proto_tree_add_string(tree, hf_index, tvb, offset, len, ldapvalue_string);
+
 
+finished:
+       offset+=len;
        return offset;
 }
 
-/* This string contains the last LDAPString that was decoded */
-static char *attributedesc_string=NULL;
-
 /* This string contains the last Filter item that was decoded */
 static char *Filter_string=NULL;
 static char *and_filter_string=NULL;
@@ -458,13 +520,18 @@ ldap_match_call_response(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, gu
     /* we have found a match */
 
     if(lcrp){
+      proto_item *it;
+
       if(lcrp->is_request){
-        proto_tree_add_uint(tree, hf_ldap_response_in, tvb, 0, 0, lcrp->rep_frame);
+        it=proto_tree_add_uint(tree, hf_ldap_response_in, tvb, 0, 0, lcrp->rep_frame);
+        PROTO_ITEM_SET_GENERATED(it);
       } else {
         nstime_t ns;
-        proto_tree_add_uint(tree, hf_ldap_response_to, tvb, 0, 0, lcrp->req_frame);
+        it=proto_tree_add_uint(tree, hf_ldap_response_to, tvb, 0, 0, lcrp->req_frame);
+        PROTO_ITEM_SET_GENERATED(it);
         nstime_delta(&ns, &pinfo->fd->abs_ts, &lcrp->req_time);
-        proto_tree_add_time(tree, hf_ldap_time, tvb, 0, 0, &ns);
+        it=proto_tree_add_time(tree, hf_ldap_time, tvb, 0, 0, &ns);
+        PROTO_ITEM_SET_GENERATED(it);
       }
     }
 
@@ -479,7 +546,6 @@ dissect_ldap_payload(tvbuff_t *tvb, packet_info *pinfo,
                     gboolean rest_is_pad, gboolean is_mscldap)
 {
   int offset = 0;
-  gboolean first_time = TRUE;
   guint length_remaining;
   guint msg_len = 0;
   int messageOffset = 0;
@@ -490,12 +556,6 @@ dissect_ldap_payload(tvbuff_t *tvb, packet_info *pinfo,
   gboolean pc, ind = 0;
   gint32 ber_tag;
 
-  while (tvb_reported_length_remaining(tvb, offset) > 0) {
-    /*
-     * This will throw an exception if we don't have any data left.
-     * That's what we want.  (See "tcp_dissect_pdus()", which is
-     * similar)
-     */
     length_remaining = tvb_ensure_length_remaining(tvb, offset);
 
     if (rest_is_pad && length_remaining < 6) return;
@@ -556,8 +616,6 @@ dissect_ldap_payload(tvbuff_t *tvb, packet_info *pinfo,
      * Now dissect the LDAP message.
      */
 
-    /*dissect_ldap_message(msg_tvb, 0, pinfo, msg_tree, msg_item, first_time, ldap_info, is_mscldap);*/
-       ldap_info->first_time= first_time;
        ldap_info->is_mscldap = is_mscldap;
        pinfo->private_data = ldap_info;
        dissect_LDAPMessage_PDU(msg_tvb, pinfo, tree);
@@ -565,8 +623,6 @@ dissect_ldap_payload(tvbuff_t *tvb, packet_info *pinfo,
 
     offset += msg_len;
 
-    first_time = FALSE;
-  }
 }
 
 static void
@@ -630,17 +686,6 @@ dissect_ldap_pdu(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, gboolean i
     }
   }
 
-  while (tvb_reported_length_remaining(tvb, offset) > 0) {
-
-    /*
-     * This will throw an exception if we don't have any data left.
-     * That's what we want.  (See "tcp_dissect_pdus()", which is
-     * similar, but doesn't have to deal with the SASL issues.
-     * XXX - can we make "tcp_dissect_pdus()" provide enough information
-     * to the "get_pdu_len" routine so that we could have one dealing
-     * with the SASL issues, have that routine deal with SASL and
-     * ASN.1, and just use "tcp_dissect_pdus()"?)
-     */
     length_remaining = tvb_ensure_length_remaining(tvb, offset);
 
     /* It might still be a packet containing a SASL security layer
@@ -849,10 +894,7 @@ dissect_ldap_pdu(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, gboolean i
     } else {
        /* plain LDAP, so dissect the payload */
        dissect_ldap_payload(tvb, pinfo, ldap_tree, ldap_info, FALSE, is_mscldap);
-       /* dissect_ldap_payload() has it's own loop so go out here */
-       break;
     }
-  }
 }
 
 static int dissect_mscldap_string(tvbuff_t *tvb, int offset, char *str, int maxlen, gboolean prepend_dot)
@@ -1086,7 +1128,7 @@ static void dissect_NetLogon_PDU(tvbuff_t *tvb, packet_info *pinfo, proto_tree *
 
 
 static guint
-get_sasl_ldap_pdu_len(tvbuff_t *tvb, int offset)
+get_sasl_ldap_pdu_len(packet_info *pinfo _U_, tvbuff_t *tvb, int offset)
 {
        /* sasl encapsulated ldap is 4 bytes plus the length in size */
        return tvb_get_ntohl(tvb, offset)+4;
@@ -1100,18 +1142,18 @@ dissect_sasl_ldap_pdu(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
 }
 
 static guint
-get_normal_ldap_pdu_len(tvbuff_t *tvb, int offset)
+get_normal_ldap_pdu_len(packet_info *pinfo _U_, tvbuff_t *tvb, int offset)
 {
        guint32 len;
        gboolean ind;
        int data_offset;
 
        /* normal ldap is tag+len bytes plus the length
-        * offset==0 is where the tag is
-        * offset==1 is where length starts
+        * offset is where the tag is
+        * offset+1 is where length starts
         */
-       data_offset=get_ber_length(NULL, tvb, 1, &len, &ind);
-       return len+data_offset;
+       data_offset=get_ber_length(NULL, tvb, offset+1, &len, &ind);
+       return len+data_offset-offset;
 }
 
 static void
@@ -1121,73 +1163,218 @@ dissect_normal_ldap_pdu(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
        return;
 }
 
+static void
+dissect_ldap_oid(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
+{
+       char *oid;
+       const char *oidname;
+
+       /* tvb here contains an ascii string that is really an oid */
+/* XXX   we should convert the string oid into a real oid so we can use
+ *       proto_tree_add_oid() instead.
+ */
+
+       oid=tvb_get_ephemeral_string(tvb, 0, tvb_length(tvb));
+       if(!oid){
+               return;
+       }
+
+       oidname=get_oid_str_name(oid);
+
+       if(oidname){
+               proto_tree_add_text(tree, tvb, 0, tvb_length(tvb), "OID: %s (%s)",oid,oidname);
+       } else {
+               proto_tree_add_text(tree, tvb, 0, tvb_length(tvb), "OID: %s",oid);
+       }
+}
+
+#define LDAP_ACCESSMASK_ADS_CREATE_CHILD       0x00000001
+static const true_false_string ldap_AccessMask_ADS_CREATE_CHILD_tfs = {
+   "ADS CREATE CHILD is SET",
+   "Ads create child is NOT set",
+};
+
+#define LDAP_ACCESSMASK_ADS_DELETE_CHILD       0x00000002
+static const true_false_string ldap_AccessMask_ADS_DELETE_CHILD_tfs = {
+   "ADS DELETE CHILD is SET",
+   "Ads delete child is NOT set",
+};
+#define LDAP_ACCESSMASK_ADS_LIST               0x00000004
+static const true_false_string ldap_AccessMask_ADS_LIST_tfs = {
+   "ADS LIST is SET",
+   "Ads list is NOT set",
+};
+#define LDAP_ACCESSMASK_ADS_SELF_WRITE         0x00000008
+static const true_false_string ldap_AccessMask_ADS_SELF_WRITE_tfs = {
+   "ADS SELF WRITE is SET",
+   "Ads self write is NOT set",
+};
+#define LDAP_ACCESSMASK_ADS_READ_PROP          0x00000010
+static const true_false_string ldap_AccessMask_ADS_READ_PROP_tfs = {
+   "ADS READ PROP is SET",
+   "Ads read prop is NOT set",
+};
+#define LDAP_ACCESSMASK_ADS_WRITE_PROP         0x00000020
+static const true_false_string ldap_AccessMask_ADS_WRITE_PROP_tfs = {
+   "ADS WRITE PROP is SET",
+   "Ads write prop is NOT set",
+};
+#define LDAP_ACCESSMASK_ADS_DELETE_TREE                0x00000040
+static const true_false_string ldap_AccessMask_ADS_DELETE_TREE_tfs = {
+   "ADS DELETE TREE is SET",
+   "Ads delete tree is NOT set",
+};
+#define LDAP_ACCESSMASK_ADS_LIST_OBJECT                0x00000080
+static const true_false_string ldap_AccessMask_ADS_LIST_OBJECT_tfs = {
+   "ADS LIST OBJECT is SET",
+   "Ads list object is NOT set",
+};
+#define LDAP_ACCESSMASK_ADS_CONTROL_ACCESS     0x00000100
+static const true_false_string ldap_AccessMask_ADS_CONTROL_ACCESS_tfs = {
+   "ADS CONTROL ACCESS is SET",
+   "Ads control access is NOT set",
+};
 
 static void
-dissect_ldap(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
+ldap_specific_rights(tvbuff_t *tvb, gint offset, proto_tree *tree, guint32 access)
 {
+       proto_tree_add_boolean(tree, hf_ldap_AccessMask_ADS_CONTROL_ACCESS, tvb, offset, 4, access);
+
+       proto_tree_add_boolean(tree, hf_ldap_AccessMask_ADS_LIST_OBJECT, tvb, offset, 4, access);
+
+       proto_tree_add_boolean(tree, hf_ldap_AccessMask_ADS_DELETE_TREE, tvb, offset, 4, access);
+
+       proto_tree_add_boolean(tree, hf_ldap_AccessMask_ADS_WRITE_PROP, tvb, offset, 4, access);
+
+       proto_tree_add_boolean(tree, hf_ldap_AccessMask_ADS_READ_PROP, tvb, offset, 4, access);
+
+       proto_tree_add_boolean(tree, hf_ldap_AccessMask_ADS_SELF_WRITE, tvb, offset, 4, access);
+
+       proto_tree_add_boolean(tree, hf_ldap_AccessMask_ADS_LIST, tvb, offset, 4, access);
+
+       proto_tree_add_boolean(tree, hf_ldap_AccessMask_ADS_DELETE_CHILD, tvb, offset, 4, access);
+
+       proto_tree_add_boolean(tree, hf_ldap_AccessMask_ADS_CREATE_CHILD, tvb, offset, 4, access);
+}
+struct access_mask_info ldap_access_mask_info = {
+       "LDAP",                 /* Name of specific rights */
+       ldap_specific_rights,   /* Dissection function */
+       NULL,                   /* Generic mapping table */
+       NULL                    /* Standard mapping table */
+};
+
+static void
+dissect_ldap_nt_sec_desc(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
+{
+       dissect_nt_sec_desc(tvb, 0, pinfo, tree, NULL, TRUE, tvb_length(tvb), &ldap_access_mask_info);
+}
+
+static void
+dissect_ldap_sid(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
+{
+       char *tmpstr;
+
+       /* this octet string contains an NT SID */
+       dissect_nt_sid(tvb, 0, tree, "SID", &tmpstr, hf_ldap_sid);
+       ldapvalue_string=tmpstr;
+}
+
+static void
+dissect_ldap_guid(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
+{
+       guint8 drep[4] = { 0x10, 0x00, 0x00, 0x00}; /* fake DREP struct */
+       e_uuid_t uuid;
+
+       /* This octet string contained a GUID */
+       dissect_dcerpc_uuid_t(tvb, 0, pinfo, tree, drep, hf_ldap_guid, &uuid);
+
+       ldapvalue_string=ep_alloc(1024);
+       g_snprintf(ldapvalue_string, 1023, "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
+                   uuid.Data1, uuid.Data2, uuid.Data3,
+                   uuid.Data4[0], uuid.Data4[1],
+                   uuid.Data4[2], uuid.Data4[3],
+                   uuid.Data4[4], uuid.Data4[5],
+                   uuid.Data4[6], uuid.Data4[7]);
+}
+
+static void
+dissect_ldap_tcp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
+{
+       guint32 sasl_len;
+       guint32 gss_len;
+       guint32 ldap_len;
+       int offset;
+       gboolean ind;
+
         ldm_tree = NULL;
 
-       /* Here we must take care of reassembly but this is tricky since
-        * depending on whether SASL is present or not, the heuristics
-        * will be very different.
+       /* This is a bit tricky. We have to find out whether SASL is used
+        * so that we know how big a header we are supposed to pass
+        * to tcp_dissect_pdus()
         */
-       if(ldap_desegment && (tvb_length(tvb)==tvb_reported_length(tvb))){
-               guint32 len;
-
-               /* check for a SASL header, i.e. four byte integer where the
-                * first two bytes are 0x00 and the value is <64k and >2
-                * (>2 to fight false positives, 0x00000000 is a common
-                *     "random" tcp payload)
-                * (no SASL ldap PDUs are ever going to be >64k in size?)
-                *
-                * Following the SASL header is a GSSAPI blob so the next byte
-                * is always 0x60. (only true for MS SASL LDAP, there are other
-                * blobs that may follow in real-world)
-                */
-               len=tvb_get_ntohl(tvb, 0);
-               if( (len<65535)
-               &&  (len>2)
-               &&  (tvb_get_guint8(tvb, 4)==0x60)){
-                       if(len<=tvb_length_remaining(tvb, 4)){
-                               /* we have a full ldap pdu */
-                               dissect_ldap_pdu(tvb, pinfo, tree, FALSE);
-                               return;
-                       } else {
-                               /* we have to do reassembly */
-                               tcp_dissect_pdus(tvb, pinfo, tree, ldap_desegment, 4, get_sasl_ldap_pdu_len, dissect_sasl_ldap_pdu);
-                               return;
-                       }
-               }
-               /* check if it is a normal BER encoded LDAP packet
-                * i.e. first byte is 0x30 followed by a length that is
-                * <64k
-                * (no ldap PDUs are ever >64kb? )
-                */
-               if(tvb_get_guint8(tvb, 0)==0x30){
-                       gboolean ind;
-                       int data_offset;
-
-                       /* check that length makes sense */
-                       data_offset=get_ber_length(NULL, tvb, 1, &len, &ind);
-
-                       /* dont check ind since indefinite length is never used for ldap (famous last words)*/
-                       if(len<2 || len>65535){
-                               return;
-                       }
-
-                       if(len<=tvb_length_remaining(tvb, data_offset)){
-                               /* we have a full ldap pdu */
-                               dissect_ldap_pdu(tvb, pinfo, tree, FALSE);
-                               return;
-                       } else {
-                               /* we have to do reassembly */
-                               tcp_dissect_pdus(tvb, pinfo, tree, ldap_desegment, 4, get_normal_ldap_pdu_len, dissect_normal_ldap_pdu);
-                               return;
-                       }
-               }
+       /* check for a SASL header, i.e. assume it is SASL if 
+        * 1, first four bytes (SASL length) is an integer 
+        *    with a value that must be <64k and >2
+        *    (>2 to fight false positives, 0x00000000 is a common
+        *        "random" tcp payload)
+        * (no SASL ldap PDUs are ever going to be >64k in size?)
+        *
+        * Following the SASL header is a GSSAPI blob so the next byte
+        * is always 0x60. (only true for MS SASL LDAP, there are other
+        * blobs that may follow in real-world)
+        *
+        * 2, Then one byte with the value 0x60 indicating the GSSAPI blob
+        *
+        * 3, Then X bytes describing the BER encoded lengtyh of the blob.
+        *    This length should point to the same end-of-pdu as 1,
+        *
+        * 4, finally a byte 0x06 indicating that the next object is an OID
+        */
+       sasl_len=tvb_get_ntohl(tvb, 0);
+       if( sasl_len<2 ){
+               goto this_was_not_sasl;
        }
 
-       dissect_ldap_pdu(tvb, pinfo, tree, FALSE);
+       if(tvb_get_guint8(tvb, 4)!=0x60){
+               goto this_was_not_sasl;
+       }
+               
+       offset=get_ber_length(NULL, tvb, 5, &gss_len, &ind);
+       if(sasl_len!=(gss_len+offset-4)){
+               goto this_was_not_sasl;
+       }
+
+       if(tvb_get_guint8(tvb, offset)!=0x06){
+               goto this_was_not_sasl;
+       }
+
+       tcp_dissect_pdus(tvb, pinfo, tree, ldap_desegment, 4, get_sasl_ldap_pdu_len, dissect_sasl_ldap_pdu);
+
+
+this_was_not_sasl:
+       /* check if it is a normal BER encoded LDAP packet
+        * i.e. first byte is 0x30 followed by a length that is
+        * <64k
+        * (no ldap PDUs are ever >64kb? )
+        */
+       if(tvb_get_guint8(tvb, 0)!=0x30){
+               goto this_was_not_normal_ldap;
+       }
+
+       /* check that length makes sense */
+       offset=get_ber_length(NULL, tvb, 1, &ldap_len, &ind);
+
+       /* dont check ind since indefinite length is never used for ldap (famous last words)*/
+       if(ldap_len<2){
+               goto this_was_not_normal_ldap;
+       }
+
+       tcp_dissect_pdus(tvb, pinfo, tree, ldap_desegment, 4, get_normal_ldap_pdu_len, dissect_normal_ldap_pdu);
+
+
+this_was_not_normal_ldap:
+
        return;
 }
 
@@ -1330,6 +1517,11 @@ void proto_register_ldap(void) {
         FT_STRING, BASE_NONE, NULL, 0x0,
         "Client Site name", HFILL }},
 
+    { &hf_ldap_sid,
+      { "Sid", "ldap.sid",
+        FT_STRING, BASE_NONE, NULL, 0x0,
+        "Sid", HFILL }},
+
     { &hf_mscldap_netlogon_flags_pdc,
       { "PDC", "mscldap.netlogon.flags.pdc", FT_BOOLEAN, 32,
         TFS(&tfs_ads_pdc), 0x00000001, "Is this DC a PDC or not?", HFILL }},
@@ -1370,6 +1562,37 @@ void proto_register_ldap(void) {
       { "NDNC", "mscldap.netlogon.flags.ndnc", FT_BOOLEAN, 32,
         TFS(&tfs_ads_ndnc), 0x00000400, "Is this an NDNC dc?", HFILL }},
 
+    { &hf_ldap_guid,
+      { "GUID", "ldap.guid", FT_GUID, BASE_NONE,
+        NULL, 0, "GUID", HFILL }},
+
+    { &hf_ldap_AccessMask_ADS_CREATE_CHILD, 
+         { "Create Child", "ldap.AccessMask.ADS_CREATE_CHILD", FT_BOOLEAN, 32, TFS(&ldap_AccessMask_ADS_CREATE_CHILD_tfs), LDAP_ACCESSMASK_ADS_CREATE_CHILD, "", HFILL }},
+
+    { &hf_ldap_AccessMask_ADS_DELETE_CHILD, 
+         { "Delete Child", "ldap.AccessMask.ADS_DELETE_CHILD", FT_BOOLEAN, 32, TFS(&ldap_AccessMask_ADS_DELETE_CHILD_tfs), LDAP_ACCESSMASK_ADS_DELETE_CHILD, "", HFILL }},
+
+    { &hf_ldap_AccessMask_ADS_LIST, 
+         { "List", "ldap.AccessMask.ADS_LIST", FT_BOOLEAN, 32, TFS(&ldap_AccessMask_ADS_LIST_tfs), LDAP_ACCESSMASK_ADS_LIST, "", HFILL }},
+
+    { &hf_ldap_AccessMask_ADS_SELF_WRITE, 
+         { "Self Write", "ldap.AccessMask.ADS_SELF_WRITE", FT_BOOLEAN, 32, TFS(&ldap_AccessMask_ADS_SELF_WRITE_tfs), LDAP_ACCESSMASK_ADS_SELF_WRITE, "", HFILL }},
+
+    { &hf_ldap_AccessMask_ADS_READ_PROP, 
+         { "Read Prop", "ldap.AccessMask.ADS_READ_PROP", FT_BOOLEAN, 32, TFS(&ldap_AccessMask_ADS_READ_PROP_tfs), LDAP_ACCESSMASK_ADS_READ_PROP, "", HFILL }},
+
+    { &hf_ldap_AccessMask_ADS_WRITE_PROP, 
+         { "Write Prop", "ldap.AccessMask.ADS_WRITE_PROP", FT_BOOLEAN, 32, TFS(&ldap_AccessMask_ADS_WRITE_PROP_tfs), LDAP_ACCESSMASK_ADS_WRITE_PROP, "", HFILL }},
+
+    { &hf_ldap_AccessMask_ADS_DELETE_TREE, 
+         { "Delete Tree", "ldap.AccessMask.ADS_DELETE_TREE", FT_BOOLEAN, 32, TFS(&ldap_AccessMask_ADS_DELETE_TREE_tfs), LDAP_ACCESSMASK_ADS_DELETE_TREE, "", HFILL }},
+
+    { &hf_ldap_AccessMask_ADS_LIST_OBJECT, 
+         { "List Object", "ldap.AccessMask.ADS_LIST_OBJECT", FT_BOOLEAN, 32, TFS(&ldap_AccessMask_ADS_LIST_OBJECT_tfs), LDAP_ACCESSMASK_ADS_LIST_OBJECT, "", HFILL }},
+
+    { &hf_ldap_AccessMask_ADS_CONTROL_ACCESS, 
+         { "Control Access", "ldap.AccessMask.ADS_CONTROL_ACCESS", FT_BOOLEAN, 32, TFS(&ldap_AccessMask_ADS_CONTROL_ACCESS_tfs), LDAP_ACCESSMASK_ADS_CONTROL_ACCESS, "", HFILL }},
+
 #include "packet-ldap-hfarr.c"
   };
 
@@ -1393,19 +1616,21 @@ void proto_register_ldap(void) {
   proto_register_subtree_array(ett, array_length(ett));
 
 
-  register_dissector("ldap", dissect_ldap, proto_ldap);
+  register_dissector("ldap", dissect_ldap_tcp, proto_ldap);
 
   ldap_module = prefs_register_protocol(proto_ldap, NULL);
   prefs_register_bool_preference(ldap_module, "desegment_ldap_messages",
     "Reassemble LDAP messages spanning multiple TCP segments",
     "Whether the LDAP dissector should reassemble messages spanning multiple TCP segments."
-    " To use this option, you must also enable \"Allow subdissectors to reassemble TCP streams\" in the TCP protocol settings, and disable \"Verify length\" in the BER protocol settings",
+    "To use this option, you must also enable \"Allow subdissectors to reassemble TCP streams\" in the TCP protocol settings.",
     &ldap_desegment);
 
   prefs_register_uint_preference(ldap_module, "tcp.port", "LDAP TCP Port",
                                 "Set the port for LDAP operations",
                                 10, &ldap_tcp_port);
 
+  prefs_register_obsolete_preference(ldap_module, "max_pdu");
+
   proto_cldap = proto_register_protocol(
          "Connectionless Lightweight Directory Access Protocol",
          "CLDAP", "cldap");
@@ -1415,7 +1640,6 @@ void proto_register_ldap(void) {
 
   ldap_name_dissector_table = register_dissector_table("ldap.name", "LDAP Attribute Type Dissectors", FT_STRING, BASE_NONE);
 
-
 }
 
 
@@ -1424,7 +1648,7 @@ void
 proto_reg_handoff_ldap(void)
 {
        dissector_handle_t ldap_handle, cldap_handle;
-       ldap_handle = create_dissector_handle(dissect_ldap, proto_ldap);
+       ldap_handle = create_dissector_handle(dissect_ldap_tcp, proto_ldap);
 
        dissector_add("tcp.port", ldap_tcp_port, ldap_handle);
        dissector_add("tcp.port", TCP_PORT_GLOBALCAT_LDAP, ldap_handle);
@@ -1435,15 +1659,20 @@ proto_reg_handoff_ldap(void)
        gssapi_handle = find_dissector("gssapi");
        gssapi_wrap_handle = find_dissector("gssapi_verf");
 
+       ntlmssp_handle = find_dissector("ntlmssp");
+
 /*  http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dsml/dsml/ldap_controls_and_session_support.asp */
        add_oid_str_name("1.2.840.113556.1.4.319","LDAP_PAGED_RESULT_OID_STRING");
        add_oid_str_name("1.2.840.113556.1.4.417","LDAP_SERVER_SHOW_DELETED_OID");
        add_oid_str_name("1.2.840.113556.1.4.473","LDAP_SERVER_SORT_OID");
+       add_oid_str_name("1.2.840.113556.1.4.474","LDAP_CONTROL_SORT_RESP_OID");
        add_oid_str_name("1.2.840.113556.1.4.521","LDAP_SERVER_CROSSDOM_MOVE_TARGET_OID");
        add_oid_str_name("1.2.840.113556.1.4.528","LDAP_SERVER_NOTIFICATION_OID");
        add_oid_str_name("1.2.840.113556.1.4.529","LDAP_SERVER_EXTENDED_DN_OID");
        add_oid_str_name("1.2.840.113556.1.4.619","LDAP_SERVER_LAZY_COMMIT_OID");
+       add_oid_str_name("1.2.840.113556.1.4.800","LDAP_CAP_ACTIVE_DIRECTORY_OID");
        add_oid_str_name("1.2.840.113556.1.4.801","LDAP_SERVER_SD_FLAGS_OID");
+       add_oid_str_name("1.2.840.113556.1.4.804","LDAP_OID_COMPARATOR_OR");
        add_oid_str_name("1.2.840.113556.1.4.805","LDAP_SERVER_TREE_DELETE_OID");
        add_oid_str_name("1.2.840.113556.1.4.841","LDAP_SERVER_DIRSYNC_OID");
        add_oid_str_name("1.2.840.113556.1.4.970 ","None");
@@ -1452,12 +1681,24 @@ proto_reg_handoff_ldap(void)
        add_oid_str_name("1.2.840.113556.1.4.1340","LDAP_SERVER_SEARCH_OPTIONS_OID");
        add_oid_str_name("1.2.840.113556.1.4.1413","LDAP_SERVER_PERMISSIVE_MODIFY_OID");
        add_oid_str_name("1.2.840.113556.1.4.1504","LDAP_SERVER_ASQ_OID");
+       add_oid_str_name("1.2.840.113556.1.4.1670","LDAP_CAP_ACTIVE_DIRECTORY_V51_OID");
        add_oid_str_name("1.2.840.113556.1.4.1781","LDAP_SERVER_FAST_BIND_OID");
+       add_oid_str_name("1.2.840.113556.1.4.1791","LDAP_CAP_ACTIVE_DIRECTORY_LDAP_INTEG_OID");
+       add_oid_str_name("1.2.840.113556.1.4.1851","LDAP_CAP_ACTIVE_DIRECTORY_ADAM_OID");
        add_oid_str_name("1.3.6.1.4.1.1466.101.119.1","None");
        add_oid_str_name("1.3.6.1.4.1.1466.20037","LDAP_START_TLS_OID");
        add_oid_str_name("2.16.840.1.113730.3.4.9","LDAP_CONTROL_VLVREQUEST VLV");
+       add_oid_str_name("2.16.840.1.113730.3.4.10","LDAP_CONTROL_VLVRESPONSE VLV");
 
        register_ldap_name_dissector("netlogon", dissect_NetLogon_PDU, proto_cldap);
+       register_ldap_name_dissector("objectGUID", dissect_ldap_guid, proto_ldap);
+       register_ldap_name_dissector("supportedControl", dissect_ldap_oid, proto_ldap);
+       register_ldap_name_dissector("supportedCapabilities", dissect_ldap_oid, proto_ldap);
+       register_ldap_name_dissector("objectSid", dissect_ldap_sid, proto_ldap);
+       register_ldap_name_dissector("nTSecurityDescriptor", dissect_ldap_nt_sec_desc, proto_ldap);
+
+#include "packet-ldap-dis-tab.c"
+       
 
 }