Don't remove a preference, make it obsolete instead.
[obnox/wireshark/wip.git] / asn1 / ldap / packet-ldap-template.c
index 95aa3e07c143d689c916793eb362629ff80fb58c..fe301370dda6517680e8dd1edfe40647b1c4610f 100644 (file)
@@ -5,8 +5,8 @@
  *
  * $Id$
  *
- * Ethereal - Network traffic analyzer
- * By Gerald Combs <gerald@ethereal.com>
+ * Wireshark - Network traffic analyzer
+ * By Gerald Combs <gerald@wireshark.org>
  * Copyright 1998 Gerald Combs
  *
  * This program is free software; you can redistribute it and/or
@@ -63,7 +63,7 @@
  *
  * Stefan Metzmacher <metze@samba.org>
  *
- * 15-NOV-2005 - Changed to use the asn2eth compiler
+ * 15-NOV-2005 - Changed to use the asn2wrs compiler
  * Anders Broman <anders.broman@ericsson.com>
  */
 
 
 #include <stdio.h>
 #include <string.h>
+#include <ctype.h>
 
 #include <glib.h>
 
 #include <epan/packet.h>
 #include <epan/conversation.h>
 #include <epan/prefs.h>
-#include <epan/conversation.h>
 #include <epan/tap.h>
 #include <epan/emem.h>
+#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"
 #define PSNAME "LDAP"
 #define PFNAME "ldap"
 
-
-
-static dissector_handle_t ldap_handle=NULL;
-
 /* Initialize the protocol and registered fields */
 static int ldap_tap = -1;
 static int proto_ldap = -1;
 static int proto_cldap = -1;
 
 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;
+static int hf_mscldap_netlogon_flags_pdc = -1;
+static int hf_mscldap_netlogon_flags_gc = -1;
+static int hf_mscldap_netlogon_flags_ldap = -1;
+static int hf_mscldap_netlogon_flags_ds = -1;
+static int hf_mscldap_netlogon_flags_kdc = -1;
+static int hf_mscldap_netlogon_flags_timeserv = -1;
+static int hf_mscldap_netlogon_flags_closest = -1;
+static int hf_mscldap_netlogon_flags_writable = -1;
+static int hf_mscldap_netlogon_flags_good_timeserv = -1;
+static int hf_mscldap_netlogon_flags_ndnc = -1;
+static int hf_mscldap_domain_guid = -1;
+static int hf_mscldap_forest = -1;
+static int hf_mscldap_domain = -1;
+static int hf_mscldap_hostname = -1;
+static int hf_mscldap_nb_domain = -1;
+static int hf_mscldap_nb_hostname = -1;
+static int hf_mscldap_username = -1;
+static int hf_mscldap_sitename = -1;
+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"
 
@@ -111,11 +152,20 @@ static gint ett_ldap = -1;
 static gint ett_ldap_msg = -1;
 static gint ett_ldap_sasl_blob = -1;
 static guint ett_ldap_payload = -1;
+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;
 
 #define TCP_PORT_LDAP                  389
 #define UDP_PORT_CLDAP                 389
@@ -123,12 +173,36 @@ static gboolean ldap_desegment = TRUE;
 
 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 */
 #define        MSCLDAP_RPC_NETLOGON    1
 
-
+/* Message type Choice values */
+static const value_string ldap_ProtocolOp_choice_vals[] = {
+  {   0, "bindRequest" },
+  {   1, "bindResponse" },
+  {   2, "unbindRequest" },
+  {   3, "searchRequest" },
+  {   4, "searchResEntry" },
+  {   5, "searchResDone" },
+  {      6, "searchResRef" },
+  {   7, "modifyRequest" },
+  {   8, "modifyResponse" },
+  {   9, "addRequest" },
+  {  10, "addResponse" },
+  {  11, "delRequest" },
+  {  12, "delResponse" },
+  {  13, "modDNRequest" },
+  {  14, "modDNResponse" },
+  {  15, "compareRequest" },
+  {  16, "compareResponse" },
+  {  17, "abandonRequest" },
+  {  18, "extendedReq" },
+  {  19, "extendedResp" },
+  { 0, NULL }
+};
 /*
  * Data structure attached to a conversation, giving authentication
  * information from a bind request.
@@ -143,7 +217,7 @@ 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;
 
@@ -164,9 +238,11 @@ ldap_info_equal_matched(gconstpointer k1, gconstpointer k2)
   if( key1->req_frame && key2->req_frame && (key1->req_frame!=key2->req_frame) ){
     return 0;
   }
+  /* a response may span multiple frames
   if( key1->rep_frame && key2->rep_frame && (key1->rep_frame!=key2->rep_frame) ){
     return 0;
   }
+  */
 
   return key1->messageId==key2->messageId;
 }
