2 * Routines for ldap packet dissection
4 * See RFC 1777 (LDAP v2), RFC 4511 (LDAP v3), and RFC 2222 (SASL).
8 * Wireshark - Network traffic analyzer
9 * By Gerald Combs <gerald@wireshark.org>
10 * Copyright 1998 Gerald Combs
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
17 * This program is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU General Public License for more details.
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, write to the Free Software
24 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
28 * This is not a complete implementation. It doesn't handle the full version 3, more specifically,
29 * it handles only the commands of version 2, but any additional characteristics of the ver3 command are supported.
30 * It's also missing extensible search filters.
32 * There should probably be alot more error checking, I simply assume that if we have a full packet, it will be a complete
35 * AFAIK, it will handle all messages used by the OpenLDAP 1.2.9 server and libraries which was my goal. I do plan to add
36 * the remaining commands as time permits but this is not a priority to me. Send me an email if you need it and I'll see what
40 * nazard@dragoninc.on.ca
44 * 11/11/2002 - Fixed problem when decoding LDAP with desegmentation enabled and the
45 * ASN.1 BER Universal Class Tag: "Sequence Of" header is encapsulated across 2
49 * ronald.henderson@cognicaseusa.com
53 * 20-JAN-2004 - added decoding of MS-CLDAP netlogon RPC
54 * using information from the SNIA 2003 conference paper :
55 * Active Directory Domain Controller Location Service
61 * 17-DEC-2004 - added basic decoding for LDAP Controls
62 * 20-DEC-2004 - added handling for GSS-API encrypted blobs
64 * Stefan Metzmacher <metze@samba.org>
66 * 15-NOV-2005 - Changed to use the asn2wrs compiler
67 * Anders Broman <anders.broman@ericsson.com>
71 * 3-AUG-2008 - Extended the cldap support to include all netlogon data types.
72 * Updated cldap_netlogon_flags to include Windows 2008 flags
73 * Expanded the ntver ldap option with bit field
75 * Gary Reynolds <gazzadownunder@yahoo.co.uk>
79 * 09-DEC-2009 - Added support for RFC4533
80 * Content Synchronization Operation (aka syncrepl)
81 * 11-DEC-2009 - Added support for IntermediateResponse (LDAP v3 from RFC 4511)
82 * Mathieu Parent <math.parent@gmail.com>
94 #include <epan/packet.h>
95 #include <epan/conversation.h>
96 #include <epan/prefs.h>
98 #include <epan/emem.h>
99 #include <epan/oids.h>
100 #include <epan/strutil.h>
101 #include <epan/dissectors/packet-frame.h>
102 #include <epan/dissectors/packet-tcp.h>
103 #include <epan/dissectors/packet-windows-common.h>
104 #include <epan/dissectors/packet-dcerpc.h>
105 #include <epan/asn1.h>
106 #include <epan/expert.h>
107 #include <epan/uat.h>
109 #include "packet-ldap.h"
110 #include "packet-ntlmssp.h"
111 #include "packet-ssl.h"
112 #include "packet-smb-common.h"
114 #include "packet-ber.h"
115 #include "packet-per.h"
116 #include "packet-dns.h"
118 #define PNAME "Lightweight Directory Access Protocol"
119 #define PSNAME "LDAP"
120 #define PFNAME "ldap"
122 /* Initialize the protocol and registered fields */
123 static int ldap_tap = -1;
124 static int proto_ldap = -1;
125 static int proto_cldap = -1;
127 static int hf_ldap_sasl_buffer_length = -1;
128 static int hf_ldap_response_in = -1;
129 static int hf_ldap_response_to = -1;
130 static int hf_ldap_time = -1;
131 static int hf_ldap_guid = -1;
133 static int hf_mscldap_ntver_flags = -1;
134 static int hf_mscldap_ntver_flags_v1 = -1;
135 static int hf_mscldap_ntver_flags_v5 = -1;
136 static int hf_mscldap_ntver_flags_v5ex = -1;
137 static int hf_mscldap_ntver_flags_v5ep = -1;
138 static int hf_mscldap_ntver_flags_vcs = -1;
139 static int hf_mscldap_ntver_flags_vnt4 = -1;
140 static int hf_mscldap_ntver_flags_vpdc = -1;
141 static int hf_mscldap_ntver_flags_vip = -1;
142 static int hf_mscldap_ntver_flags_vl = -1;
143 static int hf_mscldap_ntver_flags_vgc = -1;
145 static int hf_mscldap_netlogon_ipaddress_family = -1;
146 static int hf_mscldap_netlogon_ipaddress_port = -1;
147 static int hf_mscldap_netlogon_ipaddress = -1;
148 static int hf_mscldap_netlogon_ipaddress_ipv4 = -1;
149 static int hf_mscldap_netlogon_opcode = -1;
150 static int hf_mscldap_netlogon_flags = -1;
151 static int hf_mscldap_netlogon_flags_pdc = -1;
152 static int hf_mscldap_netlogon_flags_gc = -1;
153 static int hf_mscldap_netlogon_flags_ldap = -1;
154 static int hf_mscldap_netlogon_flags_ds = -1;
155 static int hf_mscldap_netlogon_flags_kdc = -1;
156 static int hf_mscldap_netlogon_flags_timeserv = -1;
157 static int hf_mscldap_netlogon_flags_closest = -1;
158 static int hf_mscldap_netlogon_flags_writable = -1;
159 static int hf_mscldap_netlogon_flags_good_timeserv = -1;
160 static int hf_mscldap_netlogon_flags_ndnc = -1;
161 static int hf_mscldap_netlogon_flags_fnc = -1;
162 static int hf_mscldap_netlogon_flags_dnc = -1;
163 static int hf_mscldap_netlogon_flags_dns = -1;
164 static int hf_mscldap_netlogon_flags_wdc = -1;
165 static int hf_mscldap_netlogon_flags_rodc = -1;
166 static int hf_mscldap_domain_guid = -1;
167 static int hf_mscldap_forest = -1;
168 static int hf_mscldap_domain = -1;
169 static int hf_mscldap_hostname = -1;
170 static int hf_mscldap_nb_domain = -1;
171 static int hf_mscldap_nb_hostname = -1;
172 static int hf_mscldap_username = -1;
173 static int hf_mscldap_sitename = -1;
174 static int hf_mscldap_clientsitename = -1;
175 static int hf_mscldap_netlogon_lm_token = -1;
176 static int hf_mscldap_netlogon_nt_token = -1;
177 static int hf_ldap_sid = -1;
178 static int hf_ldap_AccessMask_ADS_CREATE_CHILD = -1;
179 static int hf_ldap_AccessMask_ADS_DELETE_CHILD = -1;
180 static int hf_ldap_AccessMask_ADS_LIST = -1;
181 static int hf_ldap_AccessMask_ADS_SELF_WRITE = -1;
182 static int hf_ldap_AccessMask_ADS_READ_PROP = -1;
183 static int hf_ldap_AccessMask_ADS_WRITE_PROP = -1;
184 static int hf_ldap_AccessMask_ADS_DELETE_TREE = -1;
185 static int hf_ldap_AccessMask_ADS_LIST_OBJECT = -1;
186 static int hf_ldap_AccessMask_ADS_CONTROL_ACCESS = -1;
188 #include "packet-ldap-hf.c"
190 /* Initialize the subtree pointers */
191 static gint ett_ldap = -1;
192 static gint ett_ldap_msg = -1;
193 static gint ett_ldap_sasl_blob = -1;
194 static gint ett_ldap_payload = -1;
195 static gint ett_mscldap_netlogon_flags = -1;
196 static gint ett_mscldap_ntver_flags = -1;
197 static gint ett_mscldap_ipdetails = -1;
199 #include "packet-ldap-ett.c"
201 static dissector_table_t ldap_name_dissector_table=NULL;
202 static const char *object_identifier_id = NULL; /* LDAP OID */
204 static gboolean do_protocolop = FALSE;
205 static gchar *attr_type = NULL;
206 static gboolean is_binary_attr_type = FALSE;
207 static gboolean ldap_found_in_frame = FALSE;
209 #define TCP_PORT_LDAP 389
210 #define TCP_PORT_LDAPS 636
211 #define UDP_PORT_CLDAP 389
212 #define TCP_PORT_GLOBALCAT_LDAP 3268 /* Windows 2000 Global Catalog */
214 /* desegmentation of LDAP */
215 static gboolean ldap_desegment = TRUE;
216 static guint global_ldap_tcp_port = TCP_PORT_LDAP;
217 static guint global_ldaps_tcp_port = TCP_PORT_LDAPS;
218 static guint tcp_port = 0;
219 static guint ssl_port = 0;
221 static dissector_handle_t gssapi_handle;
222 static dissector_handle_t gssapi_wrap_handle;
223 static dissector_handle_t ntlmssp_handle;
224 static dissector_handle_t spnego_handle;
225 static dissector_handle_t ssl_handle;
226 static dissector_handle_t ldap_handle ;
228 static void prefs_register_ldap(void); /* forward declaration for use in preferences registration */
231 /* different types of rpc calls ontop of ms cldap */
232 #define MSCLDAP_RPC_NETLOGON 1
234 /* Message type Choice values */
235 static const value_string ldap_ProtocolOp_choice_vals[] = {
236 { 0, "bindRequest" },
237 { 1, "bindResponse" },
238 { 2, "unbindRequest" },
239 { 3, "searchRequest" },
240 { 4, "searchResEntry" },
241 { 5, "searchResDone" },
242 { 6, "searchResRef" },
243 { 7, "modifyRequest" },
244 { 8, "modifyResponse" },
246 { 10, "addResponse" },
247 { 11, "delRequest" },
248 { 12, "delResponse" },
249 { 13, "modDNRequest" },
250 { 14, "modDNResponse" },
251 { 15, "compareRequest" },
252 { 16, "compareResponse" },
253 { 17, "abandonRequest" },
254 { 18, "extendedReq" },
255 { 19, "extendedResp" },
256 { 20, "intermediateResponse" },
260 #define LOGON_PRIMARY_QUERY 7
261 #define LOGON_PRIMARY_RESPONSE 12
262 #define LOGON_SAM_LOGON_REQUEST 18
263 #define LOGON_SAM_LOGON_RESPONSE 19
264 #define LOGON_SAM_PAUSE_RESPONSE 20
265 #define LOGON_SAM_USER_UNKNOWN 21
266 #define LOGON_SAM_LOGON_RESPONSE_EX 23
267 #define LOGON_SAM_PAUSE_RESPONSE_EX 24
268 #define LOGON_SAM_USER_UNKNOWN_EX 25
270 static const value_string netlogon_opcode_vals[] = {
271 { LOGON_PRIMARY_QUERY, "LOGON_PRIMARY_QUERY" },
272 { LOGON_PRIMARY_RESPONSE, "LOGON_PRIMARY_RESPONSE" },
273 { LOGON_SAM_LOGON_REQUEST, "LOGON_SAM_LOGON_REQUEST" },
274 { LOGON_SAM_LOGON_RESPONSE, "LOGON_SAM_LOGON_RESPONSE" },
275 { LOGON_SAM_PAUSE_RESPONSE, "LOGON_SAM_PAUSE_RESPONSE" },
276 { LOGON_SAM_LOGON_RESPONSE_EX, "LOGON_SAM_LOGON_RESPONSE_EX" },
277 { LOGON_SAM_PAUSE_RESPONSE_EX, "LOGON_SAM_PAUSE_RESPONSE_EX" },
278 { LOGON_SAM_USER_UNKNOWN_EX, "LOGON_SAM_USER_UNKNOWN_EX" },
283 * Data structure attached to a conversation, giving authentication
284 * information from a bind request.
285 * We keep a linked list of them, so that we can free up all the
286 * authentication mechanism strings.
288 typedef struct ldap_conv_info_t {
289 struct ldap_conv_info_t *next;
290 guint auth_type; /* authentication type */
291 char *auth_mech; /* authentication mechanism */
292 guint32 first_auth_frame; /* first frame that would use a security layer */
293 GHashTable *unmatched;
297 gboolean start_tls_pending;
298 guint32 start_tls_frame;
300 static ldap_conv_info_t *ldap_info_items;
303 ldap_info_hash_matched(gconstpointer k)
305 const ldap_call_response_t *key = (const ldap_call_response_t *)k;
307 return key->messageId;
311 ldap_info_equal_matched(gconstpointer k1, gconstpointer k2)
313 const ldap_call_response_t *key1 = (const ldap_call_response_t*)k1;
314 const ldap_call_response_t *key2 = (const ldap_call_response_t*)k2;
316 if( key1->req_frame && key2->req_frame && (key1->req_frame!=key2->req_frame) ){
319 /* a response may span multiple frames
320 if( key1->rep_frame && key2->rep_frame && (key1->rep_frame!=key2->rep_frame) ){
325 return key1->messageId==key2->messageId;
329 ldap_info_hash_unmatched(gconstpointer k)
331 const ldap_call_response_t *key = (const ldap_call_response_t*)k;
333 return key->messageId;
337 ldap_info_equal_unmatched(gconstpointer k1, gconstpointer k2)
339 const ldap_call_response_t *key1 = (const ldap_call_response_t*)k1;
340 const ldap_call_response_t *key2 = (const ldap_call_response_t*)k2;
342 return key1->messageId==key2->messageId;
346 /* These are the NtVer flags
347 http://msdn.microsoft.com/en-us/library/cc201035.aspx
350 static const true_false_string tfs_ntver_v1 = {
351 "Client requested version 1 netlogon response",
352 "Version 1 netlogon response not requested"
355 static const true_false_string tfs_ntver_v5 = {
356 "Client requested version 5 netlogon response",
357 "Version 5 netlogon response not requested"
359 static const true_false_string tfs_ntver_v5ex = {
360 "Client requested version 5 extended netlogon response",
361 "Version 5 extended response not requested"
363 static const true_false_string tfs_ntver_v5ep = {
364 "Client has requested IP address of the server",
365 "IP address of server not requested"
367 static const true_false_string tfs_ntver_vcs = {
368 "Client has asked for the closest site information",
369 "Closest site information not requested"
371 static const true_false_string tfs_ntver_vnt4 = {
372 "Client is requesting server to avoid NT4 emulation",
373 "Only full AD DS requested"
375 static const true_false_string tfs_ntver_vpdc = {
376 "Client has requested the Primary Domain Controller",
377 "Primary Domain Controller not requested"
379 static const true_false_string tfs_ntver_vip = {
380 "Client has requested IP details (obsolete)",
381 "IP details not requested (obsolete)"
383 static const true_false_string tfs_ntver_vl = {
384 "Client indicated that it is the local machine",
385 "Client is not the local machine"
386 };static const true_false_string tfs_ntver_vgc = {
387 "Client has requested a Global Catalog server",
388 "Global Catalog not requested"
391 /* Stuff for generation/handling of fields for custom AttributeValues */
392 typedef struct _attribute_type_t {
393 gchar* attribute_type;
394 gchar* attribute_desc;
397 static attribute_type_t* attribute_types = NULL;
398 static guint num_attribute_types = 0;
400 static GHashTable* attribute_types_hash = NULL;
403 attribute_types_update_cb(void *r, const char **err)
405 attribute_type_t *rec = (attribute_type_t *)r;
408 if (rec->attribute_type == NULL) {
409 *err = ep_strdup_printf("Attribute type can't be empty");
413 g_strstrip(rec->attribute_type);
414 if (rec->attribute_type[0] == 0) {
415 *err = ep_strdup_printf("Attribute type can't be empty");
419 /* Check for invalid characters (to avoid asserting out when
420 * registering the field).
422 c = proto_check_field_name(rec->attribute_type);
424 *err = ep_strdup_printf("Attribute type can't contain '%c'", c);
432 attribute_types_copy_cb(void* n, const void* o, size_t siz _U_)
434 attribute_type_t* new_rec = (attribute_type_t*)n;
435 const attribute_type_t* old_rec = (const attribute_type_t*)o;
437 new_rec->attribute_type = g_strdup(old_rec->attribute_type);
438 new_rec->attribute_desc = g_strdup(old_rec->attribute_desc);
444 attribute_types_free_cb(void*r)
446 attribute_type_t* rec = (attribute_type_t*)r;
448 if (rec->attribute_type) g_free(rec->attribute_type);
449 if (rec->attribute_desc) g_free(rec->attribute_desc);
452 UAT_CSTRING_CB_DEF(attribute_types, attribute_type, attribute_type_t)
453 UAT_CSTRING_CB_DEF(attribute_types, attribute_desc, attribute_type_t)
459 get_hf_for_header(char* attribute_type)
463 if (attribute_types_hash) {
464 hf_id = (gint*) g_hash_table_lookup(attribute_types_hash, attribute_type);
476 attribute_types_initialize_cb(void)
478 static hf_register_info* hf;
481 gchar* attribute_type;
483 if (attribute_types_hash) {
484 guint hf_size = g_hash_table_size (attribute_types_hash);
485 /* Unregister all fields */
486 for (i = 0; i < hf_size; i++) {
487 proto_unregister_field (proto_ldap, *(hf[i].p_id));
490 g_free ((char *) hf[i].hfinfo.name);
491 g_free ((char *) hf[i].hfinfo.abbrev);
492 g_free ((char *) hf[i].hfinfo.blurb);
494 g_hash_table_destroy (attribute_types_hash);
496 attribute_types_hash = NULL;
499 if (num_attribute_types) {
500 attribute_types_hash = g_hash_table_new(g_str_hash, g_str_equal);
501 hf = g_new0(hf_register_info,num_attribute_types);
503 for (i = 0; i < num_attribute_types; i++) {
504 hf_id = g_new(gint,1);
506 attribute_type = g_strdup(attribute_types[i].attribute_type);
509 hf[i].hfinfo.name = attribute_type;
510 hf[i].hfinfo.abbrev = g_strdup_printf("ldap.AttributeValue.%s", attribute_type);
511 hf[i].hfinfo.type = FT_STRING;
512 hf[i].hfinfo.display = BASE_NONE;
513 hf[i].hfinfo.strings = NULL;
514 hf[i].hfinfo.blurb = g_strdup(attribute_types[i].attribute_desc);
515 hf[i].hfinfo.same_name_prev = NULL;
516 hf[i].hfinfo.same_name_next = NULL;
518 g_hash_table_insert(attribute_types_hash, attribute_type, hf_id);
521 proto_register_field_array(proto_ldap, hf, num_attribute_types);
525 /* MS-ADTS specification, section 7.3.1.1, NETLOGON_NT_VERSION Options Bits */
526 static int dissect_mscldap_ntver_flags(proto_tree *parent_tree, tvbuff_t *tvb, int offset)
530 proto_tree *tree=NULL;
532 hf_mscldap_ntver_flags_v1,
533 hf_mscldap_ntver_flags_v5,
534 hf_mscldap_ntver_flags_v5ex,
535 hf_mscldap_ntver_flags_v5ep,
536 hf_mscldap_ntver_flags_vcs,
537 hf_mscldap_ntver_flags_vnt4,
538 hf_mscldap_ntver_flags_vpdc,
539 hf_mscldap_ntver_flags_vip,
540 hf_mscldap_ntver_flags_vl,
541 hf_mscldap_ntver_flags_vgc,
545 header_field_info *hfi;
546 gboolean one_bit_set = FALSE;
548 flags=tvb_get_letohl(tvb, offset);
549 item=proto_tree_add_item(parent_tree, hf_mscldap_ntver_flags, tvb, offset, 4, ENC_LITTLE_ENDIAN);
551 tree = proto_item_add_subtree(item, ett_mscldap_ntver_flags);
554 proto_item_append_text(item, " (");
556 for(field = fields; *field; field++) {
557 proto_tree_add_boolean(tree, *field, tvb, offset, 4, flags);
558 hfi = proto_registrar_get_nth(*field);
560 if(flags & hfi->bitmask) {
563 proto_item_append_text(item, ", ");
567 proto_item_append_text(item, "%s", hfi->name);
572 proto_item_append_text(item, ")");
579 /* This string contains the last LDAPString that was decoded */
580 static const char *attributedesc_string=NULL;
582 /* This string contains the last AssertionValue that was decoded */
583 static char *ldapvalue_string=NULL;
585 /* if the octet string contain all printable ASCII characters, then
586 * display it as a string, othervise just display it in hex.
589 dissect_ldap_AssertionValue(gboolean implicit_tag, tvbuff_t *tvb, int offset, asn1_ctx_t *actx _U_, proto_tree *tree, int hf_index)
592 gboolean pc, ind, is_ascii;
598 offset=get_ber_identifier(tvb, offset, &ber_class, &pc, &tag);
599 offset=get_ber_length(tvb, offset, &len, &ind);
601 len=tvb_length_remaining(tvb,offset);
610 * Some special/wellknown attributes in common LDAP (read AD)
611 * are neither ascii strings nor blobs of hex data.
612 * Special case these attributes and decode them more nicely.
614 * Add more special cases as required to prettify further
615 * (there cant be that many ones that are truly interesting)
617 if(attributedesc_string && !strncmp("DomainSid", attributedesc_string, 9)){
621 /* this octet string contains an NT SID */
622 sid_tvb=tvb_new_subset(tvb, offset, len, len);
623 dissect_nt_sid(sid_tvb, 0, tree, "SID", &tmpstr, hf_index);
624 ldapvalue_string=tmpstr;
627 } else if ( (len==16) /* GUIDs are always 16 bytes */
628 && (attributedesc_string && !strncmp("DomainGuid", attributedesc_string, 10))) {
629 guint8 drep[4] = { 0x10, 0x00, 0x00, 0x00}; /* fake DREP struct */
632 /* This octet string contained a GUID */
633 dissect_dcerpc_uuid_t(tvb, offset, actx->pinfo, tree, drep, hf_ldap_guid, &uuid);
635 ldapvalue_string=(char*)ep_alloc(1024);
636 g_snprintf(ldapvalue_string, 1023, "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
637 uuid.Data1, uuid.Data2, uuid.Data3,
638 uuid.Data4[0], uuid.Data4[1],
639 uuid.Data4[2], uuid.Data4[3],
640 uuid.Data4[4], uuid.Data4[5],
641 uuid.Data4[6], uuid.Data4[7]);
644 } else if (attributedesc_string && !strncmp("NtVer", attributedesc_string, 5)){
648 /* get flag value to populate ldapvalue_string */
649 flags=tvb_get_letohl(tvb, offset);
651 ldapvalue_string=(char*)ep_alloc(1024);
652 g_snprintf(ldapvalue_string, 1023, "0x%08x",flags);
654 /* populate bitmask subtree */
655 offset = dissect_mscldap_ntver_flags(tree, tvb, offset);
663 * It was not one of our "wellknown" attributes so make the best
664 * we can and just try to see if it is an ascii string or if it
667 * XXX - should we support reading RFC 2252-style schemas
668 * for LDAP, and using that to determine how to display
669 * attribute values and assertion values?
671 * -- I dont think there are full schemas available that describe the
672 * interesting cases i.e. AD -- ronnie
674 str=tvb_get_ptr(tvb, offset, len);
677 if(!isascii(str[i]) || !isprint(str[i])){
683 /* convert the string into a printable string */
685 ldapvalue_string=ep_strndup(str, len);
687 ldapvalue_string=(char*)ep_alloc(3*len);
689 g_snprintf(ldapvalue_string+i*3,3,"%02x",str[i]&0xff);
690 ldapvalue_string[3*i+2]=':';
692 ldapvalue_string[3*len-1]=0;
695 proto_tree_add_string(tree, hf_index, tvb, offset, len, ldapvalue_string);
703 /* This string contains the last Filter item that was decoded */
704 static const char *Filter_string=NULL;
705 static const char *and_filter_string=NULL;
706 static const char *or_filter_string=NULL;
707 static const char *substring_value=NULL;
708 static const char *substring_item_init=NULL;
709 static const char *substring_item_any=NULL;
710 static const char *substring_item_final=NULL;
711 static const char *matching_rule_string=NULL;
712 static gboolean matching_rule_dnattr=FALSE;
714 #define MAX_FILTER_LEN 4096
715 static gint Filter_length;
717 #define MAX_FILTER_ELEMENTS 200
718 static gint Filter_elements;
720 /* Global variables */
721 static gint MessageID =-1;
722 static gint ProtocolOp = -1;
723 static gint result = 0;
724 static proto_item *ldm_tree = NULL; /* item to add text to */
726 static void ldap_do_protocolop(packet_info *pinfo)
732 valstr = val_to_str(ProtocolOp, ldap_ProtocolOp_choice_vals, "Unknown (%%u)");
734 col_append_fstr(pinfo->cinfo, COL_INFO, "%s(%u) ", valstr, MessageID);
737 proto_item_append_text(ldm_tree, " %s(%d)", valstr, MessageID);
739 do_protocolop = FALSE;
744 static ldap_call_response_t *
745 ldap_match_call_response(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint messageId, guint protocolOpTag)
747 ldap_call_response_t lcr, *lcrp=NULL;
748 ldap_conv_info_t *ldap_info = (ldap_conv_info_t *)pinfo->private_data;
750 /* first see if we have already matched this */
752 lcr.messageId=messageId;
753 switch(protocolOpTag){
755 case LDAP_REQ_SEARCH:
756 case LDAP_REQ_MODIFY:
758 case LDAP_REQ_DELETE:
759 case LDAP_REQ_MODRDN:
760 case LDAP_REQ_COMPARE:
761 case LDAP_REQ_EXTENDED:
763 lcr.req_frame=pinfo->fd->num;
767 case LDAP_RES_SEARCH_ENTRY:
768 case LDAP_RES_SEARCH_REF:
769 case LDAP_RES_SEARCH_RESULT:
770 case LDAP_RES_MODIFY:
772 case LDAP_RES_DELETE:
773 case LDAP_RES_MODRDN:
774 case LDAP_RES_COMPARE:
775 case LDAP_RES_EXTENDED:
776 case LDAP_RES_INTERMEDIATE:
777 lcr.is_request=FALSE;
779 lcr.rep_frame=pinfo->fd->num;
782 lcrp=(ldap_call_response_t *)g_hash_table_lookup(ldap_info->matched, &lcr);
786 lcrp->is_request=lcr.is_request;
790 /* we haven't found a match - try and match it up */
792 switch(protocolOpTag){
794 case LDAP_REQ_SEARCH:
795 case LDAP_REQ_MODIFY:
797 case LDAP_REQ_DELETE:
798 case LDAP_REQ_MODRDN:
799 case LDAP_REQ_COMPARE:
800 case LDAP_REQ_EXTENDED:
802 /* this a a request - add it to the unmatched list */
804 /* check that we dont already have one of those in the
805 unmatched list and if so remove it */
807 lcr.messageId=messageId;
808 lcrp=(ldap_call_response_t *)g_hash_table_lookup(ldap_info->unmatched, &lcr);
810 g_hash_table_remove(ldap_info->unmatched, lcrp);
812 /* if we cant reuse the old one, grab a new chunk */
814 lcrp=se_new(ldap_call_response_t);
816 lcrp->messageId=messageId;
817 lcrp->req_frame=pinfo->fd->num;
818 lcrp->req_time=pinfo->fd->abs_ts;
820 lcrp->protocolOpTag=protocolOpTag;
821 lcrp->is_request=TRUE;
822 g_hash_table_insert(ldap_info->unmatched, lcrp, lcrp);
826 case LDAP_RES_SEARCH_ENTRY:
827 case LDAP_RES_SEARCH_REF:
828 case LDAP_RES_SEARCH_RESULT:
829 case LDAP_RES_MODIFY:
831 case LDAP_RES_DELETE:
832 case LDAP_RES_MODRDN:
833 case LDAP_RES_COMPARE:
834 case LDAP_RES_EXTENDED:
835 case LDAP_RES_INTERMEDIATE:
837 /* this is a result - it should be in our unmatched list */
839 lcr.messageId=messageId;
840 lcrp=(ldap_call_response_t *)g_hash_table_lookup(ldap_info->unmatched, &lcr);
844 if(!lcrp->rep_frame){
845 g_hash_table_remove(ldap_info->unmatched, lcrp);
846 lcrp->rep_frame=pinfo->fd->num;
847 lcrp->is_request=FALSE;
848 g_hash_table_insert(ldap_info->matched, lcrp, lcrp);
856 /* we have found a match */
861 if(lcrp->is_request){
862 it=proto_tree_add_uint(tree, hf_ldap_response_in, tvb, 0, 0, lcrp->rep_frame);
863 PROTO_ITEM_SET_GENERATED(it);
866 it=proto_tree_add_uint(tree, hf_ldap_response_to, tvb, 0, 0, lcrp->req_frame);
867 PROTO_ITEM_SET_GENERATED(it);
868 nstime_delta(&ns, &pinfo->fd->abs_ts, &lcrp->req_time);
869 it=proto_tree_add_time(tree, hf_ldap_time, tvb, 0, 0, &ns);
870 PROTO_ITEM_SET_GENERATED(it);
877 #include "packet-ldap-fn.c"
880 dissect_ldap_payload(tvbuff_t *tvb, packet_info *pinfo,
881 proto_tree *tree, ldap_conv_info_t *ldap_info,
885 guint length_remaining;
887 int messageOffset = 0;
888 guint headerLength = 0;
890 tvbuff_t *msg_tvb = NULL;
892 gboolean pc, ind = 0;
895 attributedesc_string=NULL;
900 length_remaining = tvb_ensure_length_remaining(tvb, offset);
902 if (length_remaining < 6) return;
905 * OK, try to read the "Sequence Of" header; this gets the total
906 * length of the LDAP message.
908 messageOffset = get_ber_identifier(tvb, offset, &ber_class, &pc, &ber_tag);
909 messageOffset = get_ber_length(tvb, messageOffset, &msg_len, &ind);
912 if((msg_len<4) || (msg_len>10000000)) return;
914 if ( (ber_class==BER_CLASS_UNI) && (ber_tag==BER_UNI_TAG_SEQUENCE) ) {
916 * Add the length of the "Sequence Of" header to the message
919 headerLength = messageOffset - offset;
920 msg_len += headerLength;
921 if (msg_len < headerLength) {
923 * The message length was probably so large that the total length
926 * Report this as an error.
928 show_reported_bounds_error(tvb, pinfo, tree);
933 * We couldn't parse the header; just make it the amount of data
934 * remaining in the tvbuff, so we'll give up on this segment
935 * after attempting to parse the message - there's nothing more
936 * we can do. "dissect_ldap_message()" will display the error.
938 msg_len = length_remaining;
942 * Construct a tvbuff containing the amount of the payload we have
943 * available. Make its reported length the amount of data in the
946 * XXX - if reassembly isn't enabled. the subdissector will throw a
947 * BoundsError exception, rather than a ReportedBoundsError exception.
948 * We really want a tvbuff where the length is "length", the reported
949 * length is "plen", and the "if the snapshot length were infinite"
950 * length is the minimum of the reported length of the tvbuff handed
951 * to us and "plen", with a new type of exception thrown if the offset
952 * is within the reported length but beyond that third length, with
953 * that exception getting the "Unreassembled Packet" error.
955 length = length_remaining;
956 if (length > msg_len) length = msg_len;
957 msg_tvb = tvb_new_subset(tvb, offset, length, msg_len);
960 * Now dissect the LDAP message.
962 ldap_info->is_mscldap = is_mscldap;
963 pinfo->private_data = ldap_info;
964 dissect_LDAPMessage_PDU(msg_tvb, pinfo, tree);
968 /* If this was a sasl blob there might be another PDU following in the
971 if(tvb_length_remaining(tvb, offset)>=6){
972 tvb = tvb_new_subset(tvb, offset, tvb_length_remaining(tvb, offset), -1);
983 ldap_found_in_frame = FALSE;
985 ldapvalue_string = NULL;
987 attributedesc_string = NULL;
988 Filter_string = NULL;
989 and_filter_string = NULL;
990 object_identifier_id = NULL;
991 or_filter_string = NULL;
993 substring_item_any = NULL;
994 substring_item_final = NULL;
995 substring_item_init = NULL;
996 substring_value = NULL;
1000 Filter_elements = 0;
1002 do_protocolop = FALSE;
1005 /* seems to be ok, but reset just in case */
1006 matching_rule_string = NULL;
1010 dissect_ldap_pdu(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, gboolean is_mscldap)
1013 conversation_t *conversation;
1014 gboolean doing_sasl_security = FALSE;
1015 guint length_remaining;
1016 ldap_conv_info_t *ldap_info = NULL;
1017 proto_item *ldap_item = NULL;
1018 proto_tree *ldap_tree = NULL;
1022 conversation = find_or_create_conversation(pinfo);
1025 * Do we already have a type and mechanism?
1027 ldap_info = (ldap_conv_info_t *)conversation_get_proto_data(conversation, proto_ldap);
1028 if (ldap_info == NULL) {
1029 /* No. Attach that information to the conversation, and add
1030 * it to the list of information structures.
1032 ldap_info = g_new0(ldap_conv_info_t,1);
1033 ldap_info->matched=g_hash_table_new(ldap_info_hash_matched, ldap_info_equal_matched);
1034 ldap_info->unmatched=g_hash_table_new(ldap_info_hash_unmatched, ldap_info_equal_unmatched);
1036 conversation_add_proto_data(conversation, proto_ldap, ldap_info);
1038 ldap_info->next = ldap_info_items;
1039 ldap_info_items = ldap_info;
1043 switch (ldap_info->auth_type) {
1044 case LDAP_AUTH_SASL:
1046 * It's SASL; are we using a security layer?
1048 if (ldap_info->first_auth_frame != 0 &&
1049 pinfo->fd->num >= ldap_info->first_auth_frame) {
1050 doing_sasl_security = TRUE; /* yes */
1054 length_remaining = tvb_ensure_length_remaining(tvb, offset);
1056 /* It might still be a packet containing a SASL security layer
1057 * but its just that we never saw the BIND packet.
1058 * check if it looks like it could be a SASL blob here
1059 * and in that case just assume it is GSS-SPNEGO
1061 if(!doing_sasl_security && (tvb_bytes_exist(tvb, offset, 5))
1062 &&(tvb_get_ntohl(tvb, offset)<=(guint)(tvb_reported_length_remaining(tvb, offset)-4))
1063 &&(tvb_get_guint8(tvb, offset+4)==0x60) ){
1064 ldap_info->auth_type=LDAP_AUTH_SASL;
1065 ldap_info->first_auth_frame=pinfo->fd->num;
1066 ldap_info->auth_mech=g_strdup("GSS-SPNEGO");
1067 doing_sasl_security=TRUE;
1071 * This is the first PDU, set the Protocol column and clear the
1074 col_set_str(pinfo->cinfo, COL_PROTOCOL, pinfo->current_proto);
1076 if(ldap_found_in_frame) {
1077 /* we have already dissected an ldap PDU in this frame - add a separator and set a fence */
1078 col_append_str(pinfo->cinfo, COL_INFO, " | ");
1079 col_set_fence(pinfo->cinfo, COL_INFO);
1081 col_clear(pinfo->cinfo, COL_INFO);
1082 register_frame_end_routine (ldap_frame_end);
1083 ldap_found_in_frame = TRUE;
1086 ldap_item = proto_tree_add_item(tree, is_mscldap?proto_cldap:proto_ldap, tvb, 0, -1, ENC_NA);
1087 ldap_tree = proto_item_add_subtree(ldap_item, ett_ldap);
1090 * Might we be doing a SASL security layer and, if so, *are* we doing
1093 * Just because we've seen a bind reply for SASL, that doesn't mean
1094 * that we're using a SASL security layer; I've seen captures in
1095 * which some SASL negotiations lead to a security layer being used
1096 * and other negotiations don't, and it's not obvious what's different
1097 * in the two negotiations. Therefore, we assume that if the first
1098 * byte is 0, it's a length for a SASL security layer (that way, we
1099 * never reassemble more than 16 megabytes, protecting us from
1100 * chewing up *too* much memory), and otherwise that it's an LDAP
1101 * message (actually, if it's an LDAP message it should begin with 0x30,
1102 * but we want to parse garbage as LDAP messages rather than really
1106 if (doing_sasl_security && tvb_get_guint8(tvb, offset) == 0) {
1107 proto_item *sasl_item = NULL;
1108 proto_tree *sasl_tree = NULL;
1110 guint sasl_len, sasl_msg_len, length;
1112 * Yes. The frame begins with a 4-byte big-endian length.
1113 * And we know we have at least 6 bytes
1117 * Get the SASL length, which is the length of data in the buffer
1118 * following the length (i.e., it's 4 less than the total length).
1120 * XXX - do we need to reassemble buffers? For now, we
1121 * assume that each LDAP message is entirely contained within
1124 sasl_len = tvb_get_ntohl(tvb, offset);
1125 sasl_msg_len = sasl_len + 4;
1126 if (sasl_msg_len < 4) {
1128 * The message length was probably so large that the total length
1131 * Report this as an error.
1133 show_reported_bounds_error(tvb, pinfo, tree);
1138 * Construct a tvbuff containing the amount of the payload we have
1139 * available. Make its reported length the amount of data in the PDU.
1141 * XXX - if reassembly isn't enabled. the subdissector will throw a
1142 * BoundsError exception, rather than a ReportedBoundsError exception.
1143 * We really want a tvbuff where the length is "length", the reported
1144 * length is "plen", and the "if the snapshot length were infinite"
1145 * length is the minimum of the reported length of the tvbuff handed
1146 * to us and "plen", with a new type of exception thrown if the offset
1147 * is within the reported length but beyond that third length, with
1148 * that exception getting the "Unreassembled Packet" error.
1150 length = length_remaining;
1151 if (length > sasl_msg_len) length = sasl_msg_len;
1152 sasl_tvb = tvb_new_subset(tvb, offset, length, sasl_msg_len);
1155 proto_tree_add_uint(ldap_tree, hf_ldap_sasl_buffer_length, sasl_tvb, 0, 4,
1158 sasl_item = proto_tree_add_text(ldap_tree, sasl_tvb, 0, sasl_msg_len, "SASL Buffer");
1159 sasl_tree = proto_item_add_subtree(sasl_item, ett_ldap_sasl_blob);
1162 if (ldap_info->auth_mech != NULL &&
1163 ((strcmp(ldap_info->auth_mech, "GSS-SPNEGO") == 0) ||
1164 /* auth_mech may have been set from the bind */
1165 (strcmp(ldap_info->auth_mech, "GSSAPI") == 0))) {
1166 tvbuff_t *gssapi_tvb, *plain_tvb = NULL, *decr_tvb= NULL;
1171 * This is GSS-API (using SPNEGO, but we should be done with
1172 * the negotiation by now).
1174 * Dissect the GSS_Wrap() token; it'll return the length of
1175 * the token, from which we compute the offset in the tvbuff at
1176 * which the plaintext data, i.e. the LDAP message, begins.
1178 tmp_length = tvb_length_remaining(sasl_tvb, 4);
1179 if ((guint)tmp_length > sasl_len)
1180 tmp_length = sasl_len;
1181 gssapi_tvb = tvb_new_subset(sasl_tvb, 4, tmp_length, sasl_len);
1183 /* Attempt decryption of the GSSAPI wrapped data if possible */
1184 pinfo->decrypt_gssapi_tvb=DECRYPT_GSSAPI_NORMAL;
1185 pinfo->gssapi_wrap_tvb=NULL;
1186 pinfo->gssapi_encrypted_tvb=NULL;
1187 pinfo->gssapi_decrypted_tvb=NULL;
1188 ver_len = call_dissector(gssapi_wrap_handle, gssapi_tvb, pinfo, sasl_tree);
1189 /* if we could unwrap, do a tvb shuffle */
1190 if(pinfo->gssapi_decrypted_tvb){
1191 decr_tvb=pinfo->gssapi_decrypted_tvb;
1194 pinfo->decrypt_gssapi_tvb=0;
1195 pinfo->gssapi_wrap_tvb=NULL;
1196 pinfo->gssapi_encrypted_tvb=NULL;
1197 pinfo->gssapi_decrypted_tvb=NULL;
1200 * if len is 0 it probably mean that we got a PDU that is not
1201 * aligned to the start of the segment.
1208 * if we don't have unwrapped data,
1209 * see if the wrapping involved encryption of the
1210 * data; if not, just use the plaintext data.
1213 if(!pinfo->gssapi_data_encrypted){
1214 plain_tvb = tvb_new_subset_remaining(gssapi_tvb, ver_len);
1219 proto_item *enc_item = NULL;
1220 proto_tree *enc_tree = NULL;
1223 * The LDAP message was encrypted in the packet, and has
1224 * been decrypted; dissect the decrypted LDAP message.
1226 col_set_str(pinfo->cinfo, COL_INFO, "SASL GSS-API Privacy (decrypted): ");
1229 enc_item = proto_tree_add_text(sasl_tree, gssapi_tvb, ver_len, -1,
1230 "GSS-API Encrypted payload (%d byte%s)",
1232 plurality(sasl_len - ver_len, "", "s"));
1233 enc_tree = proto_item_add_subtree(enc_item, ett_ldap_payload);
1235 dissect_ldap_payload(decr_tvb, pinfo, enc_tree, ldap_info, is_mscldap);
1236 } else if (plain_tvb) {
1237 proto_item *plain_item = NULL;
1238 proto_tree *plain_tree = NULL;
1241 * The LDAP message wasn't encrypted in the packet;
1242 * dissect the plain LDAP message.
1244 col_set_str(pinfo->cinfo, COL_INFO, "SASL GSS-API Integrity: ");
1247 plain_item = proto_tree_add_text(sasl_tree, gssapi_tvb, ver_len, -1,
1248 "GSS-API payload (%d byte%s)",
1250 plurality(sasl_len - ver_len, "", "s"));
1251 plain_tree = proto_item_add_subtree(plain_item, ett_ldap_payload);
1254 dissect_ldap_payload(plain_tvb, pinfo, plain_tree, ldap_info, is_mscldap);
1257 * The LDAP message was encrypted in the packet, and was
1258 * not decrypted; just show it as encrypted data.
1260 col_add_fstr(pinfo->cinfo, COL_INFO, "SASL GSS-API Privacy: payload (%d byte%s)",
1262 plurality(sasl_len - ver_len, "", "s"));
1265 proto_tree_add_text(sasl_tree, gssapi_tvb, ver_len, -1,
1266 "GSS-API Encrypted payload (%d byte%s)",
1268 plurality(sasl_len - ver_len, "", "s"));
1273 /* plain LDAP, so dissect the payload */
1274 dissect_ldap_payload(tvb, pinfo, ldap_tree, ldap_info, is_mscldap);
1279 * prepend_dot is no longer used, but is being left in place in order to
1280 * maintain ABI compatibility.
1282 int dissect_mscldap_string(tvbuff_t *tvb, int offset, char *str, int max_len, gboolean prepend_dot _U_)
1287 /* The name data MUST start at offset 0 of the tvb */
1288 compr_len = expand_dns_name(tvb, offset, max_len, 0, &name);
1289 g_strlcpy(str, name, max_len);
1290 return offset + compr_len;
1294 /* These are the cldap DC flags
1295 http://msdn.microsoft.com/en-us/library/cc201036.aspx
1297 static const true_false_string tfs_ads_pdc = {
1301 static const true_false_string tfs_ads_gc = {
1302 "This is a GLOBAL CATALOGUE of forest",
1303 "This is NOT a global catalog of forest"
1305 static const true_false_string tfs_ads_ldap = {
1306 "This is an LDAP server",
1307 "This is NOT an ldap server"
1309 static const true_false_string tfs_ads_ds = {
1310 "This dc supports DS",
1311 "This dc does NOT support ds"
1313 static const true_false_string tfs_ads_kdc = {
1314 "This is a KDC (kerberos)",
1315 "This is NOT a kdc (kerberos)"
1317 static const true_false_string tfs_ads_timeserv = {
1318 "This dc is running TIME SERVICES (ntp)",
1319 "This dc is NOT running time services (ntp)"
1321 static const true_false_string tfs_ads_closest = {
1322 "This server is in the same site as the client",
1323 "This server is NOT in the same site as the client"
1325 static const true_false_string tfs_ads_writable = {
1326 "This dc is WRITABLE",
1327 "This dc is NOT writable"
1329 static const true_false_string tfs_ads_good_timeserv = {
1330 "This dc has a GOOD TIME SERVICE (i.e. hardware clock)",
1331 "This dc does NOT have a good time service (i.e. no hardware clock)"
1333 static const true_false_string tfs_ads_ndnc = {
1334 "Domain is NON-DOMAIN NC serviced by ldap server",
1335 "Domain is NOT non-domain nc serviced by ldap server"
1337 static const true_false_string tfs_ads_rodc = {
1338 "Domain controller is a Windows 2008 RODC",
1339 "Domain controller is not a Windows 2008 RODC"
1341 static const true_false_string tfs_ads_wdc = {
1342 "Domain controller is a Windows 2008 writable NC",
1343 "Domain controller is not a Windows 2008 writable NC"
1345 static const true_false_string tfs_ads_dns = {
1346 "Server name is in DNS format (Windows 2008)",
1347 "Server name is not in DNS format (Windows 2008)"
1349 static const true_false_string tfs_ads_dnc = {
1350 "The NC is the default NC (Windows 2008)",
1351 "The NC is not the default NC (Windows 2008)"
1353 static const true_false_string tfs_ads_fnc = {
1354 "The NC is the default forest NC(Windows 2008)",
1355 "The NC is not the default forest NC (Windows 2008)"
1357 static int dissect_mscldap_netlogon_flags(proto_tree *parent_tree, tvbuff_t *tvb, int offset)
1361 proto_tree *tree=NULL;
1363 hf_mscldap_netlogon_flags_fnc,
1364 hf_mscldap_netlogon_flags_dnc,
1365 hf_mscldap_netlogon_flags_dns,
1366 hf_mscldap_netlogon_flags_wdc,
1367 hf_mscldap_netlogon_flags_rodc,
1368 hf_mscldap_netlogon_flags_ndnc,
1369 hf_mscldap_netlogon_flags_good_timeserv,
1370 hf_mscldap_netlogon_flags_writable,
1371 hf_mscldap_netlogon_flags_closest,
1372 hf_mscldap_netlogon_flags_timeserv,
1373 hf_mscldap_netlogon_flags_kdc,
1374 hf_mscldap_netlogon_flags_ds,
1375 hf_mscldap_netlogon_flags_ldap,
1376 hf_mscldap_netlogon_flags_gc,
1377 hf_mscldap_netlogon_flags_pdc,
1380 header_field_info *hfi;
1381 gboolean one_bit_set = FALSE;
1383 flags=tvb_get_letohl(tvb, offset);
1384 item=proto_tree_add_item(parent_tree, hf_mscldap_netlogon_flags, tvb, offset, 4, ENC_LITTLE_ENDIAN);
1386 tree = proto_item_add_subtree(item, ett_mscldap_netlogon_flags);
1389 proto_item_append_text(item, " (");
1391 for(field = fields; *field; field++) {
1392 proto_tree_add_boolean(tree, *field, tvb, offset, 4, flags);
1393 hfi = proto_registrar_get_nth(*field);
1395 if(flags & hfi->bitmask) {
1398 proto_item_append_text(item, ", ");
1402 proto_item_append_text(item, "%s", hfi->name);
1407 proto_item_append_text(item, ")");
1414 static void dissect_NetLogon_PDU(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree)
1416 int old_offset, offset=0;
1429 /* Get the length of the buffer */
1430 len=tvb_length_remaining(tvb,offset);
1432 /* check the len if it is to small return */
1433 if (len < 10) return;
1436 proto_tree_add_item(tree, hf_mscldap_netlogon_opcode, tvb, offset, 2, ENC_LITTLE_ENDIAN);
1437 itype = tvb_get_letohs(tvb, offset);
1440 /* get the version number from the end of the buffer, as the
1441 length is variable and the version determines what fields
1442 need to be decoded */
1444 version = tvb_get_letohl(tvb,len-8);
1448 case LOGON_SAM_LOGON_RESPONSE:
1449 bc = tvb_length_remaining(tvb, offset);
1450 /* logon server name */
1451 fn = get_unicode_or_ascii_string(tvb,&offset,TRUE,&fn_len,FALSE,FALSE,&bc);
1452 proto_tree_add_string(tree, hf_mscldap_nb_hostname, tvb,offset, fn_len, fn);
1456 fn = get_unicode_or_ascii_string(tvb,&offset,TRUE,&fn_len,FALSE,FALSE,&bc);
1457 proto_tree_add_string(tree, hf_mscldap_username, tvb,offset, fn_len, fn);
1461 fn = get_unicode_or_ascii_string(tvb,&offset,TRUE,&fn_len,FALSE,FALSE,&bc);
1462 proto_tree_add_string(tree, hf_mscldap_nb_domain, tvb,offset, fn_len, fn);
1465 /* include the extra version 5 fields */
1466 if ((version & NETLOGON_NT_VERSION_5) == NETLOGON_NT_VERSION_5){
1469 proto_tree_add_item(tree, hf_mscldap_domain_guid, tvb, offset, 16, ENC_LITTLE_ENDIAN);
1472 /* domain guid part 2
1473 there is another 16 byte guid but this is alway zero, so we will skip it */
1478 offset=dissect_mscldap_string(tvb, offset, str, 255, FALSE);
1479 proto_tree_add_string(tree, hf_mscldap_forest, tvb, old_offset, offset-old_offset, str);
1483 offset=dissect_mscldap_string(tvb, offset, str, 255, FALSE);
1484 proto_tree_add_string(tree, hf_mscldap_domain, tvb, old_offset, offset-old_offset, str);
1488 offset=dissect_mscldap_string(tvb, offset, str, 255, FALSE);
1489 proto_tree_add_string(tree, hf_mscldap_hostname, tvb, old_offset, offset-old_offset, str);
1492 proto_tree_add_ipv4(tree, hf_mscldap_netlogon_ipaddress, tvb, offset, 4, tvb_get_ntohl(tvb,offset));
1496 offset = dissect_mscldap_netlogon_flags(tree, tvb, offset);
1502 case LOGON_SAM_LOGON_RESPONSE_EX:
1503 /* MS-ADTS 7.3.1.9 */
1504 offset += 2; /* Skip over "Sbz" field (MUST be set to 0) */
1507 offset = dissect_mscldap_netlogon_flags(tree, tvb, offset);
1510 proto_tree_add_item(tree, hf_mscldap_domain_guid, tvb, offset, 16, ENC_LITTLE_ENDIAN);
1515 offset=dissect_mscldap_string(tvb, offset, str, 255, FALSE);
1516 proto_tree_add_string(tree, hf_mscldap_forest, tvb, old_offset, offset-old_offset, str);
1520 offset=dissect_mscldap_string(tvb, offset, str, 255, FALSE);
1521 proto_tree_add_string(tree, hf_mscldap_domain, tvb, old_offset, offset-old_offset, str);
1525 offset=dissect_mscldap_string(tvb, offset, str, 255, FALSE);
1526 proto_tree_add_string(tree, hf_mscldap_hostname, tvb, old_offset, offset-old_offset, str);
1528 /* NetBIOS Domain */
1530 offset=dissect_mscldap_string(tvb, offset, str, 255, FALSE);
1531 proto_tree_add_string(tree, hf_mscldap_nb_domain, tvb, old_offset, offset-old_offset, str);
1533 /* NetBIOS Hostname */
1535 offset=dissect_mscldap_string(tvb, offset, str, 255, FALSE);
1536 proto_tree_add_string(tree, hf_mscldap_nb_hostname, tvb, old_offset, offset-old_offset, str);
1540 offset=dissect_mscldap_string(tvb, offset, str, 255, FALSE);
1541 proto_tree_add_string(tree, hf_mscldap_username, tvb, old_offset, offset-old_offset, str);
1545 offset=dissect_mscldap_string(tvb, offset, str, 255, FALSE);
1546 proto_tree_add_string(tree, hf_mscldap_sitename, tvb, old_offset, offset-old_offset, str);
1550 offset=dissect_mscldap_string(tvb, offset, str, 255, FALSE);
1551 proto_tree_add_string(tree, hf_mscldap_clientsitename, tvb, old_offset, offset-old_offset, str);
1553 /* include the extra fields for version 5 with IP s */
1554 if ((version & NETLOGON_NT_VERSION_5EX_WITH_IP) == NETLOGON_NT_VERSION_5EX_WITH_IP){
1555 /* The ip address is returned as a sockaddr_in structure
1557 * This section may need to be updated if the base Windows APIs
1558 * are changed to support ipv6, which currently is not the case.
1560 * The desector assumes the length is based on ipv4 and
1561 * ignores the length
1564 /* skip the length of the sockaddr_in */
1568 /* add IP address and desect the sockaddr_in structure */
1570 old_offset = offset + 4;
1571 item = proto_tree_add_ipv4(tree, hf_mscldap_netlogon_ipaddress, tvb, old_offset, 4, tvb_get_ipv4(tvb,old_offset));
1574 proto_tree *subtree;
1576 subtree = proto_item_add_subtree(item, ett_mscldap_ipdetails);
1578 /* get sockaddr family */
1579 proto_tree_add_item(subtree, hf_mscldap_netlogon_ipaddress_family, tvb, offset, 2, ENC_LITTLE_ENDIAN);
1582 /* get sockaddr port */
1583 proto_tree_add_item(subtree, hf_mscldap_netlogon_ipaddress_port, tvb, offset, 2, ENC_LITTLE_ENDIAN);
1586 /* get IP address */
1587 proto_tree_add_ipv4(subtree, hf_mscldap_netlogon_ipaddress_ipv4, tvb, offset, 4, tvb_get_ipv4(tvb,offset));
1590 /* skip the 8 bytes of zeros in the sockaddr structure */
1600 /* complete the decode with the version and token details */
1604 /* NETLOGON_NT_VERISON Options (MS-ADTS 7.3.1.1) */
1605 offset = dissect_mscldap_ntver_flags(tree, tvb, offset);
1608 proto_tree_add_item(tree, hf_mscldap_netlogon_lm_token, tvb, offset, 2, ENC_LITTLE_ENDIAN);
1612 proto_tree_add_item(tree, hf_mscldap_netlogon_nt_token, tvb, offset, 2, ENC_LITTLE_ENDIAN);
1619 get_sasl_ldap_pdu_len(packet_info *pinfo _U_, tvbuff_t *tvb, int offset)
1621 /* sasl encapsulated ldap is 4 bytes plus the length in size */
1622 return tvb_get_ntohl(tvb, offset)+4;
1626 dissect_sasl_ldap_pdu(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
1628 dissect_ldap_pdu(tvb, pinfo, tree, FALSE);
1633 get_normal_ldap_pdu_len(packet_info *pinfo _U_, tvbuff_t *tvb, int offset)
1639 /* normal ldap is tag+len bytes plus the length
1640 * offset is where the tag is
1641 * offset+1 is where length starts
1643 data_offset=get_ber_length(tvb, offset+1, &len, &ind);
1644 return len+data_offset-offset;
1648 dissect_normal_ldap_pdu(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
1650 dissect_ldap_pdu(tvb, pinfo, tree, FALSE);
1655 dissect_ldap_oid(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree)
1658 const char *oidname;
1660 /* tvb here contains an ascii string that is really an oid */
1661 /* XXX we should convert the string oid into a real oid so we can use
1662 * proto_tree_add_oid() instead.
1665 oid=tvb_get_ephemeral_string(tvb, 0, tvb_length(tvb));
1670 oidname=oid_resolved_from_string(oid);
1673 proto_tree_add_text(tree, tvb, 0, tvb_length(tvb), "OID: %s (%s)",oid,oidname);
1675 proto_tree_add_text(tree, tvb, 0, tvb_length(tvb), "OID: %s",oid);
1679 #define LDAP_ACCESSMASK_ADS_CREATE_CHILD 0x00000001
1680 static const true_false_string ldap_AccessMask_ADS_CREATE_CHILD_tfs = {
1681 "ADS CREATE CHILD is SET",
1682 "Ads create child is NOT set",
1685 #define LDAP_ACCESSMASK_ADS_DELETE_CHILD 0x00000002
1686 static const true_false_string ldap_AccessMask_ADS_DELETE_CHILD_tfs = {
1687 "ADS DELETE CHILD is SET",
1688 "Ads delete child is NOT set",
1690 #define LDAP_ACCESSMASK_ADS_LIST 0x00000004
1691 static const true_false_string ldap_AccessMask_ADS_LIST_tfs = {
1693 "Ads list is NOT set",
1695 #define LDAP_ACCESSMASK_ADS_SELF_WRITE 0x00000008
1696 static const true_false_string ldap_AccessMask_ADS_SELF_WRITE_tfs = {
1697 "ADS SELF WRITE is SET",
1698 "Ads self write is NOT set",
1700 #define LDAP_ACCESSMASK_ADS_READ_PROP 0x00000010
1701 static const true_false_string ldap_AccessMask_ADS_READ_PROP_tfs = {
1702 "ADS READ PROP is SET",
1703 "Ads read prop is NOT set",
1705 #define LDAP_ACCESSMASK_ADS_WRITE_PROP 0x00000020
1706 static const true_false_string ldap_AccessMask_ADS_WRITE_PROP_tfs = {
1707 "ADS WRITE PROP is SET",
1708 "Ads write prop is NOT set",
1710 #define LDAP_ACCESSMASK_ADS_DELETE_TREE 0x00000040
1711 static const true_false_string ldap_AccessMask_ADS_DELETE_TREE_tfs = {
1712 "ADS DELETE TREE is SET",
1713 "Ads delete tree is NOT set",
1715 #define LDAP_ACCESSMASK_ADS_LIST_OBJECT 0x00000080
1716 static const true_false_string ldap_AccessMask_ADS_LIST_OBJECT_tfs = {
1717 "ADS LIST OBJECT is SET",
1718 "Ads list object is NOT set",
1720 #define LDAP_ACCESSMASK_ADS_CONTROL_ACCESS 0x00000100
1721 static const true_false_string ldap_AccessMask_ADS_CONTROL_ACCESS_tfs = {
1722 "ADS CONTROL ACCESS is SET",
1723 "Ads control access is NOT set",
1727 ldap_specific_rights(tvbuff_t *tvb, gint offset, proto_tree *tree, guint32 access)
1729 proto_tree_add_boolean(tree, hf_ldap_AccessMask_ADS_CONTROL_ACCESS, tvb, offset, 4, access);
1731 proto_tree_add_boolean(tree, hf_ldap_AccessMask_ADS_LIST_OBJECT, tvb, offset, 4, access);
1733 proto_tree_add_boolean(tree, hf_ldap_AccessMask_ADS_DELETE_TREE, tvb, offset, 4, access);
1735 proto_tree_add_boolean(tree, hf_ldap_AccessMask_ADS_WRITE_PROP, tvb, offset, 4, access);
1737 proto_tree_add_boolean(tree, hf_ldap_AccessMask_ADS_READ_PROP, tvb, offset, 4, access);
1739 proto_tree_add_boolean(tree, hf_ldap_AccessMask_ADS_SELF_WRITE, tvb, offset, 4, access);
1741 proto_tree_add_boolean(tree, hf_ldap_AccessMask_ADS_LIST, tvb, offset, 4, access);
1743 proto_tree_add_boolean(tree, hf_ldap_AccessMask_ADS_DELETE_CHILD, tvb, offset, 4, access);
1745 proto_tree_add_boolean(tree, hf_ldap_AccessMask_ADS_CREATE_CHILD, tvb, offset, 4, access);
1747 struct access_mask_info ldap_access_mask_info = {
1748 "LDAP", /* Name of specific rights */
1749 ldap_specific_rights, /* Dissection function */
1750 NULL, /* Generic mapping table */
1751 NULL /* Standard mapping table */
1755 dissect_ldap_nt_sec_desc(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
1757 dissect_nt_sec_desc(tvb, 0, pinfo, tree, NULL, TRUE, tvb_length(tvb), &ldap_access_mask_info);
1761 dissect_ldap_sid(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree)
1765 /* this octet string contains an NT SID */
1766 dissect_nt_sid(tvb, 0, tree, "SID", &tmpstr, hf_ldap_sid);
1767 ldapvalue_string=tmpstr;
1771 dissect_ldap_guid(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
1773 guint8 drep[4] = { 0x10, 0x00, 0x00, 0x00}; /* fake DREP struct */
1776 /* This octet string contained a GUID */
1777 dissect_dcerpc_uuid_t(tvb, 0, pinfo, tree, drep, hf_ldap_guid, &uuid);
1779 ldapvalue_string=(char*)ep_alloc(1024);
1780 g_snprintf(ldapvalue_string, 1023, "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
1781 uuid.Data1, uuid.Data2, uuid.Data3,
1782 uuid.Data4[0], uuid.Data4[1],
1783 uuid.Data4[2], uuid.Data4[3],
1784 uuid.Data4[4], uuid.Data4[5],
1785 uuid.Data4[6], uuid.Data4[7]);
1789 dissect_ldap_tcp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
1794 conversation_t *conversation;
1795 ldap_conv_info_t *ldap_info = NULL;
1798 * Do we have a conversation for this connection?
1800 conversation = find_conversation(pinfo->fd->num,
1801 &pinfo->src, &pinfo->dst,
1802 pinfo->ptype, pinfo->srcport,
1803 pinfo->destport, 0);
1805 ldap_info = (ldap_conv_info_t *)conversation_get_proto_data(conversation, proto_ldap);
1810 /* This is a bit tricky. We have to find out whether SASL is used
1811 * so that we know how big a header we are supposed to pass
1812 * to tcp_dissect_pdus()
1813 * We must also cope with the case when a client connects to LDAP
1814 * and performs a few unauthenticated searches of LDAP before
1815 * it performs the bind on the same tcp connection.
1817 /* check for a SASL header, i.e. assume it is SASL if
1818 * 1, first four bytes (SASL length) is an integer
1819 * with a value that must be <LDAP_SASL_MAX_BUF and >2
1820 * (>2 to fight false positives, 0x00000000 is a common
1821 * "random" tcp payload)
1822 * (SASL ldap PDUs might be >64k in size, which is why
1823 * LDAP_SASL_MAX_BUF is used - defined in packet-ldap.h)
1825 * 2, we must have a conversation and the auth type must
1828 sasl_len=tvb_get_ntohl(tvb, 0);
1831 goto this_was_not_sasl;
1834 if( sasl_len>LDAP_SASL_MAX_BUF ){
1835 goto this_was_not_sasl;
1838 if((!ldap_info) || (ldap_info->auth_type!=LDAP_AUTH_SASL) ){
1839 goto this_was_not_sasl;
1842 tcp_dissect_pdus(tvb, pinfo, tree, ldap_desegment, 4, get_sasl_ldap_pdu_len, dissect_sasl_ldap_pdu);
1846 /* check if it is a normal BER encoded LDAP packet
1847 * i.e. first byte is 0x30 followed by a length that is
1849 * (no ldap PDUs are ever >64kb? )
1851 if(tvb_get_guint8(tvb, 0)!=0x30){
1852 goto this_was_not_normal_ldap;
1855 /* check that length makes sense */
1856 get_ber_length(tvb, 1, &ldap_len, &ind);
1858 /* dont check ind since indefinite length is never used for ldap (famous last words)*/
1860 goto this_was_not_normal_ldap;
1864 * The minimun size of a LDAP pdu is 7 bytes
1866 * dumpasn1 -hh ldap-unbind-min.dat
1868 * <30 05 02 01 09 42 00>
1873 * 5 0: [APPLICATION 2]
1874 * : Error: Object has zero length.
1877 * dumpasn1 -hh ldap-unbind-windows.dat
1879 * <30 84 00 00 00 05 02 01 09 42 00>
1884 * 9 0: [APPLICATION 2]
1885 * : Error: Object has zero length.
1888 * 6 bytes would also be ok to get the full length of
1889 * the pdu, but as the smallest pdu can be 7 bytes
1892 tcp_dissect_pdus(tvb, pinfo, tree, ldap_desegment, 7, get_normal_ldap_pdu_len, dissect_normal_ldap_pdu);
1896 this_was_not_normal_ldap:
1898 /* perhaps it was SSL? */
1900 ldap_info->start_tls_frame &&
1901 ( pinfo->fd->num >= ldap_info->start_tls_frame)) {
1903 /* we have started TLS and so this may be an SSL layer */
1904 guint32 old_start_tls_frame;
1906 /* temporarily dissect this port as SSL */
1907 dissector_delete_uint("tcp.port", tcp_port, ldap_handle);
1908 ssl_dissector_add(tcp_port, "ldap", TRUE);
1910 old_start_tls_frame = ldap_info->start_tls_frame;
1911 ldap_info->start_tls_frame = 0; /* make sure we don't call SSL again */
1912 pinfo->can_desegment++; /* ignore this LDAP layer so SSL can use the TCP resegment */
1914 call_dissector(ssl_handle, tvb, pinfo, tree);
1916 ldap_info->start_tls_frame = old_start_tls_frame;
1917 ssl_dissector_delete(tcp_port, "ldap", TRUE);
1919 /* restore ldap as the dissector for this port */
1920 dissector_add_uint("tcp.port", tcp_port, ldap_handle);
1925 /* Ok it might be a strange case of SASL still
1926 * It has been seen with Exchange setup to MS AD
1927 * when Exchange pretend that there is SASL but in fact data are still
1929 if ((sasl_len + 4) == (guint32)tvb_length_remaining(tvb, 0))
1930 tcp_dissect_pdus(tvb, pinfo, tree, ldap_desegment, 4, get_sasl_ldap_pdu_len, dissect_sasl_ldap_pdu);
1936 dissect_mscldap(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
1938 dissect_ldap_pdu(tvb, pinfo, tree, TRUE);
1946 ldap_conv_info_t *ldap_info;
1948 /* Free up state attached to the ldap_info structures */
1949 for (ldap_info = ldap_info_items; ldap_info != NULL; ) {
1950 ldap_conv_info_t *next;
1952 g_free(ldap_info->auth_mech);
1953 g_hash_table_destroy(ldap_info->matched);
1954 g_hash_table_destroy(ldap_info->unmatched);
1956 next = ldap_info->next;
1961 ldap_info_items = NULL;
1965 register_ldap_name_dissector_handle(const char *attr_type_p, dissector_handle_t dissector)
1967 dissector_add_string("ldap.name", attr_type_p, dissector);
1971 register_ldap_name_dissector(const char *attr_type_p, dissector_t dissector, int proto)
1973 dissector_handle_t dissector_handle;
1975 dissector_handle=create_dissector_handle(dissector, proto);
1976 register_ldap_name_dissector_handle(attr_type_p, dissector_handle);
1980 /*--- proto_register_ldap -------------------------------------------*/
1981 void proto_register_ldap(void) {
1983 /* List of fields */
1985 static hf_register_info hf[] = {
1987 { &hf_ldap_sasl_buffer_length,
1988 { "SASL Buffer Length", "ldap.sasl_buffer_length",
1989 FT_UINT32, BASE_DEC, NULL, 0x0,
1991 { &hf_ldap_response_in,
1992 { "Response In", "ldap.response_in",
1993 FT_FRAMENUM, BASE_NONE, NULL, 0x0,
1994 "The response to this LDAP request is in this frame", HFILL }},
1995 { &hf_ldap_response_to,
1996 { "Response To", "ldap.response_to",
1997 FT_FRAMENUM, BASE_NONE, NULL, 0x0,
1998 "This is a response to the LDAP request in this frame", HFILL }},
2000 { "Time", "ldap.time",
2001 FT_RELATIVE_TIME, BASE_NONE, NULL, 0x0,
2002 "The time between the Call and the Reply", HFILL }},
2004 { &hf_mscldap_netlogon_opcode,
2005 { "Operation code", "mscldap.netlogon.opcode",
2006 FT_UINT16, BASE_DEC, VALS(netlogon_opcode_vals), 0x0,
2007 "LDAP ping operation code", HFILL }},
2009 { &hf_mscldap_netlogon_ipaddress_family,
2010 { "Family", "mscldap.netlogon.ipaddress.family",
2011 FT_UINT16, BASE_DEC, NULL, 0x0,
2014 { &hf_mscldap_netlogon_ipaddress_ipv4,
2015 { "IPv4", "mscldap.netlogon.ipaddress.ipv4",
2016 FT_IPv4, BASE_NONE, NULL, 0x0,
2017 "IP Address", HFILL }},
2019 { &hf_mscldap_netlogon_ipaddress_port,
2020 { "Port", "mscldap.netlogon.ipaddress.port",
2021 FT_UINT16, BASE_DEC, NULL, 0x0,
2024 { &hf_mscldap_netlogon_ipaddress,
2025 { "IP Address","mscldap.netlogon.ipaddress",
2026 FT_IPv4, BASE_NONE, NULL, 0x0,
2027 "Domain Controller IP Address", HFILL }},
2029 { &hf_mscldap_netlogon_lm_token,
2030 { "LM Token", "mscldap.netlogon.lm_token",
2031 FT_UINT16, BASE_HEX, NULL, 0x0,
2032 "MUST be set to 0xFFFF", HFILL }},
2034 { &hf_mscldap_netlogon_nt_token,
2035 { "NT Token", "mscldap.netlogon.nt_token",
2036 FT_UINT16, BASE_HEX, NULL, 0x0,
2037 "MUST be set to 0xFFFF", HFILL }},
2039 { &hf_mscldap_netlogon_flags,
2040 { "Flags", "mscldap.netlogon.flags",
2041 FT_UINT32, BASE_HEX, NULL, 0x0,
2042 "Netlogon flags describing the DC properties", HFILL }},
2044 { &hf_mscldap_ntver_flags,
2045 { "Version Flags", "mscldap.ntver.flags",
2046 FT_UINT32, BASE_HEX, NULL, 0x0,
2047 "NETLOGON_NT_VERSION Options Bits", HFILL }},
2049 { &hf_mscldap_domain_guid,
2050 { "Domain GUID", "mscldap.domain.guid",
2051 FT_GUID, BASE_NONE, NULL, 0x0,
2052 "Value of the NC's GUID attribute", HFILL }},
2054 { &hf_mscldap_forest,
2055 { "Forest", "mscldap.forest",
2056 FT_STRING, BASE_NONE, NULL, 0x0,
2057 "DNS name of the forest", HFILL }},
2059 { &hf_mscldap_domain,
2060 { "Domain", "mscldap.domain",
2061 FT_STRING, BASE_NONE, NULL, 0x0,
2062 "DNS name of the NC", HFILL }},
2064 { &hf_mscldap_hostname,
2065 { "Hostname", "mscldap.hostname",
2066 FT_STRING, BASE_NONE, NULL, 0x0,
2067 "DNS name of server", HFILL }},
2069 { &hf_mscldap_nb_domain,
2070 { "NetBIOS Domain", "mscldap.nb_domain",
2071 FT_STRING, BASE_NONE, NULL, 0x0,
2072 "NetBIOS name of the NC", HFILL }},
2074 { &hf_mscldap_nb_hostname,
2075 { "NetBIOS Hostname", "mscldap.nb_hostname",
2076 FT_STRING, BASE_NONE, NULL, 0x0,
2077 "NetBIOS name of the server", HFILL }},
2079 { &hf_mscldap_username,
2080 { "Username", "mscldap.username",
2081 FT_STRING, BASE_NONE, NULL, 0x0,
2082 "User specified in client's request", HFILL }},
2084 { &hf_mscldap_sitename,
2085 { "Server Site", "mscldap.sitename",
2086 FT_STRING, BASE_NONE, NULL, 0x0,
2087 "Site name of the server", HFILL }},
2089 { &hf_mscldap_clientsitename,
2090 { "Client Site", "mscldap.clientsitename",
2091 FT_STRING, BASE_NONE, NULL, 0x0,
2092 "Site name of the client", HFILL }},
2095 { "Sid", "ldap.sid",
2096 FT_STRING, BASE_NONE, NULL, 0x0,
2099 { &hf_mscldap_ntver_flags_v1,
2100 { "V1", "mscldap.ntver.searchflags.v1", FT_BOOLEAN, 32,
2101 TFS(&tfs_ntver_v1), 0x00000001, "See section 7.3.1.1 of MS-ADTS specification", HFILL }},
2103 { &hf_mscldap_ntver_flags_v5,
2104 { "V5", "mscldap.ntver.searchflags.v5", FT_BOOLEAN, 32,
2105 TFS(&tfs_ntver_v5), 0x00000002, "See section 7.3.1.1 of MS-ADTS specification", HFILL }},
2107 { &hf_mscldap_ntver_flags_v5ex,
2108 { "V5EX", "mscldap.ntver.searchflags.v5ex", FT_BOOLEAN, 32,
2109 TFS(&tfs_ntver_v5ex), 0x00000004, "See section 7.3.1.1 of MS-ADTS specification", HFILL }},
2111 { &hf_mscldap_ntver_flags_v5ep,
2112 { "V5EP", "mscldap.ntver.searchflags.v5ep", FT_BOOLEAN, 32,
2113 TFS(&tfs_ntver_v5ep), 0x00000008, "See section 7.3.1.1 of MS-ADTS specification", HFILL }},
2115 { &hf_mscldap_ntver_flags_vcs,
2116 { "VCS", "mscldap.ntver.searchflags.vcs", FT_BOOLEAN, 32,
2117 TFS(&tfs_ntver_vcs), 0x00000010, "See section 7.3.1.1 of MS-ADTS specification", HFILL }},
2119 { &hf_mscldap_ntver_flags_vnt4,
2120 { "VNT4", "mscldap.ntver.searchflags.vnt4", FT_BOOLEAN, 32,
2121 TFS(&tfs_ntver_vnt4), 0x01000000, "See section 7.3.1.1 of MS-ADTS specification", HFILL }},
2123 { &hf_mscldap_ntver_flags_vpdc,
2124 { "VPDC", "mscldap.ntver.searchflags.vpdc", FT_BOOLEAN, 32,
2125 TFS(&tfs_ntver_vpdc), 0x10000000, "See section 7.3.1.1 of MS-ADTS specification", HFILL }},
2127 { &hf_mscldap_ntver_flags_vip,
2128 { "VIP", "mscldap.ntver.searchflags.vip", FT_BOOLEAN, 32,
2129 TFS(&tfs_ntver_vip), 0x20000000, "See section 7.3.1.1 of MS-ADTS specification", HFILL }},
2131 { &hf_mscldap_ntver_flags_vl,
2132 { "VL", "mscldap.ntver.searchflags.vl", FT_BOOLEAN, 32,
2133 TFS(&tfs_ntver_vl), 0x40000000, "See section 7.3.1.1 of MS-ADTS specification", HFILL }},
2135 { &hf_mscldap_ntver_flags_vgc,
2136 { "VGC", "mscldap.ntver.searchflags.vgc", FT_BOOLEAN, 32,
2137 TFS(&tfs_ntver_vgc), 0x80000000, "See section 7.3.1.1 of MS-ADTS specification", HFILL }},
2140 { &hf_mscldap_netlogon_flags_pdc,
2141 { "PDC", "mscldap.netlogon.flags.pdc", FT_BOOLEAN, 32,
2142 TFS(&tfs_ads_pdc), 0x00000001, "Is this DC a PDC or not?", HFILL }},
2144 { &hf_mscldap_netlogon_flags_gc,
2145 { "GC", "mscldap.netlogon.flags.gc", FT_BOOLEAN, 32,
2146 TFS(&tfs_ads_gc), 0x00000004, "Does this dc service as a GLOBAL CATALOGUE?", HFILL }},
2148 { &hf_mscldap_netlogon_flags_ldap,
2149 { "LDAP", "mscldap.netlogon.flags.ldap", FT_BOOLEAN, 32,
2150 TFS(&tfs_ads_ldap), 0x00000008, "Does this DC act as an LDAP server?", HFILL }},
2152 { &hf_mscldap_netlogon_flags_ds,
2153 { "DS", "mscldap.netlogon.flags.ds", FT_BOOLEAN, 32,
2154 TFS(&tfs_ads_ds), 0x00000010, "Does this dc provide DS services?", HFILL }},
2156 { &hf_mscldap_netlogon_flags_kdc,
2157 { "KDC", "mscldap.netlogon.flags.kdc", FT_BOOLEAN, 32,
2158 TFS(&tfs_ads_kdc), 0x00000020, "Does this dc act as a KDC?", HFILL }},
2160 { &hf_mscldap_netlogon_flags_timeserv,
2161 { "Time Serv", "mscldap.netlogon.flags.timeserv", FT_BOOLEAN, 32,
2162 TFS(&tfs_ads_timeserv), 0x00000040, "Does this dc provide time services (ntp) ?", HFILL }},
2164 { &hf_mscldap_netlogon_flags_closest,
2165 { "Closest", "mscldap.netlogon.flags.closest", FT_BOOLEAN, 32,
2166 TFS(&tfs_ads_closest), 0x00000080, "Is this the closest dc?", HFILL }},
2168 { &hf_mscldap_netlogon_flags_writable,
2169 { "Writable", "mscldap.netlogon.flags.writable", FT_BOOLEAN, 32,
2170 TFS(&tfs_ads_writable), 0x00000100, "Is this dc writable?", HFILL }},
2172 { &hf_mscldap_netlogon_flags_good_timeserv,
2173 { "Good Time Serv", "mscldap.netlogon.flags.good_timeserv", FT_BOOLEAN, 32,
2174 TFS(&tfs_ads_good_timeserv), 0x00000200, "Is this a Good Time Server? (i.e. does it have a hardware clock)", HFILL }},
2176 { &hf_mscldap_netlogon_flags_ndnc,
2177 { "NDNC", "mscldap.netlogon.flags.ndnc", FT_BOOLEAN, 32,
2178 TFS(&tfs_ads_ndnc), 0x00000400, "Is this an NDNC dc?", HFILL }},
2180 { &hf_mscldap_netlogon_flags_rodc,
2181 { "RODC", "mscldap.netlogon.flags.rodc", FT_BOOLEAN, 32,
2182 TFS(&tfs_ads_rodc), 0x00000800, "Is this an read only dc?", HFILL }},
2184 { &hf_mscldap_netlogon_flags_wdc,
2185 { "WDC", "mscldap.netlogon.flags.writabledc.", FT_BOOLEAN, 32,
2186 TFS(&tfs_ads_wdc), 0x00001000, "Is this an writable dc (Windows 2008)?", HFILL }},
2188 { &hf_mscldap_netlogon_flags_dns,
2189 { "DNS", "mscldap.netlogon.flags.dnsname", FT_BOOLEAN, 32,
2190 TFS(&tfs_ads_dns), 0x20000000, "Does the server have a dns name (Windows 2008)?", HFILL }},
2192 { &hf_mscldap_netlogon_flags_dnc,
2193 { "DNC", "mscldap.netlogon.flags.defaultnc", FT_BOOLEAN, 32,
2194 TFS(&tfs_ads_dnc), 0x40000000, "Is this the default NC (Windows 2008)?", HFILL }},
2196 { &hf_mscldap_netlogon_flags_fnc,
2197 { "FDC", "mscldap.netlogon.flags.forestnc", FT_BOOLEAN, 32,
2198 TFS(&tfs_ads_fnc), 0x80000000, "Is the the NC the default forest root(Windows 2008)?", HFILL }},
2201 { "GUID", "ldap.guid", FT_GUID, BASE_NONE,
2202 NULL, 0, NULL, HFILL }},
2204 { &hf_ldap_AccessMask_ADS_CREATE_CHILD,
2205 { "Create Child", "ldap.AccessMask.ADS_CREATE_CHILD", FT_BOOLEAN, 32, TFS(&ldap_AccessMask_ADS_CREATE_CHILD_tfs), LDAP_ACCESSMASK_ADS_CREATE_CHILD, NULL, HFILL }},
2207 { &hf_ldap_AccessMask_ADS_DELETE_CHILD,
2208 { "Delete Child", "ldap.AccessMask.ADS_DELETE_CHILD", FT_BOOLEAN, 32, TFS(&ldap_AccessMask_ADS_DELETE_CHILD_tfs), LDAP_ACCESSMASK_ADS_DELETE_CHILD, NULL, HFILL }},
2210 { &hf_ldap_AccessMask_ADS_LIST,
2211 { "List", "ldap.AccessMask.ADS_LIST", FT_BOOLEAN, 32, TFS(&ldap_AccessMask_ADS_LIST_tfs), LDAP_ACCESSMASK_ADS_LIST, NULL, HFILL }},
2213 { &hf_ldap_AccessMask_ADS_SELF_WRITE,
2214 { "Self Write", "ldap.AccessMask.ADS_SELF_WRITE", FT_BOOLEAN, 32, TFS(&ldap_AccessMask_ADS_SELF_WRITE_tfs), LDAP_ACCESSMASK_ADS_SELF_WRITE, NULL, HFILL }},
2216 { &hf_ldap_AccessMask_ADS_READ_PROP,
2217 { "Read Prop", "ldap.AccessMask.ADS_READ_PROP", FT_BOOLEAN, 32, TFS(&ldap_AccessMask_ADS_READ_PROP_tfs), LDAP_ACCESSMASK_ADS_READ_PROP, NULL, HFILL }},
2219 { &hf_ldap_AccessMask_ADS_WRITE_PROP,
2220 { "Write Prop", "ldap.AccessMask.ADS_WRITE_PROP", FT_BOOLEAN, 32, TFS(&ldap_AccessMask_ADS_WRITE_PROP_tfs), LDAP_ACCESSMASK_ADS_WRITE_PROP, NULL, HFILL }},
2222 { &hf_ldap_AccessMask_ADS_DELETE_TREE,
2223 { "Delete Tree", "ldap.AccessMask.ADS_DELETE_TREE", FT_BOOLEAN, 32, TFS(&ldap_AccessMask_ADS_DELETE_TREE_tfs), LDAP_ACCESSMASK_ADS_DELETE_TREE, NULL, HFILL }},
2225 { &hf_ldap_AccessMask_ADS_LIST_OBJECT,
2226 { "List Object", "ldap.AccessMask.ADS_LIST_OBJECT", FT_BOOLEAN, 32, TFS(&ldap_AccessMask_ADS_LIST_OBJECT_tfs), LDAP_ACCESSMASK_ADS_LIST_OBJECT, NULL, HFILL }},
2228 { &hf_ldap_AccessMask_ADS_CONTROL_ACCESS,
2229 { "Control Access", "ldap.AccessMask.ADS_CONTROL_ACCESS", FT_BOOLEAN, 32, TFS(&ldap_AccessMask_ADS_CONTROL_ACCESS_tfs), LDAP_ACCESSMASK_ADS_CONTROL_ACCESS, NULL, HFILL }},
2231 #include "packet-ldap-hfarr.c"
2234 /* List of subtrees */
2235 static gint *ett[] = {
2238 &ett_ldap_sasl_blob,
2240 &ett_mscldap_netlogon_flags,
2241 &ett_mscldap_ntver_flags,
2242 &ett_mscldap_ipdetails,
2244 #include "packet-ldap-ettarr.c"
2246 /* UAT for header fields */
2247 static uat_field_t custom_attribute_types_uat_fields[] = {
2248 UAT_FLD_CSTRING(attribute_types, attribute_type, "Attribute type", "Attribute type"),
2249 UAT_FLD_CSTRING(attribute_types, attribute_desc, "Description", "Description of the value matching type"),
2253 module_t *ldap_module;
2254 uat_t *attributes_uat;
2256 /* Register protocol */
2257 proto_ldap = proto_register_protocol(PNAME, PSNAME, PFNAME);
2258 /* Register fields and subtrees */
2259 proto_register_field_array(proto_ldap, hf, array_length(hf));
2260 proto_register_subtree_array(ett, array_length(ett));
2263 register_dissector("ldap", dissect_ldap_tcp, proto_ldap);
2265 ldap_module = prefs_register_protocol(proto_ldap, prefs_register_ldap);
2266 prefs_register_bool_preference(ldap_module, "desegment_ldap_messages",
2267 "Reassemble LDAP messages spanning multiple TCP segments",
2268 "Whether the LDAP dissector should reassemble messages spanning multiple TCP segments."
2269 " To use this option, you must also enable \"Allow subdissectors to reassemble TCP streams\" in the TCP protocol settings.",
2272 prefs_register_uint_preference(ldap_module, "tcp.port", "LDAP TCP Port",
2273 "Set the port for LDAP operations",
2274 10, &global_ldap_tcp_port);
2276 prefs_register_uint_preference(ldap_module, "ssl.port", "LDAPS TCP Port",
2277 "Set the port for LDAP operations over SSL",
2278 10, &global_ldaps_tcp_port);
2280 attributes_uat = uat_new("Custom LDAP AttributeValue types",
2281 sizeof(attribute_type_t),
2282 "custom_ldap_attribute_types",
2284 (void*) &attribute_types,
2285 &num_attribute_types,
2288 attribute_types_copy_cb,
2289 attribute_types_update_cb,
2290 attribute_types_free_cb,
2291 attribute_types_initialize_cb,
2292 custom_attribute_types_uat_fields);
2294 prefs_register_uat_preference(ldap_module, "custom_ldap_attribute_types",
2295 "Custom AttributeValue types",
2296 "A table to define custom LDAP attribute type values for which fields can be setup and used for filtering/data extraction etc.",
2299 prefs_register_obsolete_preference(ldap_module, "max_pdu");
2301 proto_cldap = proto_register_protocol(
2302 "Connectionless Lightweight Directory Access Protocol",
2305 register_init_routine(ldap_reinit);
2306 ldap_tap=register_tap("ldap");
2308 ldap_name_dissector_table = register_dissector_table("ldap.name", "LDAP Attribute Type Dissectors", FT_STRING, BASE_NONE);
2313 /*--- proto_reg_handoff_ldap ---------------------------------------*/
2315 proto_reg_handoff_ldap(void)
2317 dissector_handle_t cldap_handle;
2318 ldap_handle = find_dissector("ldap");
2320 dissector_add_uint("tcp.port", TCP_PORT_GLOBALCAT_LDAP, ldap_handle);
2322 cldap_handle = create_dissector_handle(dissect_mscldap, proto_cldap);
2323 dissector_add_uint("udp.port", UDP_PORT_CLDAP, cldap_handle);
2325 gssapi_handle = find_dissector("gssapi");
2326 gssapi_wrap_handle = find_dissector("gssapi_verf");
2327 spnego_handle = find_dissector("spnego");
2329 ntlmssp_handle = find_dissector("ntlmssp");
2331 ssl_handle = find_dissector("ssl");
2333 prefs_register_ldap();
2335 /* http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dsml/dsml/ldap_controls_and_session_support.asp */
2336 oid_add_from_string("LDAP_PAGED_RESULT_OID_STRING","1.2.840.113556.1.4.319");
2337 oid_add_from_string("LDAP_SERVER_SHOW_DELETED_OID","1.2.840.113556.1.4.417");
2338 oid_add_from_string("LDAP_SERVER_SORT_OID","1.2.840.113556.1.4.473");
2339 oid_add_from_string("LDAP_CONTROL_SORT_RESP_OID","1.2.840.113556.1.4.474");
2340 oid_add_from_string("LDAP_SERVER_CROSSDOM_MOVE_TARGET_OID","1.2.840.113556.1.4.521");
2341 oid_add_from_string("LDAP_SERVER_NOTIFICATION_OID","1.2.840.113556.1.4.528");
2342 oid_add_from_string("LDAP_SERVER_EXTENDED_DN_OID","1.2.840.113556.1.4.529");
2343 oid_add_from_string("meetingAdvertiseScope","1.2.840.113556.1.4.582");
2344 oid_add_from_string("LDAP_SERVER_LAZY_COMMIT_OID","1.2.840.113556.1.4.619");
2345 oid_add_from_string("mhsORAddress","1.2.840.113556.1.4.650");
2346 oid_add_from_string("managedObjects","1.2.840.113556.1.4.654");
2347 oid_add_from_string("LDAP_CAP_ACTIVE_DIRECTORY_OID","1.2.840.113556.1.4.800");
2348 oid_add_from_string("LDAP_SERVER_SD_FLAGS_OID","1.2.840.113556.1.4.801");
2349 oid_add_from_string("LDAP_OID_COMPARATOR_OR","1.2.840.113556.1.4.804");
2350 oid_add_from_string("LDAP_SERVER_TREE_DELETE_OID","1.2.840.113556.1.4.805");
2351 oid_add_from_string("LDAP_SERVER_DIRSYNC_OID","1.2.840.113556.1.4.841");
2352 oid_add_from_string("None","1.2.840.113556.1.4.970");
2353 oid_add_from_string("LDAP_SERVER_VERIFY_NAME_OID","1.2.840.113556.1.4.1338");
2354 oid_add_from_string("LDAP_SERVER_DOMAIN_SCOPE_OID","1.2.840.113556.1.4.1339");
2355 oid_add_from_string("LDAP_SERVER_SEARCH_OPTIONS_OID","1.2.840.113556.1.4.1340");
2356 oid_add_from_string("LDAP_SERVER_PERMISSIVE_MODIFY_OID","1.2.840.113556.1.4.1413");
2357 oid_add_from_string("LDAP_SERVER_ASQ_OID","1.2.840.113556.1.4.1504");
2358 oid_add_from_string("LDAP_CAP_ACTIVE_DIRECTORY_V51_OID","1.2.840.113556.1.4.1670");
2359 oid_add_from_string("LDAP_SERVER_FAST_BIND_OID","1.2.840.113556.1.4.1781");
2360 oid_add_from_string("LDAP_CAP_ACTIVE_DIRECTORY_LDAP_INTEG_OID","1.2.840.113556.1.4.1791");
2361 oid_add_from_string("msDS-ObjectReference","1.2.840.113556.1.4.1840");
2362 oid_add_from_string("msDS-QuotaEffective","1.2.840.113556.1.4.1848");
2363 oid_add_from_string("LDAP_CAP_ACTIVE_DIRECTORY_ADAM_OID","1.2.840.113556.1.4.1851");
2364 oid_add_from_string("msDS-PortSSL","1.2.840.113556.1.4.1860");
2365 oid_add_from_string("msDS-isRODC","1.2.840.113556.1.4.1960");
2366 oid_add_from_string("msDS-SDReferenceDomain","1.2.840.113556.1.4.1711");
2367 oid_add_from_string("msDS-AdditionalDnsHostName","1.2.840.113556.1.4.1717");
2368 oid_add_from_string("None","1.3.6.1.4.1.1466.101.119.1");
2369 oid_add_from_string("LDAP_START_TLS_OID","1.3.6.1.4.1.1466.20037");
2370 oid_add_from_string("LDAP_CONTROL_VLVREQUEST VLV","2.16.840.1.113730.3.4.9");
2371 oid_add_from_string("LDAP_CONTROL_VLVRESPONSE VLV","2.16.840.1.113730.3.4.10");
2372 oid_add_from_string("LDAP_SERVER_QUOTA_CONTROL_OID","1.2.840.113556.1.4.1852");
2373 oid_add_from_string("LDAP_SERVER_RANGE_OPTION_OID","1.2.840.113556.1.4.802");
2374 oid_add_from_string("LDAP_SERVER_SHUTDOWN_NOTIFY_OID","1.2.840.113556.1.4.1907");
2375 oid_add_from_string("LDAP_SERVER_RANGE_RETRIEVAL_NOERR_OID","1.2.840.113556.1.4.1948");
2377 register_ldap_name_dissector("netlogon", dissect_NetLogon_PDU, proto_cldap);
2378 register_ldap_name_dissector("objectGUID", dissect_ldap_guid, proto_ldap);
2379 register_ldap_name_dissector("supportedControl", dissect_ldap_oid, proto_ldap);
2380 register_ldap_name_dissector("supportedCapabilities", dissect_ldap_oid, proto_ldap);
2381 register_ldap_name_dissector("objectSid", dissect_ldap_sid, proto_ldap);
2382 register_ldap_name_dissector("nTSecurityDescriptor", dissect_ldap_nt_sec_desc, proto_ldap);
2384 #include "packet-ldap-dis-tab.c"
2390 prefs_register_ldap(void)
2393 if(tcp_port != global_ldap_tcp_port) {
2395 dissector_delete_uint("tcp.port", tcp_port, ldap_handle);
2397 /* Set our port number for future use */
2398 tcp_port = global_ldap_tcp_port;
2401 dissector_add_uint("tcp.port", tcp_port, ldap_handle);
2405 if(ssl_port != global_ldaps_tcp_port) {
2407 ssl_dissector_delete(ssl_port, "ldap", TRUE);
2409 /* Set our port number for future use */
2410 ssl_port = global_ldaps_tcp_port;
2413 ssl_dissector_add(ssl_port, "ldap", TRUE);