2 * Routines for ldap packet dissection
4 * See RFC 1777 (LDAP v2), RFC 2251 (LDAP v3), and RFC 2222 (SASL).
6 * $Id: packet-ldap.c,v 1.74 2004/04/20 08:33:15 sahlberg Exp $
8 * Ethereal - Network traffic analyzer
9 * By Gerald Combs <gerald@ethereal.com>
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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, 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
69 #ifdef NEED_SNPRINTF_H
70 # include "snprintf.h"
73 #include <epan/packet.h>
77 #include <epan/conversation.h>
78 #include "packet-frame.h"
80 #include "packet-ldap.h"
82 static int proto_ldap = -1;
83 static int proto_cldap = -1;
84 static int hf_ldap_response_to = -1;
85 static int hf_ldap_response_in = -1;
86 static int hf_ldap_time = -1;
87 static int hf_ldap_sasl_buffer_length = -1;
88 static int hf_ldap_length = -1;
89 static int hf_ldap_message_id = -1;
90 static int hf_ldap_message_type = -1;
91 static int hf_ldap_message_length = -1;
93 static int hf_ldap_message_result = -1;
94 static int hf_ldap_message_result_matcheddn = -1;
95 static int hf_ldap_message_result_errormsg = -1;
96 static int hf_ldap_message_result_referral = -1;
98 static int hf_ldap_message_bind_version = -1;
99 static int hf_ldap_message_bind_dn = -1;
100 static int hf_ldap_message_bind_auth = -1;
101 static int hf_ldap_message_bind_auth_password = -1;
102 static int hf_ldap_message_bind_auth_mechanism = -1;
103 static int hf_ldap_message_bind_auth_credentials = -1;
104 static int hf_ldap_message_bind_server_credentials = -1;
106 static int hf_ldap_message_search_base = -1;
107 static int hf_ldap_message_search_scope = -1;
108 static int hf_ldap_message_search_deref = -1;
109 static int hf_ldap_message_search_sizeLimit = -1;
110 static int hf_ldap_message_search_timeLimit = -1;
111 static int hf_ldap_message_search_typesOnly = -1;
112 static int hf_ldap_message_search_filter = -1;
113 static int hf_ldap_message_search_reference = -1;
115 static int hf_ldap_message_dn = -1;
116 static int hf_ldap_message_attribute = -1;
117 static int hf_ldap_message_value = -1;
119 static int hf_ldap_message_modrdn_name = -1;
120 static int hf_ldap_message_modrdn_delete = -1;
121 static int hf_ldap_message_modrdn_superior = -1;
123 static int hf_ldap_message_compare = -1;
125 static int hf_ldap_message_modify_add = -1;
126 static int hf_ldap_message_modify_replace = -1;
127 static int hf_ldap_message_modify_delete = -1;
129 static int hf_ldap_message_abandon_msgid = -1;
131 static int hf_mscldap_netlogon_type = -1;
132 static int hf_mscldap_netlogon_flags = -1;
133 static int hf_mscldap_netlogon_flags_pdc = -1;
134 static int hf_mscldap_netlogon_flags_gc = -1;
135 static int hf_mscldap_netlogon_flags_ldap = -1;
136 static int hf_mscldap_netlogon_flags_ds = -1;
137 static int hf_mscldap_netlogon_flags_kdc = -1;
138 static int hf_mscldap_netlogon_flags_timeserv = -1;
139 static int hf_mscldap_netlogon_flags_closest = -1;
140 static int hf_mscldap_netlogon_flags_writable = -1;
141 static int hf_mscldap_netlogon_flags_good_timeserv = -1;
142 static int hf_mscldap_netlogon_flags_ndnc = -1;
143 static int hf_mscldap_domain_guid = -1;
144 static int hf_mscldap_forest = -1;
145 static int hf_mscldap_domain = -1;
146 static int hf_mscldap_hostname = -1;
147 static int hf_mscldap_nb_domain = -1;
148 static int hf_mscldap_nb_hostname = -1;
149 static int hf_mscldap_username = -1;
150 static int hf_mscldap_sitename = -1;
151 static int hf_mscldap_clientsitename = -1;
152 static int hf_mscldap_netlogon_version = -1;
153 static int hf_mscldap_netlogon_lm_token = -1;
154 static int hf_mscldap_netlogon_nt_token = -1;
156 static gint ett_ldap = -1;
157 static gint ett_ldap_gssapi_token = -1;
158 static gint ett_ldap_referrals = -1;
159 static gint ett_ldap_attribute = -1;
160 static gint ett_mscldap_netlogon_flags = -1;
162 static int ldap_tap = -1;
164 /* desegmentation of LDAP */
165 static gboolean ldap_desegment = TRUE;
167 #define TCP_PORT_LDAP 389
168 #define UDP_PORT_CLDAP 389
169 #define TCP_PORT_GLOBALCAT_LDAP 3268 /* Windows 2000 Global Catalog */
171 static dissector_handle_t gssapi_handle;
172 static dissector_handle_t gssapi_wrap_handle;
175 /* different types of rpc calls ontop of ms cldap */
176 #define MSCLDAP_RPC_NETLOGON 1
180 * Data structure attached to a conversation, giving authentication
181 * information from a bind request.
182 * We keep a linked list of them, so that we can free up all the
183 * authentication mechanism strings.
185 typedef struct ldap_conv_info_t {
186 struct ldap_conv_info_t *next;
187 guint auth_type; /* authentication type */
188 char *auth_mech; /* authentication mechanism */
189 guint32 first_auth_frame; /* first frame that would use a security layer */
190 GHashTable *unmatched;
193 static GMemChunk *ldap_conv_info_chunk = NULL;
194 static guint ldap_conv_info_chunk_count = 20;
195 static ldap_conv_info_t *ldap_info_items;
197 static GMemChunk *ldap_call_response_chunk = NULL;
198 static guint ldap_call_response_chunk_count = 200;
201 ldap_info_hash_matched(gconstpointer k)
203 ldap_call_response_t *key = (ldap_call_response_t *)k;
205 return key->messageId;
209 ldap_info_equal_matched(gconstpointer k1, gconstpointer k2)
211 ldap_call_response_t *key1 = (ldap_call_response_t *)k1;
212 ldap_call_response_t *key2 = (ldap_call_response_t *)k2;
214 if( key1->req_frame && key2->req_frame && (key1->req_frame!=key2->req_frame) ){
217 if( key1->rep_frame && key2->rep_frame && (key1->rep_frame!=key2->rep_frame) ){
221 return key1->messageId==key2->messageId;
225 ldap_info_hash_unmatched(gconstpointer k)
227 ldap_call_response_t *key = (ldap_call_response_t *)k;
229 return key->messageId;
233 ldap_info_equal_unmatched(gconstpointer k1, gconstpointer k2)
235 ldap_call_response_t *key1 = (ldap_call_response_t *)k1;
236 ldap_call_response_t *key2 = (ldap_call_response_t *)k2;
238 return key1->messageId==key2->messageId;
242 static value_string msgTypes [] = {
243 {LDAP_REQ_BIND, "Bind Request"},
244 {LDAP_REQ_UNBIND, "Unbind Request"},
245 {LDAP_REQ_SEARCH, "Search Request"},
246 {LDAP_REQ_MODIFY, "Modify Request"},
247 {LDAP_REQ_ADD, "Add Request"},
248 {LDAP_REQ_DELETE, "Delete Request"},
249 {LDAP_REQ_MODRDN, "Modify RDN Request"},
250 {LDAP_REQ_COMPARE, "Compare Request"},
251 {LDAP_REQ_ABANDON, "Abandon Request"},
252 {LDAP_REQ_EXTENDED, "Extended Request"},
254 {LDAP_RES_BIND, "Bind Result"},
255 {LDAP_RES_SEARCH_ENTRY, "Search Entry"},
256 {LDAP_RES_SEARCH_RESULT, "Search Result"},
257 {LDAP_RES_SEARCH_REF, "Search Result Reference"},
258 {LDAP_RES_MODIFY, "Modify Result"},
259 {LDAP_RES_ADD, "Add Result"},
260 {LDAP_RES_DELETE, "Delete Result"},
261 {LDAP_RES_MODRDN, "Modify RDN Result"},
262 {LDAP_RES_COMPARE, "Compare Result"},
263 {LDAP_RES_EXTENDED, "Extended Response"},
267 static value_string result_codes[] = {
269 {1, "Operations error"},
270 {2, "Protocol error"},
271 {3, "Time limit exceeded"},
272 {4, "Size limit exceeded"},
273 {5, "Compare false"},
275 {7, "Authentication method not supported"},
276 {8, "Strong authentication required"},
278 {11, "Administrative limit exceeded"},
279 {12, "Unavailable critical extension"},
280 {13, "Confidentiality required"},
281 {14, "SASL bind in progress"},
282 {16, "No such attribute"},
283 {17, "Undefined attribute type"},
284 {18, "Inappropriate matching"},
285 {19, "Constraint violation"},
286 {20, "Attribute or value exists"},
287 {21, "Invalid attribute syntax"},
288 {32, "No such object"},
289 {33, "Alias problem"},
290 {34, "Invalid DN syntax"},
291 {36, "Alias derefetencing problem"},
292 {48, "Inappropriate authentication"},
293 {49, "Invalid credentials"},
294 {50, "Insufficient access rights"},
297 {53, "Unwilling to perform"},
298 {54, "Loop detected"},
299 {64, "Naming violation"},
300 {65, "Objectclass violation"},
301 {66, "Not allowed on non-leaf"},
302 {67, "Not allowed on RDN"},
303 {68, "Entry already exists"},
304 {69, "Objectclass modification prohibited"},
305 {71, "Affects multiple DSAs"},
310 static int read_length(ASN1_SCK *a, proto_tree *tree, int hf_id, guint *len)
313 gboolean def = FALSE;
314 int start = a->offset;
317 ret = asn1_length_decode(a, &def, &length);
318 if (ret != ASN1_ERR_NOERROR) {
320 proto_tree_add_text(tree, a->tvb, start, 0,
321 "%s: ERROR: Couldn't parse length: %s",
322 proto_registrar_get_name(hf_id), asn1_err_to_str(ret));
331 proto_tree_add_uint(tree, hf_id, a->tvb, start, a->offset-start, length);
333 return ASN1_ERR_NOERROR;
336 static int read_sequence(ASN1_SCK *a, guint *len)
343 ret = asn1_header_decode(a, &cls, &con, &tag, &def, &length);
344 if (ret != ASN1_ERR_NOERROR)
346 if (cls != ASN1_UNI || con != ASN1_CON || tag != ASN1_SEQ)
347 return ASN1_ERR_WRONG_TYPE;
352 return ASN1_ERR_NOERROR;
355 static int read_set(ASN1_SCK *a, guint *len)
362 ret = asn1_header_decode(a, &cls, &con, &tag, &def, &length);
363 if (ret != ASN1_ERR_NOERROR)
365 if (cls != ASN1_UNI || con != ASN1_CON || tag != ASN1_SET)
366 return ASN1_ERR_WRONG_TYPE;
371 return ASN1_ERR_NOERROR;
374 static int read_integer_value(ASN1_SCK *a, proto_tree *tree, int hf_id,
375 proto_item **new_item, guint *i, int start, guint length)
378 proto_item *temp_item = NULL;
381 ret = asn1_uint32_value_decode(a, length, &integer);
382 if (ret != ASN1_ERR_NOERROR) {
384 proto_tree_add_text(tree, a->tvb, start, 0,
385 "%s: ERROR: Couldn't parse value: %s",
386 proto_registrar_get_name(hf_id), asn1_err_to_str(ret));
395 temp_item = proto_tree_add_uint(tree, hf_id, a->tvb, start, a->offset-start, integer);
398 *new_item = temp_item;
400 return ASN1_ERR_NOERROR;
403 static int read_integer(ASN1_SCK *a, proto_tree *tree, int hf_id,
404 proto_item **new_item, guint *i, guint expected_tag)
409 int start = a->offset;
412 ret = asn1_header_decode(a, &cls, &con, &tag, &def, &length);
413 if (ret == ASN1_ERR_NOERROR) {
414 if (cls != ASN1_UNI || con != ASN1_PRI || tag != expected_tag)
415 ret = ASN1_ERR_WRONG_TYPE;
417 if (ret != ASN1_ERR_NOERROR) {
419 proto_tree_add_text(tree, a->tvb, start, 0,
420 "%s: ERROR: Couldn't parse header: %s",
421 (hf_id != -1) ? proto_registrar_get_name(hf_id) : "LDAP message",
422 asn1_err_to_str(ret));
427 return read_integer_value(a, tree, hf_id, new_item, i, start, length);
430 static int read_boolean_value(ASN1_SCK *a, proto_tree *tree, int hf_id,
431 proto_item **new_item, guint *i, int start, guint length)
434 proto_item *temp_item = NULL;
437 ret = asn1_uint32_value_decode(a, length, &integer);
438 if (ret != ASN1_ERR_NOERROR) {
440 proto_tree_add_text(tree, a->tvb, start, 0,
441 "%s: ERROR: Couldn't parse value: %s",
442 proto_registrar_get_name(hf_id), asn1_err_to_str(ret));
451 temp_item = proto_tree_add_boolean(tree, hf_id, a->tvb, start, a->offset-start, integer);
453 *new_item = temp_item;
455 return ASN1_ERR_NOERROR;
458 static int read_boolean(ASN1_SCK *a, proto_tree *tree, int hf_id,
459 proto_item **new_item, guint *i)
464 int start = a->offset;
467 ret = asn1_header_decode(a, &cls, &con, &tag, &def, &length);
468 if (ret == ASN1_ERR_NOERROR) {
469 if (cls != ASN1_UNI || con != ASN1_PRI || tag != ASN1_BOL)
470 ret = ASN1_ERR_WRONG_TYPE;
472 if (ret != ASN1_ERR_NOERROR) {
474 proto_tree_add_text(tree, a->tvb, start, 0,
475 "%s: ERROR: Couldn't parse header: %s",
476 proto_registrar_get_name(hf_id), asn1_err_to_str(ret));
481 return read_boolean_value(a, tree, hf_id, new_item, i, start, length);
484 static int read_string_value(ASN1_SCK *a, proto_tree *tree, int hf_id,
485 proto_item **new_item, char **s, int start, guint length)
488 proto_item *temp_item = NULL;
493 ret = asn1_string_value_decode(a, length, &string);
494 if (ret != ASN1_ERR_NOERROR) {
496 proto_tree_add_text(tree, a->tvb, start, 0,
497 "%s: ERROR: Couldn't parse value: %s",
498 proto_registrar_get_name(hf_id), asn1_err_to_str(ret));
502 string = g_realloc(string, length + 1);
503 string[length] = '\0';
509 temp_item = proto_tree_add_string(tree, hf_id, a->tvb, start, a->offset - start, string);
511 *new_item = temp_item;
518 return ASN1_ERR_NOERROR;
521 static int read_string(ASN1_SCK *a, proto_tree *tree, int hf_id,
522 proto_item **new_item, char **s, guint *length,
523 guint expected_cls, guint expected_tag)
528 int start = a->offset;
531 ret = asn1_header_decode(a, &cls, &con, &tag, &def, &tmplen);
532 if (ret == ASN1_ERR_NOERROR) {
533 if (cls != expected_cls || con != ASN1_PRI || tag != expected_tag)
534 ret = ASN1_ERR_WRONG_TYPE;
536 if (ret != ASN1_ERR_NOERROR) {
538 proto_tree_add_text(tree, a->tvb, start, 0,
539 "%s: ERROR: Couldn't parse header: %s",
540 proto_registrar_get_name(hf_id), asn1_err_to_str(ret));
548 return read_string_value(a, tree, hf_id, new_item, s, start, tmplen);
551 static int read_bytestring_value(ASN1_SCK *a, proto_tree *tree, int hf_id,
552 proto_item **new_item, char **s, int start, guint length)
555 proto_item *temp_item = NULL;
560 ret = asn1_string_value_decode(a, length, &string);
561 if (ret != ASN1_ERR_NOERROR) {
563 proto_tree_add_text(tree, a->tvb, start, 0,
564 "%s: ERROR: Couldn't parse value: %s",
565 proto_registrar_get_name(hf_id), asn1_err_to_str(ret));
569 string = g_realloc(string, length + 1);
570 string[length] = '\0';
576 temp_item = proto_tree_add_bytes(tree, hf_id, a->tvb, start, a->offset - start, string);
578 *new_item = temp_item;
585 return ASN1_ERR_NOERROR;
588 static int read_bytestring(ASN1_SCK *a, proto_tree *tree, int hf_id,
589 proto_item **new_item, char **s, guint expected_cls, guint expected_tag)
594 int start = a->offset;
597 ret = asn1_header_decode(a, &cls, &con, &tag, &def, &length);
598 if (ret == ASN1_ERR_NOERROR) {
599 if (cls != expected_cls || con != ASN1_PRI || tag != expected_tag)
600 ret = ASN1_ERR_WRONG_TYPE;
602 if (ret != ASN1_ERR_NOERROR) {
604 proto_tree_add_text(tree, a->tvb, start, 0,
605 "%s: ERROR: Couldn't parse header: %s",
606 proto_registrar_get_name(hf_id), asn1_err_to_str(ret));
611 return read_bytestring_value(a, tree, hf_id, new_item, s, start, length);
614 static int parse_filter_strings(ASN1_SCK *a, char **filter, guint *filter_length, const guchar *operation)
619 guint string2_length;
624 ret = asn1_octet_string_decode(a, &string, &string_length, &string_bytes);
625 if (ret != ASN1_ERR_NOERROR)
627 ret = asn1_octet_string_decode(a, &string2, &string2_length, &string_bytes);
628 if (ret != ASN1_ERR_NOERROR)
630 *filter_length += 2 + strlen(operation) + string_length + string2_length;
631 *filter = g_realloc(*filter, *filter_length);
632 filterp = *filter + strlen(*filter);
634 if (string_length != 0) {
635 memcpy(filterp, string, string_length);
636 filterp += string_length;
638 strcpy(filterp, operation);
639 filterp += strlen(operation);
640 if (string2_length != 0) {
641 memcpy(filterp, string2, string2_length);
642 filterp += string2_length;
648 return ASN1_ERR_NOERROR;
651 /* Richard Dawe: To parse substring filters, I added this function. */
652 static int parse_filter_substrings(ASN1_SCK *a, char **filter, guint *filter_length)
663 /* For ASN.1 parsing of octet strings */
669 ret = asn1_octet_string_decode(a, &string, &string_length, &string_bytes);
670 if (ret != ASN1_ERR_NOERROR)
673 ret = asn1_sequence_decode(a, &seq_len, &header_bytes);
674 if (ret != ASN1_ERR_NOERROR)
677 *filter_length += 2 + 1 + string_length;
678 *filter = g_realloc(*filter, *filter_length);
680 filterp = *filter + strlen(*filter);
682 if (string_length != 0) {
683 memcpy(filterp, string, string_length);
684 filterp += string_length;
690 /* Now decode seq_len's worth of octet strings. */
692 end = a->offset + seq_len;
694 while (a->offset < end) {
695 /* Octet strings here are context-specific, which
696 * asn1_octet_string_decode() barfs on. Emulate it, but don't barf. */
697 ret = asn1_header_decode (a, &cls, &con, &tag, &def, &string_length);
698 if (ret != ASN1_ERR_NOERROR)
701 /* XXX - check the tag? */
702 if (cls != ASN1_CTX || con != ASN1_PRI) {
703 /* XXX - handle the constructed encoding? */
704 return ASN1_ERR_WRONG_TYPE;
707 return ASN1_ERR_LENGTH_NOT_DEFINITE;
709 ret = asn1_string_value_decode(a, (int) string_length, &string);
710 if (ret != ASN1_ERR_NOERROR)
713 /* If we have an 'any' component with a string value, we need to append
714 * an extra asterisk before final component. */
715 if ((tag == 1) && (string_length != 0))
718 if ( (tag == 1) || ((tag == 2) && any_valued) )
720 *filter_length += string_length;
721 *filter = g_realloc(*filter, *filter_length);
723 filterp = *filter + strlen(*filter);
724 if ( (tag == 1) || ((tag == 2) && any_valued) )
728 if (string_length != 0) {
729 memcpy(filterp, string, string_length);
730 filterp += string_length;
739 *filter = g_realloc(*filter, *filter_length);
740 filterp = *filter + strlen(*filter);
744 /* NB: Allocated byte for this earlier */
748 return ASN1_ERR_NOERROR;
751 /* Returns -1 if we're at the end, returns an ASN1_ERR value otherwise. */
752 static int parse_filter(ASN1_SCK *a, char **filter, guint *filter_length,
760 ret = asn1_header_decode(a, &cls, &con, &tag, &def, &length);
761 if (ret != ASN1_ERR_NOERROR)
766 *end = a->offset + length;
768 *filter = g_malloc0(*filter_length);
771 if (cls == ASN1_CTX) /* XXX - handle other types as errors? */
775 case LDAP_FILTER_AND:
780 return ASN1_ERR_WRONG_TYPE;
781 add_end = a->offset + length;
783 *filter = g_realloc(*filter, *filter_length);
784 strcat(*filter, "(&");
785 while ((ret = parse_filter(a, filter, filter_length, &add_end))
790 strcat(*filter, ")");
798 return ASN1_ERR_WRONG_TYPE;
799 or_end = a->offset + length;
801 *filter = g_realloc(*filter, *filter_length);
802 strcat(*filter, "(|");
803 while ((ret = parse_filter(a, filter, filter_length, &or_end))
808 strcat(*filter, ")");
811 case LDAP_FILTER_NOT:
816 return ASN1_ERR_WRONG_TYPE;
817 not_end = a->offset + length;
819 *filter = g_realloc(*filter, *filter_length);
820 strcat(*filter, "(!");
821 ret = parse_filter(a, filter, filter_length, ¬_end);
822 if (ret != -1 && ret != ASN1_ERR_NOERROR)
824 strcat(*filter, ")");
827 case LDAP_FILTER_EQUALITY:
829 return ASN1_ERR_WRONG_TYPE;
830 ret = parse_filter_strings(a, filter, filter_length, "=");
831 if (ret != ASN1_ERR_NOERROR)
836 return ASN1_ERR_WRONG_TYPE;
837 ret = parse_filter_strings(a, filter, filter_length, ">=");
838 if (ret != ASN1_ERR_NOERROR)
843 return ASN1_ERR_WRONG_TYPE;
844 ret = parse_filter_strings(a, filter, filter_length, "<=");
845 if (ret != -1 && ret != ASN1_ERR_NOERROR)
848 case LDAP_FILTER_APPROX:
850 return ASN1_ERR_WRONG_TYPE;
851 ret = parse_filter_strings(a, filter, filter_length, "~=");
852 if (ret != ASN1_ERR_NOERROR)
855 case LDAP_FILTER_PRESENT:
861 return ASN1_ERR_WRONG_TYPE;
862 ret = asn1_string_value_decode(a, length, &string);
863 if (ret != ASN1_ERR_NOERROR)
865 *filter_length += 4 + length;
866 *filter = g_realloc(*filter, *filter_length);
867 filterp = *filter + strlen(*filter);
870 memcpy(filterp, string, length);
880 case LDAP_FILTER_SUBSTRINGS:
882 return ASN1_ERR_WRONG_TYPE;
883 /* Richard Dawe: Handle substrings */
884 ret = parse_filter_substrings(a, filter, filter_length);
885 if (ret != ASN1_ERR_NOERROR)
889 return ASN1_ERR_WRONG_TYPE;
893 if (a->offset == *end)
896 return ASN1_ERR_NOERROR;
899 static gboolean read_filter(ASN1_SCK *a, proto_tree *tree, int hf_id)
901 int start = a->offset;
903 guint filter_length = 0;
907 while ((ret = parse_filter(a, &filter, &filter_length, &end))
913 proto_tree_add_text(tree, a->tvb, start, 0,
914 "%s: ERROR: Can't parse filter: %s",
915 proto_registrar_get_name(hf_id), asn1_err_to_str(ret));
917 proto_tree_add_string(tree, hf_id, a->tvb, start, a->offset-start, filter);
922 return (ret == -1) ? TRUE : FALSE;
925 /********************************************************************************************/
927 static void dissect_ldap_result(ASN1_SCK *a, proto_tree *tree, packet_info *pinfo)
929 guint resultCode = 0;
931 if (read_integer(a, tree, hf_ldap_message_result, 0, &resultCode, ASN1_ENUM) != ASN1_ERR_NOERROR)
934 if (resultCode != 0) {
935 if (check_col(pinfo->cinfo, COL_INFO))
936 col_append_fstr(pinfo->cinfo, COL_INFO, ", %s",
937 val_to_str(resultCode, result_codes,
941 if (read_string(a, tree, hf_ldap_message_result_matcheddn, 0, 0, 0, ASN1_UNI, ASN1_OTS) != ASN1_ERR_NOERROR)
943 if (read_string(a, tree, hf_ldap_message_result_errormsg, 0, 0, 0, ASN1_UNI, ASN1_OTS) != ASN1_ERR_NOERROR)
946 if (resultCode == 10) /* Referral */
948 int start = a->offset;
952 proto_tree *referralTree;
954 ret = read_sequence(a, &length);
955 if (ret != ASN1_ERR_NOERROR) {
957 proto_tree_add_text(tree, a->tvb, start, 0,
958 "ERROR: Couldn't parse referral URL sequence header: %s",
959 asn1_err_to_str(ret));
963 ti = proto_tree_add_text(tree, a->tvb, start, length, "Referral URLs");
964 referralTree = proto_item_add_subtree(ti, ett_ldap_referrals);
966 end = a->offset + length;
967 while (a->offset < end) {
968 if (read_string(a, referralTree, hf_ldap_message_result_referral, 0, 0, 0, ASN1_UNI, ASN1_OTS) != ASN1_ERR_NOERROR)
974 static void dissect_ldap_request_bind(ASN1_SCK *a, proto_tree *tree,
975 tvbuff_t *tvb, packet_info *pinfo, ldap_conv_info_t *ldap_info)
983 char *mechanism, *s = NULL;
985 gint available_length, reported_length;
988 proto_tree *gtree = NULL;
990 if (read_integer(a, tree, hf_ldap_message_bind_version, 0, 0, ASN1_INT) != ASN1_ERR_NOERROR)
992 if (read_string(a, tree, hf_ldap_message_bind_dn, 0, &s, 0, ASN1_UNI, ASN1_OTS) != ASN1_ERR_NOERROR)
995 if (check_col(pinfo->cinfo, COL_INFO))
996 col_append_fstr(pinfo->cinfo, COL_INFO, ", DN=%s", s != NULL ? s : "(null)");
1000 ret = asn1_header_decode(a, &cls, &con, &tag, &def, &length);
1001 if (ret == ASN1_ERR_NOERROR) {
1002 if (cls != ASN1_CTX) {
1003 /* RFCs 1777 and 2251 say these are context-specific types */
1004 ret = ASN1_ERR_WRONG_TYPE;
1007 if (ret != ASN1_ERR_NOERROR) {
1008 proto_tree_add_text(tree, a->tvb, start, 0,
1009 "%s: ERROR: Couldn't parse header: %s",
1010 proto_registrar_get_name(hf_ldap_message_bind_auth),
1011 asn1_err_to_str(ret));
1014 proto_tree_add_uint(tree, hf_ldap_message_bind_auth, a->tvb, start,
1015 a->offset - start, tag);
1016 end = a->offset + length;
1019 case LDAP_AUTH_SIMPLE:
1020 if (read_string_value(a, tree, hf_ldap_message_bind_auth_password, NULL,
1021 NULL, start, length) != ASN1_ERR_NOERROR)
1025 /* For Kerberos V4, dissect it as a ticket. */
1027 case LDAP_AUTH_SASL:
1029 if (read_string(a, tree, hf_ldap_message_bind_auth_mechanism, NULL,
1030 &mechanism, 0, ASN1_UNI, ASN1_OTS) != ASN1_ERR_NOERROR)
1034 * We need to remember the authentication type and mechanism for this
1037 * XXX - actually, we might need to remember more than one
1038 * type and mechanism, if you can unbind and rebind with a
1039 * different type and/or mechanism.
1041 ldap_info->auth_type = tag;
1042 ldap_info->auth_mech = mechanism;
1043 ldap_info->first_auth_frame = 0; /* not known until we see the bind reply */
1045 * If the mechanism in this request is an empty string (which is
1046 * returned as a null pointer), use the saved mechanism instead.
1047 * Otherwise, if the saved mechanism is an empty string (null),
1048 * save this mechanism.
1050 if (mechanism == NULL)
1051 mechanism = ldap_info->auth_mech;
1053 if (ldap_info->auth_mech == NULL) {
1054 g_free(ldap_info->auth_mech);
1056 ldap_info->auth_mech = mechanism;
1059 if (a->offset < end) {
1060 if (mechanism != NULL && strcmp(mechanism, "GSS-SPNEGO") == 0) {
1062 * This is a GSS-API token ancapsulated within GSS-SPNEGO.
1063 * Find out how big it is by parsing the ASN.1 header for the
1064 * OCTET STREAM that contains it.
1066 token_offset = a->offset;
1067 ret = asn1_header_decode(a, &cls, &con, &tag, &def, &length);
1068 if (ret != ASN1_ERR_NOERROR) {
1069 proto_tree_add_text(tree, a->tvb, token_offset, 0,
1070 "%s: ERROR: Couldn't parse header: %s",
1071 proto_registrar_get_name(hf_ldap_message_bind_auth_credentials),
1072 asn1_err_to_str(ret));
1076 gitem = proto_tree_add_text(tree, tvb, token_offset,
1077 (a->offset + length) - token_offset, "GSS-API Token");
1078 gtree = proto_item_add_subtree(gitem, ett_ldap_gssapi_token);
1080 available_length = tvb_length_remaining(tvb, token_offset);
1081 reported_length = tvb_reported_length_remaining(tvb, token_offset);
1082 g_assert(available_length >= 0);
1083 g_assert(reported_length >= 0);
1084 if (available_length > reported_length)
1085 available_length = reported_length;
1086 if ((guint)available_length > length)
1087 available_length = length;
1088 if ((guint)reported_length > length)
1089 reported_length = length;
1090 new_tvb = tvb_new_subset(tvb, a->offset, available_length, reported_length);
1091 call_dissector(gssapi_handle, new_tvb, pinfo, gtree);
1092 a->offset += length;
1093 } else if (mechanism != NULL && strcmp(mechanism, "GSSAPI") == 0) {
1095 * This is a raw GSS-API token.
1096 * Find out how big it is by parsing the ASN.1 header for the
1097 * OCTET STREAM that contains it.
1099 token_offset = a->offset;
1100 ret = asn1_header_decode(a, &cls, &con, &tag, &def, &length);
1101 if (ret != ASN1_ERR_NOERROR) {
1102 proto_tree_add_text(tree, a->tvb, token_offset, 0,
1103 "%s: ERROR: Couldn't parse header: %s",
1104 proto_registrar_get_name(hf_ldap_message_bind_auth_credentials),
1105 asn1_err_to_str(ret));
1109 gitem = proto_tree_add_text(tree, tvb, token_offset,
1110 (a->offset + length) - token_offset, "GSS-API Token");
1111 gtree = proto_item_add_subtree(gitem, ett_ldap_gssapi_token);
1114 /* for GSSAPI the third pdu will sometimes be "empty" */
1117 available_length = tvb_length_remaining(tvb, token_offset);
1118 reported_length = tvb_reported_length_remaining(tvb, token_offset);
1119 g_assert(available_length >= 0);
1120 g_assert(reported_length >= 0);
1121 if (available_length > reported_length)
1122 available_length = reported_length;
1123 if ((guint)available_length > length)
1124 available_length = length;
1125 if ((guint)reported_length > length)
1126 reported_length = length;
1127 new_tvb = tvb_new_subset(tvb, a->offset, available_length, reported_length);
1128 call_dissector(gssapi_handle, new_tvb, pinfo, gtree);
1129 a->offset += length;
1131 if (read_bytestring(a, tree, hf_ldap_message_bind_auth_credentials,
1132 NULL, NULL, ASN1_UNI, ASN1_OTS) != ASN1_ERR_NOERROR)
1140 static void dissect_ldap_response_bind(ASN1_SCK *a, proto_tree *tree,
1141 int start, guint length, tvbuff_t *tvb, packet_info *pinfo, ldap_conv_info_t *ldap_info)
1143 guint cls, con, tag;
1149 gint available_length, reported_length;
1152 proto_tree *gtree = NULL;
1154 end = start + length;
1155 dissect_ldap_result(a, tree, pinfo);
1156 if (a->offset < end) {
1157 switch (ldap_info->auth_type) {
1159 /* For Kerberos V4, dissect it as a ticket. */
1160 /* XXX - what about LDAP_AUTH_SIMPLE? */
1162 case LDAP_AUTH_SASL:
1164 * All frames after this are assumed to use a security layer.
1166 * XXX - won't work if there's another reply, with the security
1167 * layer, starting in the same TCP segment that ends this
1168 * reply, but as LDAP is a request/response protocol, and
1169 * as the client probably can't start using authentication until
1170 * it gets the bind reply and the server won't send a reply until
1171 * it gets a request, that probably won't happen.
1173 * XXX - that assumption is invalid; it's not clear where the
1174 * hell you find out whether there's any security layer. In
1175 * one capture, we have two GSS-SPNEGO negotiations, both of
1176 * which select MS KRB5, and the only differences in the tokens
1177 * is in the RC4-HMAC ciphertext. The various
1178 * draft-ietf--cat-sasl-gssapi-NN.txt drafts seem to imply
1179 * that the RFC 2222 spoo with the bitmask and maximum
1180 * output message size stuff is done - but where does that
1181 * stuff show up? Is it in the ciphertext, which means it's
1182 * presumably encrypted?
1184 * Grrr. We have to do a gross heuristic, checking whether the
1185 * putative LDAP message begins with 0x00 or not, making the
1186 * assumption that we won't have more than 2^24 bytes of
1187 * encapsulated stuff.
1189 ldap_info->first_auth_frame = pinfo->fd->num + 1;
1190 if (ldap_info->auth_mech != NULL &&
1191 strcmp(ldap_info->auth_mech, "GSS-SPNEGO") == 0) {
1193 * This is a GSS-API token.
1194 * Find out how big it is by parsing the ASN.1 header for the
1195 * OCTET STREAM that contains it.
1197 token_offset = a->offset;
1198 ret = asn1_header_decode(a, &cls, &con, &tag, &def, &cred_length);
1199 if (ret != ASN1_ERR_NOERROR) {
1200 proto_tree_add_text(tree, a->tvb, token_offset, 0,
1201 "%s: ERROR: Couldn't parse header: %s",
1202 proto_registrar_get_name(hf_ldap_message_bind_auth_credentials),
1203 asn1_err_to_str(ret));
1207 gitem = proto_tree_add_text(tree, tvb, token_offset,
1208 (a->offset + cred_length) - token_offset, "GSS-API Token");
1209 gtree = proto_item_add_subtree(gitem, ett_ldap_gssapi_token);
1211 available_length = tvb_length_remaining(tvb, token_offset);
1212 reported_length = tvb_reported_length_remaining(tvb, token_offset);
1213 g_assert(available_length >= 0);
1214 g_assert(reported_length >= 0);
1215 if (available_length > reported_length)
1216 available_length = reported_length;
1217 if ((guint)available_length > cred_length)
1218 available_length = cred_length;
1219 if ((guint)reported_length > cred_length)
1220 reported_length = cred_length;
1221 new_tvb = tvb_new_subset(tvb, a->offset, available_length, reported_length);
1222 call_dissector(gssapi_handle, new_tvb, pinfo, gtree);
1223 a->offset += cred_length;
1224 } else if (ldap_info->auth_mech != NULL &&
1225 strcmp(ldap_info->auth_mech, "GSSAPI") == 0) {
1227 * This is a GSS-API token.
1228 * Find out how big it is by parsing the ASN.1 header for the
1229 * OCTET STREAM that contains it.
1231 token_offset = a->offset;
1232 ret = asn1_header_decode(a, &cls, &con, &tag, &def, &cred_length);
1233 if (ret != ASN1_ERR_NOERROR) {
1234 proto_tree_add_text(tree, a->tvb, token_offset, 0,
1235 "%s: ERROR: Couldn't parse header: %s",
1236 proto_registrar_get_name(hf_ldap_message_bind_auth_credentials),
1237 asn1_err_to_str(ret));
1241 gitem = proto_tree_add_text(tree, tvb, token_offset,
1242 (a->offset + cred_length) - token_offset, "GSS-API Token");
1243 gtree = proto_item_add_subtree(gitem, ett_ldap_gssapi_token);
1245 available_length = tvb_length_remaining(tvb, token_offset);
1246 reported_length = tvb_reported_length_remaining(tvb, token_offset);
1247 g_assert(available_length >= 0);
1248 g_assert(reported_length >= 0);
1249 if (available_length > reported_length)
1250 available_length = reported_length;
1251 if ((guint)available_length > cred_length)
1252 available_length = cred_length;
1253 if ((guint)reported_length > cred_length)
1254 reported_length = cred_length;
1255 new_tvb = tvb_new_subset(tvb, a->offset, available_length, reported_length);
1256 call_dissector(gssapi_handle, new_tvb, pinfo, gtree);
1257 a->offset += cred_length;
1259 if (read_bytestring(a, tree, hf_ldap_message_bind_server_credentials,
1260 NULL, NULL, ASN1_UNI, ASN1_OTS) != ASN1_ERR_NOERROR)
1266 if (read_bytestring(a, tree, hf_ldap_message_bind_server_credentials,
1267 NULL, NULL, ASN1_CTX, 7) != ASN1_ERR_NOERROR)
1274 static void dissect_ldap_request_search(ASN1_SCK *a, proto_tree *tree, packet_info *pinfo)
1281 if (read_string(a, tree, hf_ldap_message_search_base, 0, &s, 0, ASN1_UNI, ASN1_OTS) != ASN1_ERR_NOERROR)
1284 if (check_col(pinfo->cinfo, COL_INFO))
1285 col_append_fstr(pinfo->cinfo, COL_INFO, ", Base DN=%s", s != NULL ? s : "(null)");
1288 if (read_integer(a, tree, hf_ldap_message_search_scope, 0, 0, ASN1_ENUM) != ASN1_ERR_NOERROR)
1290 if (read_integer(a, tree, hf_ldap_message_search_deref, 0, 0, ASN1_ENUM) != ASN1_ERR_NOERROR)
1292 if (read_integer(a, tree, hf_ldap_message_search_sizeLimit, 0, 0, ASN1_INT) != ASN1_ERR_NOERROR)
1294 if (read_integer(a, tree, hf_ldap_message_search_timeLimit, 0, 0, ASN1_INT) != ASN1_ERR_NOERROR)
1296 if (read_boolean(a, tree, hf_ldap_message_search_typesOnly, 0, 0) != ASN1_ERR_NOERROR)
1298 if (!read_filter(a, tree, hf_ldap_message_search_filter))
1300 ret = read_sequence(a, &seq_length);
1301 if (ret != ASN1_ERR_NOERROR) {
1303 proto_tree_add_text(tree, a->tvb, a->offset, 0,
1304 "ERROR: Couldn't parse LDAP attribute sequence header: %s",
1305 asn1_err_to_str(ret));
1309 end = a->offset + seq_length;
1310 while (a->offset < end) {
1311 if (read_string(a, tree, hf_ldap_message_attribute, 0, 0, 0, ASN1_UNI,
1312 ASN1_OTS) != ASN1_ERR_NOERROR)
1317 static int dissect_mscldap_string(tvbuff_t *tvb, int offset, char *str, int maxlen, gboolean prepend_dot)
1321 len=tvb_get_guint8(tvb, offset);
1326 /* add potential field separation dot */
1339 /* ops its a mscldap compressed string */
1341 new_offset=tvb_get_guint8(tvb, offset);
1344 dissect_mscldap_string(tvb, new_offset, str, maxlen, FALSE);
1358 return offset; /* will mess up offset in caller, is unlikely */
1360 tvb_memcpy(tvb, str, offset, len);
1367 len=tvb_get_guint8(tvb, offset);
1375 /* These flag bits were found to be defined in the samba sources.
1376 * I hope they are correct (but have serious doubts about the CLOSEST
1377 * bit being used or being meaningful).
1379 static const true_false_string tfs_ads_pdc = {
1383 static const true_false_string tfs_ads_gc = {
1384 "This is a GLOBAL CATALOGUE of forest",
1385 "This is NOT a global catalog of forest"
1387 static const true_false_string tfs_ads_ldap = {
1388 "This is an LDAP server",
1389 "This is NOT an ldap server"
1391 static const true_false_string tfs_ads_ds = {
1392 "This dc supports DS",
1393 "This dc does NOT support ds"
1395 static const true_false_string tfs_ads_kdc = {
1396 "This is a KDC (kerberos)",
1397 "This is NOT a kdc (kerberos)"
1399 static const true_false_string tfs_ads_timeserv = {
1400 "This dc is running TIME SERVICES (ntp)",
1401 "This dc is NOT running time services (ntp)"
1403 static const true_false_string tfs_ads_closest = {
1404 "This is the CLOSEST dc (unreliable?)",
1405 "This is NOT the closest dc"
1407 static const true_false_string tfs_ads_writable = {
1408 "This dc is WRITABLE",
1409 "This dc is NOT writable"
1411 static const true_false_string tfs_ads_good_timeserv = {
1412 "This dc has a GOOD TIME SERVICE (i.e. hardware clock)",
1413 "This dc does NOT have a good time service (i.e. no hardware clock)"
1415 static const true_false_string tfs_ads_ndnc = {
1416 "Domain is NON-DOMAIN NC serviced by ldap server",
1417 "Domain is NOT non-domain nc serviced by ldap server"
1419 static int dissect_mscldap_netlogon_flags(proto_tree *parent_tree, tvbuff_t *tvb, int offset)
1423 proto_tree *tree=NULL;
1425 flags=tvb_get_letohl(tvb, offset);
1426 item=proto_tree_add_item(parent_tree, hf_mscldap_netlogon_flags, tvb, offset, 4, TRUE);
1428 tree = proto_item_add_subtree(item, ett_mscldap_netlogon_flags);
1431 proto_tree_add_boolean(tree, hf_mscldap_netlogon_flags_ndnc,
1432 tvb, offset, 4, flags);
1433 proto_tree_add_boolean(tree, hf_mscldap_netlogon_flags_good_timeserv,
1434 tvb, offset, 4, flags);
1435 proto_tree_add_boolean(tree, hf_mscldap_netlogon_flags_writable,
1436 tvb, offset, 4, flags);
1437 proto_tree_add_boolean(tree, hf_mscldap_netlogon_flags_closest,
1438 tvb, offset, 4, flags);
1439 proto_tree_add_boolean(tree, hf_mscldap_netlogon_flags_timeserv,
1440 tvb, offset, 4, flags);
1441 proto_tree_add_boolean(tree, hf_mscldap_netlogon_flags_kdc,
1442 tvb, offset, 4, flags);
1443 proto_tree_add_boolean(tree, hf_mscldap_netlogon_flags_ds,
1444 tvb, offset, 4, flags);
1445 proto_tree_add_boolean(tree, hf_mscldap_netlogon_flags_ldap,
1446 tvb, offset, 4, flags);
1447 proto_tree_add_boolean(tree, hf_mscldap_netlogon_flags_gc,
1448 tvb, offset, 4, flags);
1449 proto_tree_add_boolean(tree, hf_mscldap_netlogon_flags_pdc,
1450 tvb, offset, 4, flags);
1457 static void dissect_mscldap_response_netlogon(proto_tree *tree, tvbuff_t *tvb)
1459 int old_offset, offset=0;
1465 /*XXX someone that knows what the type means should add that knowledge here*/
1466 proto_tree_add_item(tree, hf_mscldap_netlogon_type, tvb, offset, 4, TRUE);
1470 offset = dissect_mscldap_netlogon_flags(tree, tvb, offset);
1473 proto_tree_add_item(tree, hf_mscldap_domain_guid, tvb, offset, 16, TRUE);
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);
1491 /* NetBios Domain */
1493 offset=dissect_mscldap_string(tvb, offset, str, 255, FALSE);
1494 proto_tree_add_string(tree, hf_mscldap_nb_domain, tvb, old_offset, offset-old_offset, str);
1496 /* NetBios Hostname */
1498 offset=dissect_mscldap_string(tvb, offset, str, 255, FALSE);
1499 proto_tree_add_string(tree, hf_mscldap_nb_hostname, tvb, old_offset, offset-old_offset, str);
1503 offset=dissect_mscldap_string(tvb, offset, str, 255, FALSE);
1504 proto_tree_add_string(tree, hf_mscldap_username, tvb, old_offset, offset-old_offset, str);
1508 offset=dissect_mscldap_string(tvb, offset, str, 255, FALSE);
1509 proto_tree_add_string(tree, hf_mscldap_sitename, tvb, old_offset, offset-old_offset, str);
1513 offset=dissect_mscldap_string(tvb, offset, str, 255, FALSE);
1514 proto_tree_add_string(tree, hf_mscldap_clientsitename, tvb, old_offset, offset-old_offset, str);
1517 proto_tree_add_item(tree, hf_mscldap_netlogon_version, tvb, offset, 4, TRUE);
1521 proto_tree_add_item(tree, hf_mscldap_netlogon_lm_token, tvb, offset, 2, TRUE);
1525 proto_tree_add_item(tree, hf_mscldap_netlogon_nt_token, tvb, offset, 2, TRUE);
1530 static void dissect_mscldap_response(proto_tree *tree, tvbuff_t *tvb, guint32 rpc)
1533 case MSCLDAP_RPC_NETLOGON:
1534 dissect_mscldap_response_netlogon(tree, tvb);
1537 proto_tree_add_text(tree, tvb, 0, tvb_length(tvb),
1538 "ERROR: Unknown type of MS-CLDAP RPC call");
1543 static void dissect_ldap_response_search_entry(ASN1_SCK *a, proto_tree *tree,
1544 gboolean is_mscldap)
1547 int end_of_sequence;
1551 guint32 mscldap_rpc;
1553 if (read_string(a, tree, hf_ldap_message_dn, 0, 0, 0, ASN1_UNI, ASN1_OTS) != ASN1_ERR_NOERROR)
1555 ret = read_sequence(a, &seq_length);
1556 if (ret != ASN1_ERR_NOERROR) {
1558 proto_tree_add_text(tree, a->tvb, a->offset, 0,
1559 "ERROR: Couldn't parse search entry response sequence header: %s",
1560 asn1_err_to_str(ret));
1565 end_of_sequence = a->offset + seq_length;
1566 while (a->offset < end_of_sequence)
1569 proto_tree *attr_tree;
1573 ret = read_sequence(a, 0);
1574 if (ret != ASN1_ERR_NOERROR) {
1576 proto_tree_add_text(tree, a->tvb, a->offset, 0,
1577 "ERROR: Couldn't parse LDAP attribute sequence header: %s",
1578 asn1_err_to_str(ret));
1582 if (read_string(a, tree, hf_ldap_message_attribute, &ti, &str, &len, ASN1_UNI, ASN1_OTS) != ASN1_ERR_NOERROR)
1587 if(!strncmp(str, "netlogon", 8)){
1588 mscldap_rpc=MSCLDAP_RPC_NETLOGON;
1595 attr_tree = proto_item_add_subtree(ti, ett_ldap_attribute);
1597 ret = read_set(a, &set_length);
1598 if (ret != ASN1_ERR_NOERROR) {
1600 proto_tree_add_text(attr_tree, a->tvb, a->offset, 0,
1601 "ERROR: Couldn't parse LDAP value set header: %s",
1602 asn1_err_to_str(ret));
1606 end_of_set = a->offset + set_length;
1607 while (a->offset < end_of_set) {
1609 if (read_string(a, attr_tree, hf_ldap_message_value, 0, 0, 0, ASN1_UNI,
1610 ASN1_OTS) != ASN1_ERR_NOERROR){
1614 guint cls, con, tag;
1617 int start = a->offset;
1619 tvbuff_t *mscldap_tvb=NULL;
1621 ret = asn1_header_decode(a, &cls, &con, &tag, &def, &len);
1622 if (ret == ASN1_ERR_NOERROR) {
1623 if (cls != ASN1_UNI || con != ASN1_PRI || tag != ASN1_OTS)
1624 ret = ASN1_ERR_WRONG_TYPE;
1626 if (ret != ASN1_ERR_NOERROR) {
1628 proto_tree_add_text(tree, a->tvb, start, 0,
1629 "%s: ERROR: Couldn't parse header: %s",
1630 proto_registrar_get_name(hf_ldap_message_value), asn1_err_to_str(ret));
1634 mscldap_tvb=tvb_new_subset(a->tvb, a->offset, len, len);
1635 dissect_mscldap_response(attr_tree, mscldap_tvb, mscldap_rpc);
1643 static void dissect_ldap_response_search_ref(ASN1_SCK *a, proto_tree *tree)
1645 read_string(a, tree, hf_ldap_message_search_reference, 0, 0, 0, ASN1_UNI, ASN1_OTS);
1648 static void dissect_ldap_request_add(ASN1_SCK *a, proto_tree *tree, packet_info *pinfo)
1651 int end_of_sequence;
1655 if (read_string(a, tree, hf_ldap_message_dn, 0, &s, 0, ASN1_UNI, ASN1_OTS) != ASN1_ERR_NOERROR)
1658 if (check_col(pinfo->cinfo, COL_INFO))
1659 col_append_fstr(pinfo->cinfo, COL_INFO, ", DN=%s", s != NULL ? s : "(null)");
1662 ret = read_sequence(a, &seq_length);
1663 if (ret != ASN1_ERR_NOERROR) {
1665 proto_tree_add_text(tree, a->tvb, a->offset, 0,
1666 "ERROR: Couldn't parse add request sequence header: %s",
1667 asn1_err_to_str(ret));
1672 end_of_sequence = a->offset + seq_length;
1673 while (a->offset < end_of_sequence)
1676 proto_tree *attr_tree;
1680 ret = read_sequence(a, 0);
1681 if (ret != ASN1_ERR_NOERROR) {
1683 proto_tree_add_text(tree, a->tvb, a->offset, 0,
1684 "ERROR: Couldn't parse LDAP attribute sequence header: %s",
1685 asn1_err_to_str(ret));
1689 if (read_string(a, tree, hf_ldap_message_attribute, &ti, 0, 0, ASN1_UNI,
1690 ASN1_OTS) != ASN1_ERR_NOERROR)
1692 attr_tree = proto_item_add_subtree(ti, ett_ldap_attribute);
1694 ret = read_set(a, &set_length);
1695 if (ret != ASN1_ERR_NOERROR) {
1697 proto_tree_add_text(attr_tree, a->tvb, a->offset, 0,
1698 "ERROR: Couldn't parse LDAP value set header: %s",
1699 asn1_err_to_str(ret));
1703 end_of_set = a->offset + set_length;
1704 while (a->offset < end_of_set) {
1705 if (read_string(a, attr_tree, hf_ldap_message_value, 0, 0, 0, ASN1_UNI, ASN1_OTS) != ASN1_ERR_NOERROR)
1711 static void dissect_ldap_request_delete(ASN1_SCK *a, proto_tree *tree,
1712 int start, guint length)
1714 read_string_value(a, tree, hf_ldap_message_dn, NULL, NULL, start, length);
1717 static void dissect_ldap_request_modifyrdn(ASN1_SCK *a, proto_tree *tree,
1720 int start = a->offset;
1722 if (read_string(a, tree, hf_ldap_message_dn, 0, 0, 0, ASN1_UNI, ASN1_OTS) != ASN1_ERR_NOERROR)
1724 if (read_string(a, tree, hf_ldap_message_modrdn_name, 0, 0, 0, ASN1_UNI, ASN1_OTS) != ASN1_ERR_NOERROR)
1726 if (read_boolean(a, tree, hf_ldap_message_modrdn_delete, 0, 0) != ASN1_ERR_NOERROR)
1729 if (a->offset < (int) (start + length)) {
1730 /* LDAP V3 Modify DN operation, with newSuperior */
1731 /* "newSuperior [0] LDAPDN OPTIONAL" (0x80) */
1732 if (read_string(a, tree, hf_ldap_message_modrdn_superior, 0, 0, 0, ASN1_CTX, 0) != ASN1_ERR_NOERROR)
1737 static void dissect_ldap_request_compare(ASN1_SCK *a, proto_tree *tree)
1741 char *string1 = NULL;
1742 char *string2 = NULL;
1747 if (read_string(a, tree, hf_ldap_message_dn, 0, 0, 0, ASN1_UNI, ASN1_OTS) != ASN1_ERR_NOERROR)
1749 ret = read_sequence(a, 0);
1750 if (ret != ASN1_ERR_NOERROR) {
1752 proto_tree_add_text(tree, a->tvb, a->offset, 0,
1753 "ERROR: Couldn't parse compare request sequence header: %s",
1754 asn1_err_to_str(ret));
1760 ret = read_string(a, 0, -1, 0, &string1, 0, ASN1_UNI, ASN1_OTS);
1761 if (ret != ASN1_ERR_NOERROR) {
1763 proto_tree_add_text(tree, a->tvb, start, 0,
1764 "ERROR: Couldn't parse compare type: %s", asn1_err_to_str(ret));
1768 ret = read_string(a, 0, -1, 0, &string2, 0, ASN1_UNI, ASN1_OTS);
1769 if (ret != ASN1_ERR_NOERROR) {
1771 proto_tree_add_text(tree, a->tvb, start, 0,
1772 "ERROR: Couldn't parse compare value: %s", asn1_err_to_str(ret));
1777 s1 = (string1 == NULL) ? "(null)" : string1;
1778 s2 = (string2 == NULL) ? "(null)" : string2;
1779 length = 2 + strlen(s1) + strlen(s2);
1780 compare = g_malloc0(length);
1781 snprintf(compare, length, "%s=%s", s1, s2);
1782 proto_tree_add_string(tree, hf_ldap_message_compare, a->tvb, start,
1783 a->offset-start, compare);
1792 static void dissect_ldap_request_modify(ASN1_SCK *a, proto_tree *tree)
1795 int end_of_sequence;
1798 if (read_string(a, tree, hf_ldap_message_dn, 0, 0, 0, ASN1_UNI, ASN1_OTS) != ASN1_ERR_NOERROR)
1800 ret = read_sequence(a, &seq_length);
1801 if (ret != ASN1_ERR_NOERROR) {
1803 proto_tree_add_text(tree, a->tvb, a->offset, 0,
1804 "ERROR: Couldn't parse modify request sequence header: %s",
1805 asn1_err_to_str(ret));
1809 end_of_sequence = a->offset + seq_length;
1810 while (a->offset < end_of_sequence)
1813 proto_tree *attr_tree;
1818 ret = read_sequence(a, 0);
1819 if (ret != ASN1_ERR_NOERROR) {
1821 proto_tree_add_text(tree, a->tvb, a->offset, 0,
1822 "ERROR: Couldn't parse modify request item sequence header: %s",
1823 asn1_err_to_str(ret));
1827 ret = read_integer(a, 0, -1, 0, &operation, ASN1_ENUM);
1828 if (ret != ASN1_ERR_NOERROR) {
1830 proto_tree_add_text(tree, a->tvb, a->offset, 0,
1831 "ERROR: Couldn't parse modify operation: %s",
1832 asn1_err_to_str(ret));
1836 ret = read_sequence(a, 0);
1837 if (ret != ASN1_ERR_NOERROR) {
1839 proto_tree_add_text(tree, a->tvb, a->offset, 0,
1840 "ERROR: Couldn't parse modify request operation sequence header: %s",
1841 asn1_err_to_str(ret));
1849 if (read_string(a, tree, hf_ldap_message_modify_add, &ti, 0, 0, ASN1_UNI,
1850 ASN1_OTS) != ASN1_ERR_NOERROR)
1854 case LDAP_MOD_REPLACE:
1855 if (read_string(a, tree, hf_ldap_message_modify_replace, &ti, 0, 0,
1856 ASN1_UNI, ASN1_OTS) != ASN1_ERR_NOERROR)
1860 case LDAP_MOD_DELETE:
1861 if (read_string(a, tree, hf_ldap_message_modify_delete, &ti, 0, 0,
1862 ASN1_UNI, ASN1_OTS) != ASN1_ERR_NOERROR)
1867 proto_tree_add_text(tree, a->tvb, a->offset, 0,
1868 "Unknown LDAP modify operation (%u)", operation);
1871 attr_tree = proto_item_add_subtree(ti, ett_ldap_attribute);
1873 ret = read_set(a, &set_length);
1874 if (ret != ASN1_ERR_NOERROR) {
1876 proto_tree_add_text(attr_tree, a->tvb, a->offset, 0,
1877 "ERROR: Couldn't parse LDAP value set header: %s",
1878 asn1_err_to_str(ret));
1882 end_of_set = a->offset + set_length;
1883 while (a->offset < end_of_set) {
1884 if (read_string(a, attr_tree, hf_ldap_message_value, 0, 0, 0, ASN1_UNI,
1885 ASN1_OTS) != ASN1_ERR_NOERROR)
1891 static void dissect_ldap_request_abandon(ASN1_SCK *a, proto_tree *tree,
1892 int start, guint length)
1894 read_integer_value(a, tree, hf_ldap_message_abandon_msgid, NULL, NULL,
1898 static ldap_call_response_t *
1899 ldap_match_call_response(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, ldap_conv_info_t *ldap_info, guint messageId, guint protocolOpTag)
1901 ldap_call_response_t lcr, *lcrp=NULL;
1903 if (!pinfo->fd->flags.visited) {
1904 switch(protocolOpTag){
1906 case LDAP_REQ_SEARCH:
1907 case LDAP_REQ_MODIFY:
1909 case LDAP_REQ_DELETE:
1910 case LDAP_REQ_MODRDN:
1911 case LDAP_REQ_COMPARE:
1912 /*case LDAP_REQ_ABANDON: we dont match for this one*/
1913 /*case LDAP_REQ_UNBIND: we dont match for this one*/
1914 /* check that we dont already have one of those in the
1915 unmatched list and if so remove it */
1916 lcr.messageId=messageId;
1917 lcrp=g_hash_table_lookup(ldap_info->unmatched, &lcr);
1919 g_hash_table_remove(ldap_info->unmatched, lcrp);
1921 /* if we cant reuse the old one, grab a new chunk */
1923 lcrp=g_mem_chunk_alloc(ldap_call_response_chunk);
1925 lcrp->messageId=messageId;
1926 lcrp->req_frame=pinfo->fd->num;
1927 lcrp->req_time.secs=pinfo->fd->abs_secs;
1928 lcrp->req_time.nsecs=pinfo->fd->abs_usecs*1000;
1930 lcrp->protocolOpTag=protocolOpTag;
1931 lcrp->is_request=TRUE;
1932 g_hash_table_insert(ldap_info->unmatched, lcrp, lcrp);
1936 case LDAP_RES_SEARCH_ENTRY:
1937 case LDAP_RES_SEARCH_REF:
1938 case LDAP_RES_SEARCH_RESULT:
1939 case LDAP_RES_MODIFY:
1941 case LDAP_RES_DELETE:
1942 case LDAP_RES_MODRDN:
1943 case LDAP_RES_COMPARE:
1944 lcr.messageId=messageId;
1945 lcrp=g_hash_table_lookup(ldap_info->unmatched, &lcr);
1947 if(!lcrp->rep_frame){
1948 g_hash_table_remove(ldap_info->unmatched, lcrp);
1949 lcrp->rep_frame=pinfo->fd->num;
1950 lcrp->is_request=FALSE;
1951 g_hash_table_insert(ldap_info->matched, lcrp, lcrp);
1958 lcr.messageId=messageId;
1959 switch(protocolOpTag){
1961 case LDAP_REQ_SEARCH:
1962 case LDAP_REQ_MODIFY:
1964 case LDAP_REQ_DELETE:
1965 case LDAP_REQ_MODRDN:
1966 case LDAP_REQ_COMPARE:
1967 /*case LDAP_REQ_ABANDON: we dont match for this one*/
1968 /*case LDAP_REQ_UNBIND: we dont match for this one*/
1969 lcr.is_request=TRUE;
1970 lcr.req_frame=pinfo->fd->num;
1974 case LDAP_RES_SEARCH_ENTRY:
1975 case LDAP_RES_SEARCH_REF:
1976 case LDAP_RES_SEARCH_RESULT:
1977 case LDAP_RES_MODIFY:
1979 case LDAP_RES_DELETE:
1980 case LDAP_RES_MODRDN:
1981 case LDAP_RES_COMPARE:
1982 lcr.is_request=FALSE;
1984 lcr.rep_frame=pinfo->fd->num;
1987 lcrp=g_hash_table_lookup(ldap_info->matched, &lcr);
1989 lcrp->is_request=lcr.is_request;
1993 if(lcrp->is_request){
1994 proto_tree_add_uint(tree, hf_ldap_response_in, tvb, 0, 0, lcrp->rep_frame);
1997 proto_tree_add_uint(tree, hf_ldap_response_to, tvb, 0, 0, lcrp->req_frame);
1998 ns.secs=pinfo->fd->abs_secs-lcrp->req_time.secs;
1999 ns.nsecs=pinfo->fd->abs_usecs*1000-lcrp->req_time.nsecs;
2001 ns.nsecs+=1000000000;
2004 proto_tree_add_time(tree, hf_ldap_time, tvb, 0, 0, &ns);
2013 dissect_ldap_message(tvbuff_t *tvb, int offset, packet_info *pinfo,
2014 proto_tree *ldap_tree, proto_item *ldap_item,
2015 gboolean first_time, ldap_conv_info_t *ldap_info,
2016 gboolean is_mscldap)
2018 int message_id_start;
2019 int message_id_length;
2020 guint messageLength;
2023 guint protocolOpCls, protocolOpCon, protocolOpTag;
2029 ldap_call_response_t *lcrp;
2031 asn1_open(&a, tvb, offset);
2033 ret = read_sequence(&a, &messageLength);
2034 if (ret != ASN1_ERR_NOERROR)
2038 if (check_col(pinfo->cinfo, COL_INFO))
2040 col_add_fstr(pinfo->cinfo, COL_INFO,
2041 "Invalid LDAP message (Can't parse sequence header: %s)",
2042 asn1_err_to_str(ret));
2047 proto_tree_add_text(ldap_tree, tvb, offset, -1,
2048 "Invalid LDAP message (Can't parse sequence header: %s)",
2049 asn1_err_to_str(ret));
2054 message_id_start = a.offset;
2055 ret = read_integer(&a, 0, hf_ldap_message_id, 0, &messageId, ASN1_INT);
2056 if (ret != ASN1_ERR_NOERROR)
2058 if (first_time && check_col(pinfo->cinfo, COL_INFO))
2059 col_add_fstr(pinfo->cinfo, COL_INFO, "Invalid LDAP packet (Can't parse Message ID: %s)",
2060 asn1_err_to_str(ret));
2062 proto_tree_add_text(ldap_tree, tvb, message_id_start, 1,
2063 "Invalid LDAP packet (Can't parse Message ID: %s)",
2064 asn1_err_to_str(ret));
2067 message_id_length = a.offset - message_id_start;
2070 asn1_id_decode(&a, &protocolOpCls, &protocolOpCon, &protocolOpTag);
2071 if (protocolOpCls != ASN1_APL)
2072 typestr = "Bad message type (not Application)";
2074 typestr = val_to_str(protocolOpTag, msgTypes, "Unknown message type (%u)");
2078 if (check_col(pinfo->cinfo, COL_INFO))
2079 col_add_fstr(pinfo->cinfo, COL_INFO, "MsgId=%u %s",
2080 messageId, typestr);
2084 proto_item_append_text(ldap_item, ", %s",
2085 val_to_str(protocolOpTag, msgTypes,
2086 "Unknown message type (%u)"));
2090 proto_tree_add_uint(ldap_tree, hf_ldap_message_id, tvb, message_id_start, message_id_length, messageId);
2091 if (protocolOpCls == ASN1_APL)
2093 proto_tree_add_uint(ldap_tree, hf_ldap_message_type, tvb,
2094 start, a.offset - start, protocolOpTag);
2098 proto_tree_add_text(ldap_tree, tvb, start, a.offset - start,
2103 if (read_length(&a, ldap_tree, hf_ldap_message_length, &opLen) != ASN1_ERR_NOERROR)
2106 if (protocolOpCls == ASN1_APL)
2108 lcrp=ldap_match_call_response(tvb, pinfo, ldap_tree, ldap_info, messageId, protocolOpTag);
2110 tap_queue_packet(ldap_tap, pinfo, lcrp);
2113 switch (protocolOpTag)
2116 dissect_ldap_request_bind(&a, ldap_tree, tvb, pinfo, ldap_info);
2118 case LDAP_REQ_UNBIND:
2119 /* Nothing to dissect */
2121 case LDAP_REQ_SEARCH:
2122 dissect_ldap_request_search(&a, ldap_tree, pinfo);
2124 case LDAP_REQ_MODIFY:
2125 dissect_ldap_request_modify(&a, ldap_tree);
2128 dissect_ldap_request_add(&a, ldap_tree, pinfo);
2130 case LDAP_REQ_DELETE:
2131 dissect_ldap_request_delete(&a, ldap_tree, start, opLen);
2133 case LDAP_REQ_MODRDN:
2134 dissect_ldap_request_modifyrdn(&a, ldap_tree, opLen);
2136 case LDAP_REQ_COMPARE:
2137 dissect_ldap_request_compare(&a, ldap_tree);
2139 case LDAP_REQ_ABANDON:
2140 dissect_ldap_request_abandon(&a, ldap_tree, start, opLen);
2143 dissect_ldap_response_bind(&a, ldap_tree, start, opLen, tvb, pinfo, ldap_info);
2145 case LDAP_RES_SEARCH_ENTRY: {
2147 * XXX - this assumes that the LDAP_RES_SEARCH_ENTRY and
2148 * LDAP_RES_SEARCH_RESULT appear in the same frame.
2150 guint32 *num_results = p_get_proto_data(pinfo->fd, proto_ldap);
2153 num_results = g_malloc(sizeof(guint32));
2155 p_add_proto_data(pinfo->fd, proto_ldap, num_results);
2159 dissect_ldap_response_search_entry(&a, ldap_tree, is_mscldap);
2163 case LDAP_RES_SEARCH_REF:
2164 dissect_ldap_response_search_ref(&a, ldap_tree);
2167 case LDAP_RES_SEARCH_RESULT: {
2168 guint32 *num_results = p_get_proto_data(pinfo->fd, proto_ldap);
2171 if (check_col(pinfo->cinfo, COL_INFO))
2172 col_append_fstr(pinfo->cinfo, COL_INFO, ", %d result%s",
2173 *num_results, *num_results == 1 ? "" : "s");
2174 g_free(num_results);
2175 p_rem_proto_data(pinfo->fd, proto_ldap);
2178 dissect_ldap_result(&a, ldap_tree, pinfo);
2183 case LDAP_RES_MODIFY:
2185 case LDAP_RES_DELETE:
2186 case LDAP_RES_MODRDN:
2187 case LDAP_RES_COMPARE:
2188 dissect_ldap_result(&a, ldap_tree, pinfo);
2193 proto_tree_add_text(ldap_tree, a.tvb, a.offset, opLen,
2194 "Unknown LDAP operation (%u)", protocolOpTag);
2201 * XXX - what if "next_offset" is past the offset of the next top-level
2202 * sequence? Show that as an error?
2204 asn1_close(&a, &next_offset); /* XXX - use the new value of next_offset? */
2209 dissect_ldap_pdu(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, gboolean is_mscldap)
2212 gboolean first_time = TRUE;
2213 conversation_t *conversation;
2214 gboolean doing_sasl_security = FALSE;
2215 guint length_remaining;
2216 guint32 sasl_length;
2217 guint32 message_data_len;
2218 proto_item *ti = NULL;
2219 proto_tree *ldap_tree = NULL;
2222 guint messageLength;
2226 gint available_length, reported_length;
2228 proto_item *gitem = NULL;
2229 proto_tree *gtree = NULL;
2231 ldap_conv_info_t *ldap_info=NULL;
2235 * Do we have a conversation for this connection?
2237 conversation = find_conversation(&pinfo->src, &pinfo->dst,
2238 pinfo->ptype, pinfo->srcport,
2239 pinfo->destport, 0);
2240 if (conversation == NULL) {
2241 /* We don't yet have a conversation, so create one. */
2242 conversation = conversation_new(&pinfo->src, &pinfo->dst,
2243 pinfo->ptype, pinfo->srcport,
2244 pinfo->destport, 0);
2247 * Do we already have a type and mechanism?
2249 ldap_info = conversation_get_proto_data(conversation, proto_ldap);
2250 if (ldap_info == NULL) {
2251 /* No. Attach that information to the conversation, and add
2252 it to the list of information structures. */
2253 ldap_info = g_mem_chunk_alloc(ldap_conv_info_chunk);
2254 ldap_info->auth_type = 0;
2255 ldap_info->auth_mech = 0;
2256 ldap_info->first_auth_frame = 0;
2257 ldap_info->matched=g_hash_table_new(ldap_info_hash_matched, ldap_info_equal_matched);
2258 ldap_info->unmatched=g_hash_table_new(ldap_info_hash_unmatched, ldap_info_equal_unmatched);
2259 conversation_add_proto_data(conversation, proto_ldap, ldap_info);
2260 ldap_info->next = ldap_info_items;
2261 ldap_info_items = ldap_info;
2264 switch (ldap_info->auth_type) {
2265 case LDAP_AUTH_SASL:
2267 * It's SASL; are we using a security layer?
2269 if (ldap_info->first_auth_frame != 0 &&
2270 pinfo->fd->num >= ldap_info->first_auth_frame)
2271 doing_sasl_security = TRUE; /* yes */
2277 while (tvb_reported_length_remaining(tvb, offset) > 0) {
2279 * This will throw an exception if we don't have any data left.
2280 * That's what we want. (See "tcp_dissect_pdus()", which is
2281 * similar, but doesn't have to deal with the SASL issues.
2282 * XXX - can we make "tcp_dissect_pdus()" provide enough information
2283 * to the "get_pdu_len" routine so that we could have one dealing
2284 * with the SASL issues, have that routine deal with SASL and
2285 * ASN.1, and just use "tcp_dissect_pdus()"?)
2287 length_remaining = tvb_ensure_length_remaining(tvb, offset);
2290 * Might we be doing a SASL security layer and, if so, *are* we doing
2293 * Just because we've seen a bind reply for SASL, that doesn't mean
2294 * that we're using a SASL security layer; I've seen captures in
2295 * which some SASL negotiations lead to a security layer being used
2296 * and other negotiations don't, and it's not obvious what's different
2297 * in the two negotiations. Therefore, we assume that if the first
2298 * byte is 0, it's a length for a SASL security layer (that way, we
2299 * never reassemble more than 16 megabytes, protecting us from
2300 * chewing up *too* much memory), and otherwise that it's an LDAP
2301 * message (actually, if it's an LDAP message it should begin with 0x30,
2302 * but we want to parse garbage as LDAP messages rather than really
2305 if (doing_sasl_security && tvb_get_guint8(tvb, offset) == 0) {
2307 * Yes. The frame begins with a 4-byte big-endian length.
2308 * Can we do reassembly?
2310 if (ldap_desegment && pinfo->can_desegment) {
2312 * Yes - is the SASL length split across segment boundaries?
2314 if (length_remaining < 4) {
2316 * Yes. Tell the TCP dissector where the data for this message
2317 * starts in the data it handed us, and how many more bytes we
2320 pinfo->desegment_offset = offset;
2321 pinfo->desegment_len = 4 - length_remaining;
2327 * Get the SASL length, which is the length of data in the buffer
2328 * following the length (i.e., it's 4 less than the total length).
2330 * XXX - do we need to reassemble buffers? For now, we
2331 * assume that each LDAP message is entirely contained within
2334 sasl_length = tvb_get_ntohl(tvb, offset);
2335 message_data_len = sasl_length + 4;
2336 if (message_data_len < 4) {
2338 * The message length was probably so large that the total length
2341 * Report this as an error.
2343 show_reported_bounds_error(tvb, pinfo, tree);
2348 * Is the buffer split across segment boundaries?
2350 if (length_remaining < message_data_len) {
2351 /* provide a hint to TCP where the next PDU starts */
2352 pinfo->want_pdu_tracking=2;
2353 pinfo->bytes_until_next_pdu=message_data_len-length_remaining;
2355 * Can we do reassembly?
2357 if (ldap_desegment && pinfo->can_desegment) {
2359 * Yes. Tell the TCP dissector where the data for this message
2360 * starts in the data it handed us, and how many more bytes we
2363 pinfo->desegment_offset = offset;
2364 pinfo->desegment_len = message_data_len - length_remaining;
2370 * Construct a tvbuff containing the amount of the payload we have
2371 * available. Make its reported length the amount of data in the PDU.
2373 * XXX - if reassembly isn't enabled. the subdissector will throw a
2374 * BoundsError exception, rather than a ReportedBoundsError exception.
2375 * We really want a tvbuff where the length is "length", the reported
2376 * length is "plen", and the "if the snapshot length were infinite"
2377 * length is the minimum of the reported length of the tvbuff handed
2378 * to us and "plen", with a new type of exception thrown if the offset
2379 * is within the reported length but beyond that third length, with
2380 * that exception getting the "Unreassembled Packet" error.
2382 length = length_remaining;
2383 if (length > message_data_len)
2384 length = message_data_len;
2385 next_tvb = tvb_new_subset(tvb, offset, length, message_data_len);
2388 * If this is the first PDU, set the Protocol column and clear the
2393 if (check_col(pinfo->cinfo, COL_PROTOCOL))
2394 col_set_str(pinfo->cinfo, COL_PROTOCOL, (gchar *)pinfo->current_proto);
2395 if (check_col(pinfo->cinfo, COL_INFO))
2396 col_clear(pinfo->cinfo, COL_INFO);
2401 ti = proto_tree_add_item(tree, proto_ldap, next_tvb, 0, -1, FALSE);
2402 ldap_tree = proto_item_add_subtree(ti, ett_ldap);
2404 proto_tree_add_uint(ldap_tree, hf_ldap_sasl_buffer_length, tvb, 0, 4,
2408 if (ldap_info->auth_mech != NULL &&
2409 strcmp(ldap_info->auth_mech, "GSS-SPNEGO") == 0) {
2411 * This is GSS-API (using SPNEGO, but we should be done with
2412 * the negotiation by now).
2414 * Dissect the GSS_Wrap() token; it'll return the length of
2415 * the token, from which we compute the offset in the tvbuff at
2416 * which the plaintext data, i.e. the LDAP message, begins.
2418 available_length = tvb_length_remaining(tvb, 4);
2419 reported_length = tvb_reported_length_remaining(tvb, 4);
2420 g_assert(available_length >= 0);
2421 g_assert(reported_length >= 0);
2422 if (available_length > reported_length)
2423 available_length = reported_length;
2424 if ((guint)available_length > sasl_length - 4)
2425 available_length = sasl_length - 4;
2426 if ((guint)reported_length > sasl_length - 4)
2427 reported_length = sasl_length - 4;
2428 next_tvb = tvb_new_subset(tvb, 4, available_length, reported_length);
2431 gitem = proto_tree_add_text(ldap_tree, next_tvb, 0, -1, "GSS-API Token");
2432 gtree = proto_item_add_subtree(gitem, ett_ldap_gssapi_token);
2434 len = call_dissector(gssapi_wrap_handle, next_tvb, pinfo, gtree);
2436 * if len is 0 it probably mean that we got a PDU that is not
2437 * aligned to the start of the segment.
2443 proto_item_set_len(gitem, len);
2446 * Now dissect the LDAP message.
2448 dissect_ldap_message(tvb, 4 + len, pinfo, ldap_tree, ti, first_time, ldap_info, is_mscldap);
2451 * We don't know how to handle other authentication mechanisms
2452 * yet, so just put in an entry for the SASL buffer.
2454 proto_tree_add_text(ldap_tree, tvb, 4, -1, "SASL buffer");
2456 offset += message_data_len;
2459 * No, we're not doing a SASL security layer. The frame begins
2460 * with a "Sequence Of" header.
2461 * Can we do reassembly?
2463 if (ldap_desegment && pinfo->can_desegment) {
2465 * Yes - is the "Sequence Of" header split across segment
2466 * boundaries? We require at least 6 bytes for the header
2467 * which allows for a 4 byte length (ASN.1 BER).
2469 if (length_remaining < 6) {
2470 pinfo->desegment_offset = offset;
2471 pinfo->desegment_len = 6 - length_remaining;
2476 /* It might still be a packet containing a SASL security layer
2477 * but its just that we never saw the BIND packet.
2478 * check if it looks like it could be a SASL blob here
2479 * and in that case just assume it is GSS-SPNEGO
2481 if( (tvb_bytes_exist(tvb, offset, 5))
2482 &&(tvb_get_ntohl(tvb, offset)<=(guint)(tvb_reported_length_remaining(tvb, offset)-4))
2483 &&(tvb_get_guint8(tvb, offset+4)==0x60) ){
2484 ldap_info->auth_type=LDAP_AUTH_SASL;
2485 ldap_info->first_auth_frame=pinfo->fd->num;
2486 ldap_info->auth_mech=g_strdup("GSS-SPNEGO");
2487 doing_sasl_security=TRUE;
2493 * OK, try to read the "Sequence Of" header; this gets the total
2494 * length of the LDAP message.
2496 asn1_open(&a, tvb, offset);
2497 ret = read_sequence(&a, &messageLength);
2498 asn1_close(&a, &messageOffset);
2500 if (ret == ASN1_ERR_NOERROR) {
2502 * Add the length of the "Sequence Of" header to the message
2505 headerLength = messageOffset - offset;
2506 messageLength += headerLength;
2507 if (messageLength < headerLength) {
2509 * The message length was probably so large that the total length
2512 * Report this as an error.
2514 show_reported_bounds_error(tvb, pinfo, tree);
2519 * We couldn't parse the header; just make it the amount of data
2520 * remaining in the tvbuff, so we'll give up on this segment
2521 * after attempting to parse the message - there's nothing more
2522 * we can do. "dissect_ldap_message()" will display the error.
2524 messageLength = length_remaining;
2528 * Is the message split across segment boundaries?
2530 if (length_remaining < messageLength) {
2531 /* provide a hint to TCP where the next PDU starts */
2532 pinfo->want_pdu_tracking=2;
2533 pinfo->bytes_until_next_pdu=messageLength-length_remaining;
2535 * Can we do reassembly?
2537 if (ldap_desegment && pinfo->can_desegment) {
2539 * Yes. Tell the TCP dissector where the data for this message
2540 * starts in the data it handed us, and how many more bytes
2541 * we need, and return.
2543 pinfo->desegment_offset = offset;
2544 pinfo->desegment_len = messageLength - length_remaining;
2550 * If this is the first PDU, set the Protocol column and clear the
2554 if (check_col(pinfo->cinfo, COL_PROTOCOL))
2555 col_set_str(pinfo->cinfo, COL_PROTOCOL, (gchar *)pinfo->current_proto);
2556 if (check_col(pinfo->cinfo, COL_INFO))
2557 col_clear(pinfo->cinfo, COL_INFO);
2561 * Construct a tvbuff containing the amount of the payload we have
2562 * available. Make its reported length the amount of data in the
2565 * XXX - if reassembly isn't enabled. the subdissector will throw a
2566 * BoundsError exception, rather than a ReportedBoundsError exception.
2567 * We really want a tvbuff where the length is "length", the reported
2568 * length is "plen", and the "if the snapshot length were infinite"
2569 * length is the minimum of the reported length of the tvbuff handed
2570 * to us and "plen", with a new type of exception thrown if the offset
2571 * is within the reported length but beyond that third length, with
2572 * that exception getting the "Unreassembled Packet" error.
2574 length = length_remaining;
2575 if (length > messageLength)
2576 length = messageLength;
2577 next_tvb = tvb_new_subset(tvb, offset, length, messageLength);
2580 * Now dissect the LDAP message.
2583 ti = proto_tree_add_item(tree, proto_ldap, next_tvb, 0, -1, FALSE);
2584 ldap_tree = proto_item_add_subtree(ti, ett_ldap);
2587 dissect_ldap_message(next_tvb, 0, pinfo, ldap_tree, ti, first_time, ldap_info, is_mscldap);
2589 offset += messageLength;
2599 dissect_ldap(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
2601 dissect_ldap_pdu(tvb, pinfo, tree, FALSE);
2606 dissect_mscldap(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
2608 dissect_ldap_pdu(tvb, pinfo, tree, TRUE);
2615 ldap_conv_info_t *ldap_info;
2617 /* Free up state attached to the ldap_info structures */
2618 for (ldap_info = ldap_info_items; ldap_info != NULL; ldap_info = ldap_info->next) {
2619 if (ldap_info->auth_mech != NULL) {
2620 g_free(ldap_info->auth_mech);
2621 ldap_info->auth_mech=NULL;
2623 g_hash_table_destroy(ldap_info->matched);
2624 ldap_info->matched=NULL;
2625 g_hash_table_destroy(ldap_info->unmatched);
2626 ldap_info->unmatched=NULL;
2629 if (ldap_conv_info_chunk != NULL)
2630 g_mem_chunk_destroy(ldap_conv_info_chunk);
2632 ldap_info_items = NULL;
2634 ldap_conv_info_chunk = g_mem_chunk_new("ldap_conv_info_chunk",
2635 sizeof(ldap_conv_info_t),
2636 ldap_conv_info_chunk_count * sizeof(ldap_conv_info_t),
2639 if (ldap_call_response_chunk != NULL)
2640 g_mem_chunk_destroy(ldap_call_response_chunk);
2642 ldap_call_response_chunk = g_mem_chunk_new("ldap_call_response_chunk",
2643 sizeof(ldap_call_response_t),
2644 ldap_call_response_chunk_count * sizeof(ldap_call_response_t),
2649 proto_register_ldap(void)
2651 static value_string auth_types[] = {
2652 {LDAP_AUTH_SIMPLE, "Simple"},
2653 {LDAP_AUTH_KRBV4LDAP, "Kerberos V4 to the LDAP server"},
2654 {LDAP_AUTH_KRBV4DSA, "Kerberos V4 to the DSA"},
2655 {LDAP_AUTH_SASL, "SASL"},
2659 static value_string search_scope[] = {
2666 static value_string search_dereference[] = {
2668 {0x01, "Searching"},
2669 {0x02, "Base Object"},
2674 static hf_register_info hf[] = {
2675 { &hf_ldap_response_in,
2676 { "Response In", "ldap.response_in",
2677 FT_FRAMENUM, BASE_DEC, NULL, 0x0,
2678 "The response to this packet is in this frame", HFILL }},
2680 { &hf_ldap_response_to,
2681 { "Response To", "ldap.response_to",
2682 FT_FRAMENUM, BASE_DEC, NULL, 0x0,
2683 "This is a response to the LDAP command in this frame", HFILL }},
2686 { "Time", "ldap.time",
2687 FT_RELATIVE_TIME, BASE_NONE, NULL, 0x0,
2688 "The time between the Call and the Reply", HFILL }},
2690 { &hf_ldap_sasl_buffer_length,
2691 { "SASL Buffer Length", "ldap.sasl_buffer_length",
2692 FT_UINT32, BASE_DEC, NULL, 0x0,
2693 "SASL Buffer Length", HFILL }},
2696 { "Length", "ldap.length",
2697 FT_UINT32, BASE_DEC, NULL, 0x0,
2698 "LDAP Length", HFILL }},
2700 { &hf_ldap_message_id,
2701 { "Message Id", "ldap.message_id",
2702 FT_UINT32, BASE_DEC, NULL, 0x0,
2703 "LDAP Message Id", HFILL }},
2704 { &hf_ldap_message_type,
2705 { "Message Type", "ldap.message_type",
2706 FT_UINT8, BASE_HEX, &msgTypes, 0x0,
2707 "LDAP Message Type", HFILL }},
2708 { &hf_ldap_message_length,
2709 { "Message Length", "ldap.message_length",
2710 FT_UINT32, BASE_DEC, NULL, 0x0,
2711 "LDAP Message Length", HFILL }},
2713 { &hf_ldap_message_result,
2714 { "Result Code", "ldap.result.code",
2715 FT_UINT8, BASE_HEX, result_codes, 0x0,
2716 "LDAP Result Code", HFILL }},
2717 { &hf_ldap_message_result_matcheddn,
2718 { "Matched DN", "ldap.result.matcheddn",
2719 FT_STRING, BASE_NONE, NULL, 0x0,
2720 "LDAP Result Matched DN", HFILL }},
2721 { &hf_ldap_message_result_errormsg,
2722 { "Error Message", "ldap.result.errormsg",
2723 FT_STRING, BASE_NONE, NULL, 0x0,
2724 "LDAP Result Error Message", HFILL }},
2725 { &hf_ldap_message_result_referral,
2726 { "Referral", "ldap.result.referral",
2727 FT_STRING, BASE_NONE, NULL, 0x0,
2728 "LDAP Result Referral URL", HFILL }},
2730 { &hf_ldap_message_bind_version,
2731 { "Version", "ldap.bind.version",
2732 FT_UINT32, BASE_DEC, NULL, 0x0,
2733 "LDAP Bind Version", HFILL }},
2734 { &hf_ldap_message_bind_dn,
2735 { "DN", "ldap.bind.dn",
2736 FT_STRING, BASE_NONE, NULL, 0x0,
2737 "LDAP Bind Distinguished Name", HFILL }},
2738 { &hf_ldap_message_bind_auth,
2739 { "Auth Type", "ldap.bind.auth_type",
2740 FT_UINT8, BASE_HEX, auth_types, 0x0,
2741 "LDAP Bind Auth Type", HFILL }},
2742 { &hf_ldap_message_bind_auth_password,
2743 { "Password", "ldap.bind.password",
2744 FT_STRING, BASE_NONE, NULL, 0x0,
2745 "LDAP Bind Password", HFILL }},
2746 { &hf_ldap_message_bind_auth_mechanism,
2747 { "Mechanism", "ldap.bind.mechanism",
2748 FT_STRING, BASE_NONE, NULL, 0x0,
2749 "LDAP Bind Mechanism", HFILL }},
2750 { &hf_ldap_message_bind_auth_credentials,
2751 { "Credentials", "ldap.bind.credentials",
2752 FT_BYTES, BASE_NONE, NULL, 0x0,
2753 "LDAP Bind Credentials", HFILL }},
2754 { &hf_ldap_message_bind_server_credentials,
2755 { "Server Credentials", "ldap.bind.server_credentials",
2756 FT_BYTES, BASE_NONE, NULL, 0x0,
2757 "LDAP Bind Server Credentials", HFILL }},
2759 { &hf_ldap_message_search_base,
2760 { "Base DN", "ldap.search.basedn",
2761 FT_STRING, BASE_NONE, NULL, 0x0,
2762 "LDAP Search Base Distinguished Name", HFILL }},
2763 { &hf_ldap_message_search_scope,
2764 { "Scope", "ldap.search.scope",
2765 FT_UINT8, BASE_HEX, search_scope, 0x0,
2766 "LDAP Search Scope", HFILL }},
2767 { &hf_ldap_message_search_deref,
2768 { "Dereference", "ldap.search.dereference",
2769 FT_UINT8, BASE_HEX, search_dereference, 0x0,
2770 "LDAP Search Dereference", HFILL }},
2771 { &hf_ldap_message_search_sizeLimit,
2772 { "Size Limit", "ldap.search.sizelimit",
2773 FT_UINT32, BASE_DEC, NULL, 0x0,
2774 "LDAP Search Size Limit", HFILL }},
2775 { &hf_ldap_message_search_timeLimit,
2776 { "Time Limit", "ldap.search.timelimit",
2777 FT_UINT32, BASE_DEC, NULL, 0x0,
2778 "LDAP Search Time Limit", HFILL }},
2779 { &hf_ldap_message_search_typesOnly,
2780 { "Attributes Only", "ldap.search.typesonly",
2781 FT_BOOLEAN, BASE_NONE, NULL, 0x0,
2782 "LDAP Search Attributes Only", HFILL }},
2783 { &hf_ldap_message_search_filter,
2784 { "Filter", "ldap.search.filter",
2785 FT_STRING, BASE_NONE, NULL, 0x0,
2786 "LDAP Search Filter", HFILL }},
2787 { &hf_ldap_message_search_reference,
2788 { "Reference URL", "ldap.search.reference",
2789 FT_STRING, BASE_NONE, NULL, 0x0,
2790 "LDAP Search Reference URL", HFILL }},
2791 { &hf_ldap_message_dn,
2792 { "Distinguished Name", "ldap.dn",
2793 FT_STRING, BASE_NONE, NULL, 0x0,
2794 "LDAP Distinguished Name", HFILL }},
2795 { &hf_ldap_message_attribute,
2796 { "Attribute", "ldap.attribute",
2797 FT_STRING, BASE_NONE, NULL, 0x0,
2798 "LDAP Attribute", HFILL }},
2800 * XXX - not all LDAP values are text strings; we'd need a file
2801 * describing which values (by name) are text strings and which are
2804 * Some values that are, at least in Microsoft's schema, binary
2808 * nTSecurityDescriptor
2811 { &hf_ldap_message_value,
2812 { "Value", "ldap.value",
2813 FT_STRING, BASE_NONE, NULL, 0x0,
2814 "LDAP Value", HFILL }},
2816 { &hf_ldap_message_modrdn_name,
2817 { "New Name", "ldap.modrdn.name",
2818 FT_STRING, BASE_NONE, NULL, 0x0,
2819 "LDAP New Name", HFILL }},
2820 { &hf_ldap_message_modrdn_delete,
2821 { "Delete Values", "ldap.modrdn.delete",
2822 FT_BOOLEAN, BASE_NONE, NULL, 0x0,
2823 "LDAP Modify RDN - Delete original values", HFILL }},
2824 { &hf_ldap_message_modrdn_superior,
2825 { "New Location", "ldap.modrdn.superior",
2826 FT_STRING, BASE_NONE, NULL, 0x0,
2827 "LDAP Modify RDN - New Location", HFILL }},
2829 { &hf_ldap_message_compare,
2830 { "Test", "ldap.compare.test",
2831 FT_STRING, BASE_NONE, NULL, 0x0,
2832 "LDAP Compare Test", HFILL }},
2834 { &hf_ldap_message_modify_add,
2835 { "Add", "ldap.modify.add",
2836 FT_STRING, BASE_NONE, NULL, 0x0,
2837 "LDAP Add", HFILL }},
2838 { &hf_ldap_message_modify_replace,
2839 { "Replace", "ldap.modify.replace",
2840 FT_STRING, BASE_NONE, NULL, 0x0,
2841 "LDAP Replace", HFILL }},
2842 { &hf_ldap_message_modify_delete,
2843 { "Delete", "ldap.modify.delete",
2844 FT_STRING, BASE_NONE, NULL, 0x0,
2845 "LDAP Delete", HFILL }},
2847 { &hf_ldap_message_abandon_msgid,
2848 { "Abandon Msg Id", "ldap.abandon.msgid",
2849 FT_UINT32, BASE_DEC, NULL, 0x0,
2850 "LDAP Abandon Msg Id", HFILL }},
2852 { &hf_mscldap_netlogon_type,
2853 { "Type", "mscldap.netlogon.type",
2854 FT_UINT32, BASE_DEC, NULL, 0x0,
2855 "Type of <please tell ethereal developers what this type is>", HFILL }},
2857 { &hf_mscldap_netlogon_version,
2858 { "Version", "mscldap.netlogon.version",
2859 FT_UINT32, BASE_DEC, NULL, 0x0,
2860 "Version of <please tell ethereal developers what this type is>", HFILL }},
2862 { &hf_mscldap_netlogon_lm_token,
2863 { "LM Token", "mscldap.netlogon.lm_token",
2864 FT_UINT16, BASE_HEX, NULL, 0x0,
2865 "LM Token", HFILL }},
2867 { &hf_mscldap_netlogon_nt_token,
2868 { "NT Token", "mscldap.netlogon.nt_token",
2869 FT_UINT16, BASE_HEX, NULL, 0x0,
2870 "NT Token", HFILL }},
2872 { &hf_mscldap_netlogon_flags,
2873 { "Flags", "mscldap.netlogon.flags",
2874 FT_UINT32, BASE_HEX, NULL, 0x0,
2875 "Netlogon flags describing the DC properties", HFILL }},
2877 { &hf_mscldap_domain_guid,
2878 { "Domain GUID", "mscldap.domain.guid",
2879 FT_BYTES, BASE_HEX, NULL, 0x0,
2880 "Domain GUID", HFILL }},
2882 { &hf_mscldap_forest,
2883 { "Forest", "mscldap.forest",
2884 FT_STRING, BASE_NONE, NULL, 0x0,
2887 { &hf_mscldap_domain,
2888 { "Domain", "mscldap.domain",
2889 FT_STRING, BASE_NONE, NULL, 0x0,
2890 "Domainname", HFILL }},
2892 { &hf_mscldap_hostname,
2893 { "Hostname", "mscldap.hostname",
2894 FT_STRING, BASE_NONE, NULL, 0x0,
2895 "Hostname", HFILL }},
2897 { &hf_mscldap_nb_domain,
2898 { "NetBios Domain", "mscldap.nb_domain",
2899 FT_STRING, BASE_NONE, NULL, 0x0,
2900 "NetBios Domainname", HFILL }},
2902 { &hf_mscldap_nb_hostname,
2903 { "NetBios Hostname", "mscldap.nb_hostname",
2904 FT_STRING, BASE_NONE, NULL, 0x0,
2905 "NetBios Hostname", HFILL }},
2907 { &hf_mscldap_username,
2908 { "User", "mscldap.username",
2909 FT_STRING, BASE_NONE, NULL, 0x0,
2910 "User name", HFILL }},
2912 { &hf_mscldap_sitename,
2913 { "Site", "mscldap.sitename",
2914 FT_STRING, BASE_NONE, NULL, 0x0,
2915 "Site name", HFILL }},
2917 { &hf_mscldap_clientsitename,
2918 { "Client Site", "mscldap.clientsitename",
2919 FT_STRING, BASE_NONE, NULL, 0x0,
2920 "Client Site name", HFILL }},
2922 { &hf_mscldap_netlogon_flags_pdc,
2923 { "PDC", "mscldap.netlogon.flags.pdc", FT_BOOLEAN, 32,
2924 TFS(&tfs_ads_pdc), 0x00000001, "Is this DC a PDC or not?", HFILL }},
2926 { &hf_mscldap_netlogon_flags_gc,
2927 { "GC", "mscldap.netlogon.flags.gc", FT_BOOLEAN, 32,
2928 TFS(&tfs_ads_gc), 0x00000004, "Does this dc service as a GLOBAL CATALOGUE?", HFILL }},
2930 { &hf_mscldap_netlogon_flags_ldap,
2931 { "LDAP", "mscldap.netlogon.flags.ldap", FT_BOOLEAN, 32,
2932 TFS(&tfs_ads_ldap), 0x00000008, "Does this DC act as an LDAP server?", HFILL }},
2934 { &hf_mscldap_netlogon_flags_ds,
2935 { "DS", "mscldap.netlogon.flags.ds", FT_BOOLEAN, 32,
2936 TFS(&tfs_ads_ds), 0x00000010, "Does this dc provide DS services?", HFILL }},
2938 { &hf_mscldap_netlogon_flags_kdc,
2939 { "KDC", "mscldap.netlogon.flags.kdc", FT_BOOLEAN, 32,
2940 TFS(&tfs_ads_kdc), 0x00000020, "Does this dc act as a KDC?", HFILL }},
2942 { &hf_mscldap_netlogon_flags_timeserv,
2943 { "Time Serv", "mscldap.netlogon.flags.timeserv", FT_BOOLEAN, 32,
2944 TFS(&tfs_ads_timeserv), 0x00000040, "Does this dc provide time services (ntp) ?", HFILL }},
2946 { &hf_mscldap_netlogon_flags_closest,
2947 { "Closest", "mscldap.netlogon.flags.closest", FT_BOOLEAN, 32,
2948 TFS(&tfs_ads_closest), 0x00000080, "Is this the closest dc? (is this used at all?)", HFILL }},
2950 { &hf_mscldap_netlogon_flags_writable,
2951 { "Writable", "mscldap.netlogon.flags.writable", FT_BOOLEAN, 32,
2952 TFS(&tfs_ads_writable), 0x00000100, "Is this dc writable? (i.e. can it update the AD?)", HFILL }},
2954 { &hf_mscldap_netlogon_flags_good_timeserv,
2955 { "Good Time Serv", "mscldap.netlogon.flags.good_timeserv", FT_BOOLEAN, 32,
2956 TFS(&tfs_ads_good_timeserv), 0x00000200, "Is this a Good Time Server? (i.e. does it have a hardware clock)", HFILL }},
2958 { &hf_mscldap_netlogon_flags_ndnc,
2959 { "NDNC", "mscldap.netlogon.flags.ndnc", FT_BOOLEAN, 32,
2960 TFS(&tfs_ads_ndnc), 0x00000400, "Is this an NDNC dc?", HFILL }},
2964 static gint *ett[] = {
2966 &ett_ldap_gssapi_token,
2967 &ett_ldap_referrals,
2968 &ett_ldap_attribute,
2969 &ett_mscldap_netlogon_flags
2971 module_t *ldap_module;
2973 proto_ldap = proto_register_protocol("Lightweight Directory Access Protocol",
2975 proto_register_field_array(proto_ldap, hf, array_length(hf));
2976 proto_register_subtree_array(ett, array_length(ett));
2978 ldap_module = prefs_register_protocol(proto_ldap, NULL);
2979 prefs_register_bool_preference(ldap_module, "desegment_ldap_messages",
2980 "Desegment all LDAP messages spanning multiple TCP segments",
2981 "Whether the LDAP dissector should desegment all messages spanning multiple TCP segments",
2984 proto_cldap = proto_register_protocol(
2985 "Connectionless Lightweight Directory Access Protocol",
2988 register_init_routine(ldap_reinit);
2989 ldap_tap=register_tap("ldap");
2993 proto_reg_handoff_ldap(void)
2995 dissector_handle_t ldap_handle, cldap_handle;
2997 ldap_handle = create_dissector_handle(dissect_ldap, proto_ldap);
2998 dissector_add("tcp.port", TCP_PORT_LDAP, ldap_handle);
2999 dissector_add("tcp.port", TCP_PORT_GLOBALCAT_LDAP, ldap_handle);
3001 cldap_handle = create_dissector_handle(dissect_mscldap, proto_cldap);
3002 dissector_add("udp.port", UDP_PORT_CLDAP, cldap_handle);
3004 gssapi_handle = find_dissector("gssapi");
3005 gssapi_wrap_handle = find_dissector("gssapi_verf");