@@ -188,9 +264,279 @@ 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 *ldapvalue_string=NULL;
+
+/* if the octet string contain all printable ASCII characters, then
+ * display it as a string, othervise just display it in hex.
+ */
+static int
+dissect_ldap_AssertionValue(gboolean implicit_tag, tvbuff_t *tvb, int offset, packet_info *pinfo _U_, proto_tree *tree, int hf_index)
+{
+       gint8 class;
+       gboolean pc, ind, is_ascii;
+       gint32 tag;
+       guint32 len, i;
+       const guchar *str;
+
+       if(!implicit_tag){
+               offset=get_ber_identifier(tvb, offset, &class, &pc, &tag);
+               offset=get_ber_length(NULL, tvb, offset, &len, &ind);
+       } else {
+               len=tvb_length_remaining(tvb,offset);
+       }
+
+       if(len==0){
+               return offset;
+       }
+
+
+       /*
+        * 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;
+       for(i=0;i<len;i++){
+               if(!isascii(str[i]) || !isprint(str[i])){
+                       is_ascii=FALSE;
+                       break;
+               }
+       }
+
+       /* convert the string into a printable string */
+       if(is_ascii){
+               ldapvalue_string=ep_alloc(len+1);
+               memcpy(ldapvalue_string,str,len);
+               ldapvalue_string[i]=0;
+       } else {
+               ldapvalue_string=ep_alloc(3*len);
+               for(i=0;i<len;i++){
+                       g_snprintf(ldapvalue_string+i*3,3,"%02x",str[i]&0xff);
+                       ldapvalue_string[3*i+2]=':';
+               }
+               ldapvalue_string[3*len-1]=0;
+       }
+
+       proto_tree_add_string(tree, hf_index, tvb, offset, len, ldapvalue_string);
+
+
+finished:
+       offset+=len;
+       return offset;
+}
+
+/* This string contains the last Filter item that was decoded */
+static char *Filter_string=NULL;
+static char *and_filter_string=NULL;
+static char *or_filter_string=NULL;
+static char *substring_value=NULL;
+static char *substring_item_init=NULL;
+static char *substring_item_any=NULL;
+static char *substring_item_final=NULL;
+static char *matching_rule_string=NULL;
+static gboolean matching_rule_dnattr=FALSE;
+
 /* Global variables */
-guint32 MessageID;
-guint32 AuthenticationChoice;
+char *mechanism = NULL;
+static gint MessageID =-1;
+static gint ProtocolOp = -1;
+static gint result = 0;
+static proto_item *ldm_tree = NULL; /* item to add text to */
+
+static void ldap_do_protocolop(packet_info *pinfo)
+{
+  const gchar* valstr;
+
+  if (do_protocolop)  {
+
+    valstr = val_to_str(ProtocolOp, ldap_ProtocolOp_choice_vals, "Unknown (%%u)");
+
+    if(check_col(pinfo->cinfo, COL_INFO))
+      col_append_fstr(pinfo->cinfo, COL_INFO, "%s(%u) ", valstr, MessageID);
+
+    if(ldm_tree)
+      proto_item_append_text(ldm_tree, " %s(%d)", valstr, MessageID);
+
+    do_protocolop = FALSE;
+
+  }
+}
+
+static ldap_call_response_t *
+ldap_match_call_response(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint messageId, guint protocolOpTag)
+{
+  ldap_call_response_t lcr, *lcrp=NULL;
+  ldap_conv_info_t *ldap_info = (ldap_conv_info_t *)pinfo->private_data;
+
+  /* first see if we have already matched this */
+
+      lcr.messageId=messageId;
+      switch(protocolOpTag){
+        case LDAP_REQ_BIND:
+        case LDAP_REQ_SEARCH:
+        case LDAP_REQ_MODIFY:
+        case LDAP_REQ_ADD:
+        case LDAP_REQ_DELETE:
+        case LDAP_REQ_MODRDN:
+        case LDAP_REQ_COMPARE:
+          lcr.is_request=TRUE;
+          lcr.req_frame=pinfo->fd->num;
+          lcr.rep_frame=0;
+          break;
+        case LDAP_RES_BIND:
+        case LDAP_RES_SEARCH_ENTRY:
+        case LDAP_RES_SEARCH_REF:
+        case LDAP_RES_SEARCH_RESULT:
+        case LDAP_RES_MODIFY:
+        case LDAP_RES_ADD:
+        case LDAP_RES_DELETE:
+        case LDAP_RES_MODRDN:
+        case LDAP_RES_COMPARE:
+          lcr.is_request=FALSE;
+          lcr.req_frame=0;
+          lcr.rep_frame=pinfo->fd->num;
+          break;
+      }
+      lcrp=g_hash_table_lookup(ldap_info->matched, &lcr);
+
+      if(lcrp){
+
+        lcrp->is_request=lcr.is_request;
+
+      } else {
+
+                 /* we haven't found a match - try and match it up */
+
+  switch(protocolOpTag){
+      case LDAP_REQ_BIND:
+      case LDAP_REQ_SEARCH:
+      case LDAP_REQ_MODIFY:
+      case LDAP_REQ_ADD:
+      case LDAP_REQ_DELETE:
+      case LDAP_REQ_MODRDN:
+      case LDAP_REQ_COMPARE:
+
+               /* this a a request - add it to the unmatched list */
+
+        /* check that we dont already have one of those in the
+           unmatched list and if so remove it */
+
+        lcr.messageId=messageId;
+        lcrp=g_hash_table_lookup(ldap_info->unmatched, &lcr);
+        if(lcrp){
+          g_hash_table_remove(ldap_info->unmatched, lcrp);
+        }
+        /* if we cant reuse the old one, grab a new chunk */
+        if(!lcrp){
+          lcrp=se_alloc(sizeof(ldap_call_response_t));
+        }
+        lcrp->messageId=messageId;
+        lcrp->req_frame=pinfo->fd->num;
+        lcrp->req_time=pinfo->fd->abs_ts;
+        lcrp->rep_frame=0;
+        lcrp->protocolOpTag=protocolOpTag;
+        lcrp->is_request=TRUE;
+        g_hash_table_insert(ldap_info->unmatched, lcrp, lcrp);
+        return NULL;
+        break;
+      case LDAP_RES_BIND:
+      case LDAP_RES_SEARCH_ENTRY:
+      case LDAP_RES_SEARCH_REF:
+      case LDAP_RES_SEARCH_RESULT:
+      case LDAP_RES_MODIFY:
+      case LDAP_RES_ADD:
+      case LDAP_RES_DELETE:
+      case LDAP_RES_MODRDN:
+      case LDAP_RES_COMPARE:
+
+               /* this is a result - it should be in our unmatched list */
+
+        lcr.messageId=messageId;
+        lcrp=g_hash_table_lookup(ldap_info->unmatched, &lcr);
+
+        if(lcrp){
+
+          if(!lcrp->rep_frame){
+            g_hash_table_remove(ldap_info->unmatched, lcrp);
+            lcrp->rep_frame=pinfo->fd->num;
+            lcrp->is_request=FALSE;
+            g_hash_table_insert(ldap_info->matched, lcrp, lcrp);
+          }
+        }
+
+        break;
+         }
+
+       }
+    /* we have found a match */
+
+    if(lcrp){
+      proto_item *it;
+
+      if(lcrp->is_request){
+        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;
+        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);
+        it=proto_tree_add_time(tree, hf_ldap_time, tvb, 0, 0, &ns);
+        PROTO_ITEM_SET_GENERATED(it);
+      }
+    }
+
+    return lcrp;
+}
 
 #include "packet-ldap-fn.c"
 
@@ -200,50 +546,20 @@ 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;
   guint headerLength = 0;
   guint length = 0;
   tvbuff_t *msg_tvb = NULL;
-  proto_item *msg_item = NULL;
-  proto_tree *msg_tree = NULL;
   gint8 class;
   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;
 
-    /*
-     * The frame begins
-     * with a "Sequence Of" header.
-     * Can we do reassembly?
-     */
-    if (ldap_desegment && pinfo->can_desegment) {
-        /*
-         * Yes - is the "Sequence Of" header split across segment
-         * boundaries?  We require at least 6 bytes for the header
-         * which allows for a 4 byte length (ASN.1 BER).
-         */
-        if (length_remaining < 6) {
-         /* stop if the caller says that we are given all data and the rest is padding
-          * this is for the SASL GSSAPI case when the data is only signed and not sealed
-          */
-          pinfo->desegment_offset = offset;
-          pinfo->desegment_len = 6 - length_remaining;
-          return;
-        }
-    }
-
     /*
      * OK, try to read the "Sequence Of" header; this gets the total
      * length of the LDAP message.
@@ -278,28 +594,6 @@ dissect_ldap_payload(tvbuff_t *tvb, packet_info *pinfo,
        msg_len = length_remaining;
     }
 
-    /*
-     * Is the message split across segment boundaries?
-     */
-    if (length_remaining < msg_len) {
-        /* provide a hint to TCP where the next PDU starts */
-        pinfo->want_pdu_tracking=2;
-        pinfo->bytes_until_next_pdu= msg_len - length_remaining;
-        /*
-         * Can we do reassembly?
-         */
-        if (ldap_desegment && pinfo->can_desegment) {
-           /*
-            * Yes.  Tell the TCP dissector where the data for this message
-            * starts in the data it handed us, and how many more bytes
-            * we need, and return.
-            */
-           pinfo->desegment_offset = offset;
-           pinfo->desegment_len = msg_len - length_remaining;
-           return;
-        }
-    }
-
     /*
      * Construct a tvbuff containing the amount of the payload we have
      * available.  Make its reported length the amount of data in the
@@ -321,22 +615,14 @@ dissect_ldap_payload(tvbuff_t *tvb, packet_info *pinfo,
     /*
      * Now dissect the LDAP message.
      */
-    if (tree) {
-        msg_item = proto_tree_add_text(tree, msg_tvb, 0, msg_len, "LDAP Message");
-        msg_tree = proto_item_add_subtree(msg_item, ett_ldap_msg);
-    }
 
-    /*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, msg_tree);
+       dissect_LDAPMessage_PDU(msg_tvb, pinfo, tree);
 
 
     offset += msg_len;
 
-    first_time = FALSE;
-  }
 }
 
 static void
@@ -350,6 +636,8 @@ dissect_ldap_pdu(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, gboolean i
   proto_item *ldap_item = NULL;
   proto_tree *ldap_tree = NULL;
 
+  ldm_tree = NULL;
+
   /*
    * Do we have a conversation for this connection?
    */
@@ -361,6 +649,7 @@ dissect_ldap_pdu(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, gboolean i
     conversation = conversation_new(pinfo->fd->num, &pinfo->src, &pinfo->dst,
                                    pinfo->ptype, pinfo->srcport,
                                     pinfo->destport, 0);
+
   }
 
   /*
@@ -377,10 +666,14 @@ dissect_ldap_pdu(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, gboolean i
     ldap_info->first_auth_frame = 0;
     ldap_info->matched=g_hash_table_new(ldap_info_hash_matched, ldap_info_equal_matched);
     ldap_info->unmatched=g_hash_table_new(ldap_info_hash_unmatched, ldap_info_equal_unmatched);
+    ldap_info->num_results = 0;
+
     conversation_add_proto_data(conversation, proto_ldap, ldap_info);
+
     ldap_info->next = ldap_info_items;
     ldap_info_items = ldap_info;
-  } 
+
+  }
 
   switch (ldap_info->auth_type) {
     case LDAP_AUTH_SASL:
@@ -393,40 +686,8 @@ 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);
 
-    /*
-     * Try to find out if we have a plain LDAP buffer
-     * with a "Sequence Of" header or a SASL buffer with
-     * Can we do reassembly?
-     */
-    if (ldap_desegment && pinfo->can_desegment) {
-        /*
-         * Yes - is the "Sequence Of" header split across segment
-         * boundaries?  We require at least 6 bytes for the header
-         * which allows for a 4 byte length (ASN.1 BER).
-        * For the SASL case we need at least 4 bytes, so this is 
-        * no problem here because we check for 6 bytes ans sasl buffers
-        * with less than 2 bytes should not exist...
-         */
-        if (length_remaining < 6) {
-           pinfo->desegment_offset = offset;
-           pinfo->desegment_len = 6 - length_remaining;
-           return;
-        }
-    }
-
     /* It might still be a packet containing a SASL security layer
      * but its just that we never saw the BIND packet.
      * check if it looks like it could be a SASL blob here
@@ -448,7 +709,7 @@ dissect_ldap_pdu(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, gboolean i
     if (check_col(pinfo->cinfo, COL_PROTOCOL)) col_set_str(pinfo->cinfo, COL_PROTOCOL, pinfo->current_proto);
     if (check_col(pinfo->cinfo, COL_INFO)) col_clear(pinfo->cinfo, COL_INFO);
 
-    ldap_item = proto_tree_add_item(tree, proto_ldap, tvb, 0, -1, FALSE);
+    ldap_item = proto_tree_add_item(tree, is_mscldap?proto_cldap:proto_ldap, tvb, 0, -1, FALSE);
     ldap_tree = proto_item_add_subtree(ldap_item, ett_ldap);
 
     /*
@@ -499,28 +760,6 @@ dissect_ldap_pdu(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, gboolean i
         return;
       }
 
-      /*
-       * Is the buffer split across segment boundaries?
-       */
-      if (length_remaining < sasl_msg_len) {
-        /* provide a hint to TCP where the next PDU starts */
-        pinfo->want_pdu_tracking = 2;
-        pinfo->bytes_until_next_pdu= sasl_msg_len - length_remaining;
-        /*
-         * Can we do reassembly?
-         */
-        if (ldap_desegment && pinfo->can_desegment) {
-          /*
-           * Yes.  Tell the TCP dissector where the data for this message
-           * starts in the data it handed us, and how many more bytes we
-           * need, and return.
-           */
-          pinfo->desegment_offset = offset;
-          pinfo->desegment_len = sasl_msg_len - length_remaining;
-          return;
-        }
-      }
-
       /*
        * Construct a tvbuff containing the amount of the payload we have
        * available.  Make its reported length the amount of data in the PDU.
@@ -655,18 +894,490 @@ 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)
+{
+  guint8 len;
+
+  len=tvb_get_guint8(tvb, offset);
+  offset+=1;
+  *str=0;
+
+  while(len){
+    /* add potential field separation dot */
+    if(prepend_dot){
+      if(!maxlen){
+        *str=0;
+        return offset;
+      }
+      maxlen--;
+      *str++='.';
+      *str=0;
+    }
+
+    if(len==0xc0){
+      int new_offset;
+      /* ops its a mscldap compressed string */
+
+      new_offset=tvb_get_guint8(tvb, offset);
+      if (new_offset == offset - 1)
+        THROW(ReportedBoundsError);
+      offset+=1;
+
+      dissect_mscldap_string(tvb, new_offset, str, maxlen, FALSE);
+
+      return offset;
+    }
+
+    prepend_dot=TRUE;
+
+    if(maxlen<=len){
+      if(maxlen>3){
+        *str++='.';
+        *str++='.';
+        *str++='.';
+      }
+      *str=0;
+      return offset; /* will mess up offset in caller, is unlikely */
+    }
+    tvb_memcpy(tvb, str, offset, len);
+    str+=len;
+    *str=0;
+    maxlen-=len;
+    offset+=len;
+
+
+    len=tvb_get_guint8(tvb, offset);
+    offset+=1;
+  }
+  *str=0;
+  return offset;
+}
+
+/* These flag bits were found to be defined in the samba sources.
+ * I hope they are correct (but have serious doubts about the CLOSEST
+ * bit being used or being meaningful).
+ */
+static const true_false_string tfs_ads_pdc = {
+       "This is a PDC",
+       "This is NOT a pdc"
+};
+static const true_false_string tfs_ads_gc = {
+       "This is a GLOBAL CATALOGUE of forest",
+       "This is NOT a global catalog of forest"
+};
+static const true_false_string tfs_ads_ldap = {
+       "This is an LDAP server",
+       "This is NOT an ldap server"
+};
+static const true_false_string tfs_ads_ds = {
+       "This dc supports DS",
+       "This dc does NOT support ds"
+};
+static const true_false_string tfs_ads_kdc = {
+       "This is a KDC (kerberos)",
+       "This is NOT a kdc (kerberos)"
+};
+static const true_false_string tfs_ads_timeserv = {
+       "This dc is running TIME SERVICES (ntp)",
+       "This dc is NOT running time services (ntp)"
+};
+static const true_false_string tfs_ads_closest = {
+       "This is the CLOSEST dc (unreliable?)",
+       "This is NOT the closest dc"
+};
+static const true_false_string tfs_ads_writable = {
+       "This dc is WRITABLE",
+       "This dc is NOT writable"
+};
+static const true_false_string tfs_ads_good_timeserv = {
+       "This dc has a GOOD TIME SERVICE (i.e. hardware clock)",
+       "This dc does NOT have a good time service (i.e. no hardware clock)"
+};
+static const true_false_string tfs_ads_ndnc = {
+       "Domain is NON-DOMAIN NC serviced by ldap server",
+       "Domain is NOT non-domain nc serviced by ldap server"
+};
+static int dissect_mscldap_netlogon_flags(proto_tree *parent_tree, tvbuff_t *tvb, int offset)
+{
+  guint32 flags;
+  proto_item *item;
+  proto_tree *tree=NULL;
+  guint fields[] = { hf_mscldap_netlogon_flags_ndnc,
+                    hf_mscldap_netlogon_flags_good_timeserv,
+                    hf_mscldap_netlogon_flags_writable,
+                    hf_mscldap_netlogon_flags_closest,
+                    hf_mscldap_netlogon_flags_timeserv,
+                    hf_mscldap_netlogon_flags_kdc,
+                    hf_mscldap_netlogon_flags_ds,
+                    hf_mscldap_netlogon_flags_ldap,
+                    hf_mscldap_netlogon_flags_gc,
+                    hf_mscldap_netlogon_flags_pdc,
+                    0 };
+  guint  *field;
+  header_field_info *hfi;
+  gboolean one_bit_set = FALSE;
+
+  flags=tvb_get_letohl(tvb, offset);
+  item=proto_tree_add_item(parent_tree, hf_mscldap_netlogon_flags, tvb, offset, 4, TRUE);
+  if(parent_tree){
+    tree = proto_item_add_subtree(item, ett_mscldap_netlogon_flags);
+  }
+
+  proto_item_append_text(item, " (");
+
+  for(field = fields; *field; field++) {
+    proto_tree_add_boolean(tree, *field, tvb, offset, 4, flags);
+    hfi = proto_registrar_get_nth(*field);
+
+    if(flags & hfi->bitmask) {
+
+      if(one_bit_set)
+       proto_item_append_text(item, ", ");
+      else
+       one_bit_set = TRUE;
+
+      proto_item_append_text(item, hfi->name);
+
     }
   }
+
+  proto_item_append_text(item, ")");
+
+  offset += 4;
+
+  return offset;
+}
+
+static void dissect_NetLogon_PDU(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
+{
+  int old_offset, offset=0;
+  char str[256];
+
+  ldm_tree = NULL;
+
+/*qqq*/
+
+  /* Type */
+  /*XXX someone that knows what the type means should add that knowledge here*/
+  proto_tree_add_item(tree, hf_mscldap_netlogon_type, tvb, offset, 4, TRUE);
+  offset += 4;
+
+  /* Flags */
+  offset = dissect_mscldap_netlogon_flags(tree, tvb, offset);
+
+  /* Domain GUID */
+  proto_tree_add_item(tree, hf_mscldap_domain_guid, tvb, offset, 16, TRUE);
+  offset += 16;
+
+  /* Forest */
+  old_offset=offset;
+  offset=dissect_mscldap_string(tvb, offset, str, 255, FALSE);
+  proto_tree_add_string(tree, hf_mscldap_forest, tvb, old_offset, offset-old_offset, str);
+
+  /* Domain */
+  old_offset=offset;
+  offset=dissect_mscldap_string(tvb, offset, str, 255, FALSE);
+  proto_tree_add_string(tree, hf_mscldap_domain, tvb, old_offset, offset-old_offset, str);
+
+  /* Hostname */
+  old_offset=offset;
+  offset=dissect_mscldap_string(tvb, offset, str, 255, FALSE);
+  proto_tree_add_string(tree, hf_mscldap_hostname, tvb, old_offset, offset-old_offset, str);
+
+  /* NetBios Domain */
+  old_offset=offset;
+  offset=dissect_mscldap_string(tvb, offset, str, 255, FALSE);
+  proto_tree_add_string(tree, hf_mscldap_nb_domain, tvb, old_offset, offset-old_offset, str);
+
+  /* NetBios Hostname */
+  old_offset=offset;
+  offset=dissect_mscldap_string(tvb, offset, str, 255, FALSE);
+  proto_tree_add_string(tree, hf_mscldap_nb_hostname, tvb, old_offset, offset-old_offset, str);
+
+  /* User */
+  old_offset=offset;
+  offset=dissect_mscldap_string(tvb, offset, str, 255, FALSE);
+  proto_tree_add_string(tree, hf_mscldap_username, tvb, old_offset, offset-old_offset, str);
+
+  /* Site */
+  old_offset=offset;
+  offset=dissect_mscldap_string(tvb, offset, str, 255, FALSE);
+  proto_tree_add_string(tree, hf_mscldap_sitename, tvb, old_offset, offset-old_offset, str);
+
+  /* Client Site */
+  old_offset=offset;
+  offset=dissect_mscldap_string(tvb, offset, str, 255, FALSE);
+  proto_tree_add_string(tree, hf_mscldap_clientsitename, tvb, old_offset, offset-old_offset, str);
+
+  /* Version */
+  proto_tree_add_item(tree, hf_mscldap_netlogon_version, tvb, offset, 4, TRUE);
+  offset += 4;
+
+  /* LM Token */
+  proto_tree_add_item(tree, hf_mscldap_netlogon_lm_token, tvb, offset, 2, TRUE);
+  offset += 2;
+
+  /* NT Token */
+  proto_tree_add_item(tree, hf_mscldap_netlogon_nt_token, tvb, offset, 2, TRUE);
+  offset += 2;
+
+}
+
+
+static guint
+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;
+}
+
+static void
+dissect_sasl_ldap_pdu(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
+{
+       dissect_ldap_pdu(tvb, pinfo, tree, FALSE);
+       return;
 }
+
+static guint
+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 is where the tag is
+        * offset+1 is where length starts
+        */
+       data_offset=get_ber_length(NULL, tvb, offset+1, &len, &ind);
+       return len+data_offset-offset;
+}
+
 static void
-dissect_ldap(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
+dissect_normal_ldap_pdu(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
 {
        dissect_ldap_pdu(tvb, pinfo, tree, FALSE);
        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
+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;
+
+       /* 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()
+        */
+       /* 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;
+       }
+
+       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;
+}
+
 static void
 dissect_mscldap(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
 {
@@ -695,6 +1406,23 @@ ldap_reinit(void)
   ldap_info_items = NULL;
 
 }
+
+void
+register_ldap_name_dissector_handle(const char *attr_type, dissector_handle_t dissector)
+{
+       dissector_add_string("ldap.name", attr_type, dissector);
+}
+
+void
+register_ldap_name_dissector(const char *attr_type, dissector_t dissector, int proto)
+{
+       dissector_handle_t dissector_handle;
+
+       dissector_handle=create_dissector_handle(dissector, proto);
+       register_ldap_name_dissector_handle(attr_type, dissector_handle);
+}
+
+
 /*--- proto_register_ldap -------------------------------------------*/
 void proto_register_ldap(void) {
 
@@ -702,20 +1430,179 @@ void proto_register_ldap(void) {
 
   static hf_register_info hf[] = {
 
-             { &hf_ldap_sasl_buffer_length,
-                         { "SASL Buffer Length",       "ldap.sasl_buffer_length",
-                         FT_UINT32, BASE_DEC, NULL, 0x0,
-                         "SASL Buffer Length", HFILL }},
+               { &hf_ldap_sasl_buffer_length,
+                 { "SASL Buffer Length",       "ldap.sasl_buffer_length",
+                       FT_UINT32, BASE_DEC, NULL, 0x0,
+                       "SASL Buffer Length", HFILL }},
+           { &hf_ldap_response_in,
+             { "Response In", "ldap.response_in",
+               FT_FRAMENUM, BASE_DEC, NULL, 0x0,
+               "The response to this LDAP request is in this frame", HFILL }},
+           { &hf_ldap_response_to,
+             { "Response To", "ldap.response_to",
+               FT_FRAMENUM, BASE_DEC, NULL, 0x0,
+               "This is a response to the LDAP request in this frame", HFILL }},
+           { &hf_ldap_time,
+             { "Time", "ldap.time",
+               FT_RELATIVE_TIME, BASE_NONE, NULL, 0x0,
+               "The time between the Call and the Reply", HFILL }},
+
+    { &hf_mscldap_netlogon_type,
+      { "Type", "mscldap.netlogon.type",
+        FT_UINT32, BASE_DEC, NULL, 0x0,
+        "Type of <please tell Wireshark developers what this type is>", HFILL }},
+
+    { &hf_mscldap_netlogon_version,
+      { "Version", "mscldap.netlogon.version",
+        FT_UINT32, BASE_DEC, NULL, 0x0,
+        "Version of <please tell Wireshark developers what this type is>", HFILL }},
+
+    { &hf_mscldap_netlogon_lm_token,
+      { "LM Token", "mscldap.netlogon.lm_token",
+        FT_UINT16, BASE_HEX, NULL, 0x0,
+        "LM Token", HFILL }},
+
+    { &hf_mscldap_netlogon_nt_token,
+      { "NT Token", "mscldap.netlogon.nt_token",
+        FT_UINT16, BASE_HEX, NULL, 0x0,
+        "NT Token", HFILL }},
+
+    { &hf_mscldap_netlogon_flags,
+      { "Flags", "mscldap.netlogon.flags",
+        FT_UINT32, BASE_HEX, NULL, 0x0,
+        "Netlogon flags describing the DC properties", HFILL }},
+
+    { &hf_mscldap_domain_guid,
+      { "Domain GUID", "mscldap.domain.guid",
+        FT_BYTES, BASE_HEX, NULL, 0x0,
+        "Domain GUID", HFILL }},
+
+    { &hf_mscldap_forest,
+      { "Forest", "mscldap.forest",
+        FT_STRING, BASE_NONE, NULL, 0x0,
+        "Forest", HFILL }},
+
+    { &hf_mscldap_domain,
+      { "Domain", "mscldap.domain",
+        FT_STRING, BASE_NONE, NULL, 0x0,
+        "Domainname", HFILL }},
+
+    { &hf_mscldap_hostname,
+      { "Hostname", "mscldap.hostname",
+        FT_STRING, BASE_NONE, NULL, 0x0,
+        "Hostname", HFILL }},
+
+    { &hf_mscldap_nb_domain,
+      { "NetBios Domain", "mscldap.nb_domain",
+        FT_STRING, BASE_NONE, NULL, 0x0,
+        "NetBios Domainname", HFILL }},
+
+    { &hf_mscldap_nb_hostname,
+      { "NetBios Hostname", "mscldap.nb_hostname",
+        FT_STRING, BASE_NONE, NULL, 0x0,
+        "NetBios Hostname", HFILL }},
+
+    { &hf_mscldap_username,
+      { "User", "mscldap.username",
+        FT_STRING, BASE_NONE, NULL, 0x0,
+        "User name", HFILL }},
+
+    { &hf_mscldap_sitename,
+      { "Site", "mscldap.sitename",
+        FT_STRING, BASE_NONE, NULL, 0x0,
+        "Site name", HFILL }},
+
+    { &hf_mscldap_clientsitename,
+      { "Client Site", "mscldap.clientsitename",
+        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 }},
+
+    { &hf_mscldap_netlogon_flags_gc,
+      { "GC", "mscldap.netlogon.flags.gc", FT_BOOLEAN, 32,
+        TFS(&tfs_ads_gc), 0x00000004, "Does this dc service as a GLOBAL CATALOGUE?", HFILL }},
+
+    { &hf_mscldap_netlogon_flags_ldap,
+      { "LDAP", "mscldap.netlogon.flags.ldap", FT_BOOLEAN, 32,
+        TFS(&tfs_ads_ldap), 0x00000008, "Does this DC act as an LDAP server?", HFILL }},
+
+    { &hf_mscldap_netlogon_flags_ds,
+      { "DS", "mscldap.netlogon.flags.ds", FT_BOOLEAN, 32,
+        TFS(&tfs_ads_ds), 0x00000010, "Does this dc provide DS services?", HFILL }},
+
+    { &hf_mscldap_netlogon_flags_kdc,
+      { "KDC", "mscldap.netlogon.flags.kdc", FT_BOOLEAN, 32,
+        TFS(&tfs_ads_kdc), 0x00000020, "Does this dc act as a KDC?", HFILL }},
+
+    { &hf_mscldap_netlogon_flags_timeserv,
+      { "Time Serv", "mscldap.netlogon.flags.timeserv", FT_BOOLEAN, 32,
+        TFS(&tfs_ads_timeserv), 0x00000040, "Does this dc provide time services (ntp) ?", HFILL }},
+
+    { &hf_mscldap_netlogon_flags_closest,
+      { "Closest", "mscldap.netlogon.flags.closest", FT_BOOLEAN, 32,
+        TFS(&tfs_ads_closest), 0x00000080, "Is this the closest dc? (is this used at all?)", HFILL }},
+
+    { &hf_mscldap_netlogon_flags_writable,
+      { "Writable", "mscldap.netlogon.flags.writable", FT_BOOLEAN, 32,
+        TFS(&tfs_ads_writable), 0x00000100, "Is this dc writable? (i.e. can it update the AD?)", HFILL }},
+
+    { &hf_mscldap_netlogon_flags_good_timeserv,
+      { "Good Time Serv", "mscldap.netlogon.flags.good_timeserv", FT_BOOLEAN, 32,
+        TFS(&tfs_ads_good_timeserv), 0x00000200, "Is this a Good Time Server? (i.e. does it have a hardware clock)", HFILL }},
+
+    { &hf_mscldap_netlogon_flags_ndnc,
+      { "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"
   };
 
   /* List of subtrees */
   static gint *ett[] = {
-         &ett_ldap,
-       &ett_ldap_payload,
+    &ett_ldap,
+    &ett_ldap_payload,
     &ett_ldap_sasl_blob,
-       &ett_ldap_msg,
+    &ett_ldap_msg,
+    &ett_mscldap_netlogon_flags,
 
 #include "packet-ldap-ettarr.c"
   };
@@ -728,16 +1615,22 @@ void proto_register_ldap(void) {
   proto_register_field_array(proto_ldap, hf, array_length(hf));
   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.",
+    "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");
@@ -745,6 +1638,8 @@ void proto_register_ldap(void) {
   register_init_routine(ldap_reinit);
   ldap_tap=register_tap("ldap");
 
+  ldap_name_dissector_table = register_dissector_table("ldap.name", "LDAP Attribute Type Dissectors", FT_STRING, BASE_NONE);
+
 }
 
 
@@ -753,8 +1648,9 @@ void
 proto_reg_handoff_ldap(void)
 {
        dissector_handle_t ldap_handle, cldap_handle;
-       ldap_handle = create_dissector_handle(dissect_ldap, proto_ldap);
-       dissector_add("tcp.port", TCP_PORT_LDAP, ldap_handle);
+       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);
 
        cldap_handle = create_dissector_handle(dissect_mscldap, proto_cldap);
@@ -763,7 +1659,46 @@ 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");
+       add_oid_str_name("1.2.840.113556.1.4.1338","LDAP_SERVER_VERIFY_NAME_OID");
+       add_oid_str_name("1.2.840.113556.1.4.1339","LDAP_SERVER_DOMAIN_SCOPE_OID");
+       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"
+       
 
 }