Make sure we don't feed a null string to strncmp(). Fixes bug 161.
[obnox/wireshark/wip.git] / epan / dissectors / packet-ldap.c
1 /* packet-ldap.c
2  * Routines for ldap packet dissection
3  *
4  * See RFC 1777 (LDAP v2), RFC 2251 (LDAP v3), and RFC 2222 (SASL).
5  *
6  * $Id$
7  *
8  * Ethereal - Network traffic analyzer
9  * By Gerald Combs <gerald@ethereal.com>
10  * Copyright 1998 Gerald Combs
11  *
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.
16  *
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.
21  *
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.
25  */
26
27 /*
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.
31  *
32  * There should probably be alot more error checking, I simply assume that if we have a full packet, it will be a complete
33  * and correct packet.
34  *
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
37  * I can do.
38  *
39  * Doug Nazar
40  * nazard@dragoninc.on.ca
41  */
42
43 /*
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
46  *              TCP segments.
47  *
48  * Ronald W. Henderson
49  * ronald.henderson@cognicaseusa.com
50  */
51
52 /*
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
56  *                    by Anthony Liguori
57  * ronnie sahlberg
58  */
59
60 /*
61  * 17-DEC-2004 - added basic decoding for LDAP Controls
62  * 20-DEC-2004 - added handling for GSS-API encrypted blobs
63  *
64  * Stefan Metzmacher <metze@samba.org>
65  */
66
67 #ifdef HAVE_CONFIG_H
68 # include "config.h"
69 #endif
70
71 #include <stdio.h>
72
73 #include <string.h>
74 #include <glib.h>
75
76 #ifdef NEED_SNPRINTF_H
77 # include "snprintf.h"
78 #endif
79
80 #include <epan/packet.h>
81
82 #include <epan/asn1.h>
83 #include <epan/prefs.h>
84 #include <epan/conversation.h>
85 #include "packet-frame.h"
86 #include <epan/tap.h>
87 #include "packet-ber.h"
88 #include "packet-ldap.h"
89
90 static int proto_ldap = -1;
91 static int proto_cldap = -1;
92 static int hf_ldap_response_to = -1;
93 static int hf_ldap_response_in = -1;
94 static int hf_ldap_time = -1;
95 static int hf_ldap_sasl_buffer_length = -1;
96 static int hf_ldap_length = -1;
97 static int hf_ldap_message_id = -1;
98 static int hf_ldap_message_type = -1;
99 static int hf_ldap_message_length = -1;
100
101 static int hf_ldap_message_result = -1;
102 static int hf_ldap_message_result_matcheddn = -1;
103 static int hf_ldap_message_result_errormsg = -1;
104 static int hf_ldap_message_result_referral = -1;
105
106 static int hf_ldap_message_bind_version = -1;
107 static int hf_ldap_message_bind_dn = -1;
108 static int hf_ldap_message_bind_auth = -1;
109 static int hf_ldap_message_bind_auth_password = -1;
110 static int hf_ldap_message_bind_auth_mechanism = -1;
111 static int hf_ldap_message_bind_auth_credentials = -1;
112 static int hf_ldap_message_bind_server_credentials = -1;
113
114 static int hf_ldap_message_search_base = -1;
115 static int hf_ldap_message_search_scope = -1;
116 static int hf_ldap_message_search_deref = -1;
117 static int hf_ldap_message_search_sizeLimit = -1;
118 static int hf_ldap_message_search_timeLimit = -1;
119 static int hf_ldap_message_search_typesOnly = -1;
120 static int hf_ldap_message_search_filter = -1;
121 static int hf_ldap_message_search_reference = -1;
122
123 static int hf_ldap_message_dn = -1;
124 static int hf_ldap_message_attribute = -1;
125 static int hf_ldap_message_value = -1;
126
127 static int hf_ldap_message_modrdn_name = -1;
128 static int hf_ldap_message_modrdn_delete = -1;
129 static int hf_ldap_message_modrdn_superior = -1;
130
131 static int hf_ldap_message_compare = -1;
132
133 static int hf_ldap_message_modify_add = -1;
134 static int hf_ldap_message_modify_replace = -1;
135 static int hf_ldap_message_modify_delete = -1;
136
137 static int hf_ldap_message_abandon_msgid = -1;
138
139 static int hf_ldap_message_controls_oid = -1;
140 static int hf_ldap_message_controls_critical = -1;
141 static int hf_ldap_message_controls_value = -1;
142
143 static int hf_mscldap_netlogon_type = -1;
144 static int hf_mscldap_netlogon_flags = -1;
145 static int hf_mscldap_netlogon_flags_pdc = -1;
146 static int hf_mscldap_netlogon_flags_gc = -1;
147 static int hf_mscldap_netlogon_flags_ldap = -1;
148 static int hf_mscldap_netlogon_flags_ds = -1;
149 static int hf_mscldap_netlogon_flags_kdc = -1;
150 static int hf_mscldap_netlogon_flags_timeserv = -1;
151 static int hf_mscldap_netlogon_flags_closest = -1;
152 static int hf_mscldap_netlogon_flags_writable = -1;
153 static int hf_mscldap_netlogon_flags_good_timeserv = -1;
154 static int hf_mscldap_netlogon_flags_ndnc = -1;
155 static int hf_mscldap_domain_guid = -1;
156 static int hf_mscldap_forest = -1;
157 static int hf_mscldap_domain = -1;
158 static int hf_mscldap_hostname = -1;
159 static int hf_mscldap_nb_domain = -1;
160 static int hf_mscldap_nb_hostname = -1;
161 static int hf_mscldap_username = -1;
162 static int hf_mscldap_sitename = -1;
163 static int hf_mscldap_clientsitename = -1;
164 static int hf_mscldap_netlogon_version = -1;
165 static int hf_mscldap_netlogon_lm_token = -1;
166 static int hf_mscldap_netlogon_nt_token = -1;
167
168 static gint ett_ldap = -1;
169 static gint ett_ldap_msg = -1;
170 static gint ett_ldap_payload = -1;
171 static gint ett_ldap_sasl_blob = -1;
172 static gint ett_ldap_referrals = -1;
173 static gint ett_ldap_attribute = -1;
174 static gint ett_ldap_controls = -1;
175 static gint ett_ldap_control = -1;
176 static gint ett_mscldap_netlogon_flags = -1;
177
178 static int ldap_tap = -1;
179
180 /* desegmentation of LDAP */
181 static gboolean ldap_desegment = TRUE;
182
183 #define TCP_PORT_LDAP                   389
184 #define UDP_PORT_CLDAP                  389
185 #define TCP_PORT_GLOBALCAT_LDAP         3268 /* Windows 2000 Global Catalog */
186
187 static dissector_handle_t gssapi_handle;
188 static dissector_handle_t gssapi_wrap_handle;
189
190
191 /* different types of rpc calls ontop of ms cldap */
192 #define MSCLDAP_RPC_NETLOGON    1
193
194
195 /*
196  * Data structure attached to a conversation, giving authentication
197  * information from a bind request.
198  * We keep a linked list of them, so that we can free up all the
199  * authentication mechanism strings.
200  */
201 typedef struct ldap_conv_info_t {
202   struct ldap_conv_info_t *next;
203   guint auth_type;              /* authentication type */
204   char *auth_mech;              /* authentication mechanism */
205   guint32 first_auth_frame;     /* first frame that would use a security layer */
206   GHashTable *unmatched;
207   GHashTable *matched;
208 } ldap_conv_info_t;
209 static GMemChunk *ldap_conv_info_chunk = NULL;
210 static guint ldap_conv_info_chunk_count = 20;
211 static ldap_conv_info_t *ldap_info_items;
212
213 static GMemChunk *ldap_call_response_chunk = NULL;
214 static guint ldap_call_response_chunk_count = 200;
215
216 static guint
217 ldap_info_hash_matched(gconstpointer k)
218 {
219   const ldap_call_response_t *key = k;
220
221   return key->messageId;
222 }
223
224 static gint
225 ldap_info_equal_matched(gconstpointer k1, gconstpointer k2)
226 {
227   const ldap_call_response_t *key1 = k1;
228   const ldap_call_response_t *key2 = k2;
229
230   if( key1->req_frame && key2->req_frame && (key1->req_frame!=key2->req_frame) ){
231     return 0;
232   }
233   if( key1->rep_frame && key2->rep_frame && (key1->rep_frame!=key2->rep_frame) ){
234     return 0;
235   }
236
237   return key1->messageId==key2->messageId;
238 }
239
240 static guint
241 ldap_info_hash_unmatched(gconstpointer k)
242 {
243   const ldap_call_response_t *key = k;
244
245   return key->messageId;
246 }
247
248 static gint
249 ldap_info_equal_unmatched(gconstpointer k1, gconstpointer k2)
250 {
251   const ldap_call_response_t *key1 = k1;
252   const ldap_call_response_t *key2 = k2;
253
254   return key1->messageId==key2->messageId;
255 }
256
257
258 static value_string msgTypes [] = {
259   {LDAP_REQ_BIND, "Bind Request"},
260   {LDAP_REQ_UNBIND, "Unbind Request"},
261   {LDAP_REQ_SEARCH, "Search Request"},
262   {LDAP_REQ_MODIFY, "Modify Request"},
263   {LDAP_REQ_ADD, "Add Request"},
264   {LDAP_REQ_DELETE, "Delete Request"},
265   {LDAP_REQ_MODRDN, "Modify RDN Request"},
266   {LDAP_REQ_COMPARE, "Compare Request"},
267   {LDAP_REQ_ABANDON, "Abandon Request"},
268   {LDAP_REQ_EXTENDED, "Extended Request"},
269
270   {LDAP_RES_BIND, "Bind Result"},
271   {LDAP_RES_SEARCH_ENTRY, "Search Entry"},
272   {LDAP_RES_SEARCH_RESULT, "Search Result"},
273   {LDAP_RES_SEARCH_REF, "Search Result Reference"},
274   {LDAP_RES_MODIFY, "Modify Result"},
275   {LDAP_RES_ADD, "Add Result"},
276   {LDAP_RES_DELETE, "Delete Result"},
277   {LDAP_RES_MODRDN, "Modify RDN Result"},
278   {LDAP_RES_COMPARE, "Compare Result"},
279   {LDAP_RES_EXTENDED, "Extended Response"},
280   {0, NULL},
281 };
282
283 static const value_string LDAPResultCode_vals[] = {
284   {   0, "success" },
285   {   1, "operationsError" },
286   {   2, "protocolError" },
287   {   3, "timeLimitExceeded" },
288   {   4, "sizeLimitExceeded" },
289   {   5, "compareFalse" },
290   {   6, "compareTrue" },
291   {   7, "authMethodNotSupported" },
292   {   8, "strongAuthRequired" },
293   {  10, "referral" },
294   {  11, "adminLimitExceeded" },
295   {  12, "unavailableCriticalExtension" },
296   {  13, "confidentialityRequired" },
297   {  14, "saslBindInProgress" },
298   {  16, "noSuchAttribute" },
299   {  17, "undefinedAttributeType" },
300   {  18, "inappropriateMatching" },
301   {  19, "constraintViolation" },
302   {  20, "attributeOrValueExists" },
303   {  21, "invalidAttributeSyntax" },
304   {  32, "noSuchObject" },
305   {  33, "aliasProblem" },
306   {  34, "invalidDNSyntax" },
307   {  36, "aliasDereferencingProblem" },
308   {  48, "inappropriateAuthentication" },
309   {  49, "invalidCredentials" },
310   {  50, "insufficientAccessRights" },
311   {  51, "busy" },
312   {  52, "unavailable" },
313   {  53, "unwillingToPerform" },
314   {  54, "loopDetect" },
315   {  64, "namingViolation" },
316   {  65, "objectClassViolation" },
317   {  66, "notAllowedOnNonLeaf" },
318   {  67, "notAllowedOnRDN" },
319   {  68, "entryAlreadyExists" },
320   {  69, "objectClassModsProhibited" },
321   {  71, "affectsMultipleDSAs" },
322   {  80, "other" },
323   { 0, NULL }
324 };
325
326 static int read_length(ASN1_SCK *a, proto_tree *tree, int hf_id, guint *len)
327 {
328   guint length = 0;
329   gboolean def = FALSE;
330   int start = a->offset;
331   int ret;
332
333   ret = asn1_length_decode(a, &def, &length);
334   if (ret != ASN1_ERR_NOERROR) {
335     if (tree) {
336       proto_tree_add_text(tree, a->tvb, start, 0,
337         "%s: ERROR: Couldn't parse length: %s",
338         proto_registrar_get_name(hf_id), asn1_err_to_str(ret));
339     }
340     return ret;
341   }
342
343   if (len)
344     *len = length;
345
346   if (tree)
347     proto_tree_add_uint(tree, hf_id, a->tvb, start, a->offset-start, length);
348
349   return ASN1_ERR_NOERROR;
350 }
351
352 static int read_sequence(ASN1_SCK *a, guint *len)
353 {
354   guint cls, con, tag;
355   gboolean def;
356   guint length;
357   int ret;
358
359   ret = asn1_header_decode(a, &cls, &con, &tag, &def, &length);
360   if (ret != ASN1_ERR_NOERROR)
361     return ret;
362   if (cls != ASN1_UNI || con != ASN1_CON || tag != ASN1_SEQ)
363     return ASN1_ERR_WRONG_TYPE;
364
365   if (len)
366     *len = length;
367
368   return ASN1_ERR_NOERROR;
369 }
370
371 static int read_set(ASN1_SCK *a, guint *len)
372 {
373   guint cls, con, tag;
374   gboolean def;
375   guint length;
376   int ret;
377
378   ret = asn1_header_decode(a, &cls, &con, &tag, &def, &length);
379   if (ret != ASN1_ERR_NOERROR)
380     return ret;
381   if (cls != ASN1_UNI || con != ASN1_CON || tag != ASN1_SET)
382     return ASN1_ERR_WRONG_TYPE;
383
384   if (len)
385     *len = length;
386
387   return ASN1_ERR_NOERROR;
388 }
389
390 static int read_integer_value(ASN1_SCK *a, proto_tree *tree, int hf_id,
391         proto_item **new_item, guint *i, int start, guint length)
392 {
393   guint integer = 0;
394   proto_item *temp_item = NULL;
395   int ret;
396
397   ret = asn1_uint32_value_decode(a, length, &integer);
398   if (ret != ASN1_ERR_NOERROR) {
399     if (tree) {
400       proto_tree_add_text(tree, a->tvb, start, 0,
401        "%s: ERROR: Couldn't parse value: %s",
402         proto_registrar_get_name(hf_id), asn1_err_to_str(ret));
403     }
404     return ret;
405   }
406
407   if (i)
408     *i = integer;
409
410   if (tree)
411     temp_item = proto_tree_add_uint(tree, hf_id, a->tvb, start, a->offset-start, integer);
412
413   if (new_item)
414     *new_item = temp_item;
415
416   return ASN1_ERR_NOERROR;
417 }
418
419 static int read_integer(ASN1_SCK *a, proto_tree *tree, int hf_id,
420         proto_item **new_item, guint *i, guint expected_tag)
421 {
422   guint cls, con, tag;
423   gboolean def;
424   guint length;
425   int start = a->offset;
426   int ret;
427
428   ret = asn1_header_decode(a, &cls, &con, &tag, &def, &length);
429   if (ret == ASN1_ERR_NOERROR) {
430     if (cls != ASN1_UNI || con != ASN1_PRI || tag != expected_tag)
431       ret = ASN1_ERR_WRONG_TYPE;
432   }
433   if (ret != ASN1_ERR_NOERROR) {
434     if (tree) {
435       proto_tree_add_text(tree, a->tvb, start, 0,
436         "%s: ERROR: Couldn't parse header: %s",
437         (hf_id != -1) ? proto_registrar_get_name(hf_id) : "LDAP message",
438         asn1_err_to_str(ret));
439     }
440     return ret;
441   }
442
443   return read_integer_value(a, tree, hf_id, new_item, i, start, length);
444 }
445
446 static int read_boolean_value(ASN1_SCK *a, proto_tree *tree, int hf_id,
447         proto_item **new_item, guint *i, int start, guint length)
448 {
449   guint integer = 0;
450   proto_item *temp_item = NULL;
451   int ret;
452
453   ret = asn1_uint32_value_decode(a, length, &integer);
454   if (ret != ASN1_ERR_NOERROR) {
455     if (tree) {
456       proto_tree_add_text(tree, a->tvb, start, 0,
457         "%s: ERROR: Couldn't parse value: %s",
458         proto_registrar_get_name(hf_id), asn1_err_to_str(ret));
459     }
460     return ret;
461   }
462
463   if (i)
464     *i = integer;
465
466   if (tree)
467     temp_item = proto_tree_add_boolean(tree, hf_id, a->tvb, start, a->offset-start, integer);
468   if (new_item)
469     *new_item = temp_item;
470
471   return ASN1_ERR_NOERROR;
472 }
473
474 static int read_boolean(ASN1_SCK *a, proto_tree *tree, int hf_id,
475         proto_item **new_item, guint *i)
476 {
477   guint cls, con, tag;
478   gboolean def;
479   guint length;
480   int start = a->offset;
481   int ret;
482
483   ret = asn1_header_decode(a, &cls, &con, &tag, &def, &length);
484   if (ret == ASN1_ERR_NOERROR) {
485     if (cls != ASN1_UNI || con != ASN1_PRI || tag != ASN1_BOL)
486       ret = ASN1_ERR_WRONG_TYPE;
487   }
488   if (ret != ASN1_ERR_NOERROR) {
489     if (tree) {
490       proto_tree_add_text(tree, a->tvb, start, 0,
491         "%s: ERROR: Couldn't parse header: %s",
492         proto_registrar_get_name(hf_id), asn1_err_to_str(ret));
493     }
494     return ret;
495   }
496
497   return read_boolean_value(a, tree, hf_id, new_item, i, start, length);
498 }
499
500 static int read_string_value(ASN1_SCK *a, proto_tree *tree, int hf_id,
501         proto_item **new_item, char **s, int start, guint length)
502 {
503   guchar *string;
504   proto_item *temp_item = NULL;
505   int ret;
506
507   if (length)
508   {
509     ret = asn1_string_value_decode(a, length, &string);
510     if (ret != ASN1_ERR_NOERROR) {
511       if (tree) {
512         proto_tree_add_text(tree, a->tvb, start, 0,
513           "%s: ERROR: Couldn't parse value: %s",
514           proto_registrar_get_name(hf_id), asn1_err_to_str(ret));
515       }
516       return ret;
517     }
518     string = g_realloc(string, length + 1);
519     string[length] = '\0';
520   }
521   else
522     string = g_strdup("(null)");
523
524   if (tree)
525     temp_item = proto_tree_add_string(tree, hf_id, a->tvb, start, a->offset - start, string);
526   if (new_item)
527     *new_item = temp_item;
528
529   if (s && length)
530     *s = string;
531   else if (length)
532     g_free(string);
533
534   return ASN1_ERR_NOERROR;
535 }
536
537 static int read_string(ASN1_SCK *a, proto_tree *tree, int hf_id,
538         proto_item **new_item, char **s, guint *length,
539         guint expected_cls, guint expected_tag)
540 {
541   guint cls, con, tag;
542   gboolean def;
543   guint tmplen;
544   int start = a->offset;
545   int ret;
546
547   ret = asn1_header_decode(a, &cls, &con, &tag, &def, &tmplen);
548   if (ret == ASN1_ERR_NOERROR) {
549     if (cls != expected_cls || con != ASN1_PRI || tag != expected_tag)
550       ret = ASN1_ERR_WRONG_TYPE;
551   }
552   if (ret != ASN1_ERR_NOERROR) {
553     if (tree) {
554       proto_tree_add_text(tree, a->tvb, start, 0,
555         "%s: ERROR: Couldn't parse header: %s",
556         proto_registrar_get_name(hf_id), asn1_err_to_str(ret));
557     }
558     return ret;
559   }
560
561   if(length){
562      *length=tmplen;
563   }
564   return read_string_value(a, tree, hf_id, new_item, s, start, tmplen);
565 }
566
567 static int read_bytestring_value(ASN1_SCK *a, proto_tree *tree, int hf_id,
568         proto_item **new_item, char **s, int start, guint length)
569 {
570   guchar *string;
571   proto_item *temp_item = NULL;
572   int ret;
573
574   if (length)
575   {
576     ret = asn1_string_value_decode(a, length, &string);
577     if (ret != ASN1_ERR_NOERROR) {
578       if (tree) {
579         proto_tree_add_text(tree, a->tvb, start, 0,
580           "%s: ERROR: Couldn't parse value: %s",
581           proto_registrar_get_name(hf_id), asn1_err_to_str(ret));
582       }
583       return ret;
584     }
585     string = g_realloc(string, length + 1);
586     string[length] = '\0';
587   }
588   else
589     string = "(null)";
590
591   if (tree)
592     temp_item = proto_tree_add_bytes(tree, hf_id, a->tvb, start, a->offset - start, string);
593   if (new_item)
594     *new_item = temp_item;
595
596   if (s && length)
597     *s = string;
598   else if (length)
599     g_free(string);
600
601   return ASN1_ERR_NOERROR;
602 }
603
604 static int read_bytestring(ASN1_SCK *a, proto_tree *tree, int hf_id,
605         proto_item **new_item, char **s, guint expected_cls, guint expected_tag)
606 {
607   guint cls, con, tag;
608   gboolean def;
609   guint length;
610   int start = a->offset;
611   int ret;
612
613   ret = asn1_header_decode(a, &cls, &con, &tag, &def, &length);
614   if (ret == ASN1_ERR_NOERROR) {
615     if (cls != expected_cls || con != ASN1_PRI || tag != expected_tag)
616       ret = ASN1_ERR_WRONG_TYPE;
617   }
618   if (ret != ASN1_ERR_NOERROR) {
619     if (tree) {
620       proto_tree_add_text(tree, a->tvb, start, 0,
621         "%s: ERROR: Couldn't parse header: %s",
622         proto_registrar_get_name(hf_id), asn1_err_to_str(ret));
623     }
624     return ret;
625   }
626
627   return read_bytestring_value(a, tree, hf_id, new_item, s, start, length);
628 }
629
630 static int check_optional_tag(ASN1_SCK *a, guint expected_cls, guint expected_con, guint expected_tag)
631 {
632   guint cls, con, tag;
633   gboolean def;
634   guint length;
635   int ret;
636   int replay_offset;
637
638   replay_offset = a->offset;
639
640   ret = asn1_header_decode(a, &cls, &con, &tag, &def, &length);
641   if (ret == ASN1_ERR_NOERROR) {
642     if (cls != expected_cls || con != expected_con || tag != expected_tag) {
643       ret = ASN1_ERR_WRONG_TYPE;
644     }
645   }
646
647   a->offset = replay_offset;
648
649   return ret;
650 }
651
652 static int parse_filter_strings(ASN1_SCK *a, char **filter, guint *filter_length, const guchar *operation)
653 {
654   guchar *string;
655   guchar *string2;
656   guint string_length;
657   guint string2_length;
658   guint string_bytes;
659   char *filterp;
660   int ret;
661
662   ret = asn1_octet_string_decode(a, &string, &string_length, &string_bytes);
663   if (ret != ASN1_ERR_NOERROR)
664     return ret;
665   ret = asn1_octet_string_decode(a, &string2, &string2_length, &string_bytes);
666   if (ret != ASN1_ERR_NOERROR)
667     return ret;
668   *filter_length += 2 + strlen(operation) + string_length + string2_length;
669   *filter = g_realloc(*filter, *filter_length);
670   filterp = *filter + strlen(*filter);
671   *filterp++ = '(';
672   if (string_length != 0) {
673         memcpy(filterp, string, string_length);
674         filterp += string_length;
675   }
676   strcpy(filterp, operation);
677   filterp += strlen(operation);
678   if (string2_length != 0) {
679         memcpy(filterp, string2, string2_length);
680         filterp += string2_length;
681   }
682   *filterp++ = ')';
683   *filterp = '\0';
684   g_free(string);
685   g_free(string2);
686   return ASN1_ERR_NOERROR;
687 }
688
689 /* Richard Dawe: To parse substring filters, I added this function. */
690 static int parse_filter_substrings(ASN1_SCK *a, char **filter, guint *filter_length)
691 {
692   int end;
693   guchar *string;
694   char *filterp;
695   guint string_length;
696   guint string_bytes;
697   guint seq_len;
698   guint header_bytes;
699   int ret, any_valued;
700
701   /* For ASN.1 parsing of octet strings */
702   guint        cls;
703   guint        con;
704   guint        tag;
705   gboolean     def;
706
707   ret = asn1_octet_string_decode(a, &string, &string_length, &string_bytes);
708   if (ret != ASN1_ERR_NOERROR)
709     return ret;
710
711   ret = asn1_sequence_decode(a, &seq_len, &header_bytes);
712   if (ret != ASN1_ERR_NOERROR)
713     return ret;
714
715   *filter_length += 2 + 1 + string_length;
716   *filter = g_realloc(*filter, *filter_length);
717
718   filterp = *filter + strlen(*filter);
719   *filterp++ = '(';
720   if (string_length != 0) {
721     memcpy(filterp, string, string_length);
722     filterp += string_length;
723   }
724   *filterp++ = '=';
725   *filterp = '\0';
726   g_free(string);
727
728   /* Now decode seq_len's worth of octet strings. */
729   any_valued = 0;
730   end = a->offset + seq_len;
731
732   while (a->offset < end) {
733     /* Octet strings here are context-specific, which
734      * asn1_octet_string_decode() barfs on. Emulate it, but don't barf. */
735     ret = asn1_header_decode (a, &cls, &con, &tag, &def, &string_length);
736     if (ret != ASN1_ERR_NOERROR)
737       return ret;
738
739     /* XXX - check the tag? */
740     if (cls != ASN1_CTX || con != ASN1_PRI) {
741         /* XXX - handle the constructed encoding? */
742         return ASN1_ERR_WRONG_TYPE;
743     }
744     if (!def)
745         return ASN1_ERR_LENGTH_NOT_DEFINITE;
746
747     ret = asn1_string_value_decode(a, (int) string_length, &string);
748     if (ret != ASN1_ERR_NOERROR)
749       return ret;
750
751     /* If we have an 'any' component with a string value, we need to append
752      * an extra asterisk before final component. */
753     if ((tag == 1) && (string_length != 0))
754       any_valued = 1;
755
756     if ( (tag == 1) || ((tag == 2) && any_valued) )
757       (*filter_length)++;
758     *filter_length += string_length;
759     *filter = g_realloc(*filter, *filter_length);
760
761     filterp = *filter + strlen(*filter);
762     if ( (tag == 1) || ((tag == 2) && any_valued) )
763       *filterp++ = '*';
764     if (tag == 2)
765       any_valued = 0;
766     if (string_length != 0) {
767       memcpy(filterp, string, string_length);
768       filterp += string_length;
769     }
770     *filterp = '\0';
771     g_free(string);
772   }
773
774   if (any_valued)
775   {
776     (*filter_length)++;
777     *filter = g_realloc(*filter, *filter_length);
778     filterp = *filter + strlen(*filter);
779     *filterp++ = '*';
780   }
781
782   /* NB: Allocated byte for this earlier */
783   *filterp++ = ')';
784   *filterp = '\0';
785
786   return ASN1_ERR_NOERROR;
787 }
788
789 /* Returns -1 if we're at the end, returns an ASN1_ERR value otherwise. */
790 static int parse_filter(ASN1_SCK *a, char **filter, guint *filter_length,
791                         int *end)
792 {
793   guint cls, con, tag;
794   guint length;
795   gboolean def;
796   int ret;
797   static const char extensibleMatch[] = "(extensibleMatch not decoded)";
798
799   ret = asn1_header_decode(a, &cls, &con, &tag, &def, &length);
800   if (ret != ASN1_ERR_NOERROR)
801     return ret;
802
803   if (*end == 0)
804   {
805     *end = a->offset + length;
806     *filter_length = 1;
807     *filter = g_malloc0(*filter_length);
808   }
809
810   if (cls == ASN1_CTX)  /* XXX - handle other types as errors? */
811   {
812     switch (tag)
813     {
814      case LDAP_FILTER_AND:
815       {
816         int add_end;
817
818         if (con != ASN1_CON)
819           return ASN1_ERR_WRONG_TYPE;
820         add_end = a->offset + length;
821         *filter_length += 3;
822         *filter = g_realloc(*filter, *filter_length);
823         strcat(*filter, "(&");
824         while ((ret = parse_filter(a, filter, filter_length, &add_end))
825                 == ASN1_ERR_NOERROR)
826           continue;
827         if (ret != -1)
828           return ret;
829         strcat(*filter, ")");
830       }
831       break;
832      case LDAP_FILTER_OR:
833       {
834         int or_end;
835
836         if (con != ASN1_CON)
837           return ASN1_ERR_WRONG_TYPE;
838         or_end = a->offset + length;
839         *filter_length += 3;
840         *filter = g_realloc(*filter, *filter_length);
841         strcat(*filter, "(|");
842         while ((ret = parse_filter(a, filter, filter_length, &or_end))
843                 == ASN1_ERR_NOERROR)
844           continue;
845         if (ret != -1)
846           return ret;
847         strcat(*filter, ")");
848       }
849       break;
850      case LDAP_FILTER_NOT:
851       {
852         int not_end;
853
854         if (con != ASN1_CON)
855           return ASN1_ERR_WRONG_TYPE;
856         not_end = a->offset + length;
857         *filter_length += 3;
858         *filter = g_realloc(*filter, *filter_length);
859         strcat(*filter, "(!");
860         ret = parse_filter(a, filter, filter_length, &not_end);
861         if (ret != -1 && ret != ASN1_ERR_NOERROR)
862           return ret;
863         strcat(*filter, ")");
864       }
865       break;
866      case LDAP_FILTER_EQUALITY:
867       if (con != ASN1_CON)
868         return ASN1_ERR_WRONG_TYPE;
869       ret = parse_filter_strings(a, filter, filter_length, "=");
870       if (ret != ASN1_ERR_NOERROR)
871         return ret;
872       break;
873      case LDAP_FILTER_GE:
874       if (con != ASN1_CON)
875         return ASN1_ERR_WRONG_TYPE;
876       ret = parse_filter_strings(a, filter, filter_length, ">=");
877       if (ret != ASN1_ERR_NOERROR)
878         return ret;
879       break;
880      case LDAP_FILTER_LE:
881       if (con != ASN1_CON)
882         return ASN1_ERR_WRONG_TYPE;
883       ret = parse_filter_strings(a, filter, filter_length, "<=");
884       if (ret != -1 && ret != ASN1_ERR_NOERROR)
885         return ret;
886       break;
887      case LDAP_FILTER_APPROX:
888       if (con != ASN1_CON)
889         return ASN1_ERR_WRONG_TYPE;
890       ret = parse_filter_strings(a, filter, filter_length, "~=");
891       if (ret != ASN1_ERR_NOERROR)
892         return ret;
893       break;
894      case LDAP_FILTER_PRESENT:
895       {
896         guchar *string;
897         char *filterp;
898
899         if (con != ASN1_PRI)
900           return ASN1_ERR_WRONG_TYPE;
901         ret = asn1_string_value_decode(a, length, &string);
902         if (ret != ASN1_ERR_NOERROR)
903           return ret;
904         *filter_length += 4 + length;
905         *filter = g_realloc(*filter, *filter_length);
906         filterp = *filter + strlen(*filter);
907         *filterp++ = '(';
908         if (length != 0) {
909           memcpy(filterp, string, length);
910           filterp += length;
911         }
912         *filterp++ = '=';
913         *filterp++ = '*';
914         *filterp++ = ')';
915         *filterp = '\0';
916         g_free(string);
917       }
918       break;
919      case LDAP_FILTER_SUBSTRINGS:
920       if (con != ASN1_CON)
921         return ASN1_ERR_WRONG_TYPE;
922       /* Richard Dawe: Handle substrings */
923       ret = parse_filter_substrings(a, filter, filter_length);
924       if (ret != ASN1_ERR_NOERROR)
925         return ret;
926       break;
927      case LDAP_FILTER_EXTENSIBLE:
928       if (con != ASN1_CON)
929         return ASN1_ERR_WRONG_TYPE;
930       /* XXX - put a real decoder in here */
931       ret = asn1_null_decode(a, length);
932       if (ret != ASN1_ERR_NOERROR)
933         return ret;
934       *filter_length += sizeof extensibleMatch - 1;
935       *filter = g_realloc(*filter, *filter_length);
936       strcat(*filter, extensibleMatch);
937       break;
938      default:
939       return ASN1_ERR_WRONG_TYPE;
940     }
941   }
942
943   if (a->offset == *end)
944     return -1;
945   else
946     return ASN1_ERR_NOERROR;
947 }
948
949 static gboolean read_filter(ASN1_SCK *a, proto_tree *tree, int hf_id)
950 {
951   int start = a->offset;
952   char *filter = 0;
953   guint filter_length = 0;
954   int end = 0;
955   int ret;
956
957   while ((ret = parse_filter(a, &filter, &filter_length, &end))
958         == ASN1_ERR_NOERROR)
959     continue;
960
961   if (tree) {
962     if (ret != -1) {
963       proto_tree_add_text(tree, a->tvb, start, 0,
964         "%s: ERROR: Can't parse filter: %s",
965         proto_registrar_get_name(hf_id), asn1_err_to_str(ret));
966     } else
967       proto_tree_add_string(tree, hf_id, a->tvb, start, a->offset-start, filter);
968   }
969
970   g_free(filter);
971
972   return (ret == -1) ? TRUE : FALSE;
973 }
974
975 /********************************************************************************************/
976
977 static void dissect_ldap_result(ASN1_SCK *a, proto_tree *tree, packet_info *pinfo)
978 {
979   guint resultCode = 0;
980   int ret;
981   if (read_integer(a, tree, hf_ldap_message_result, 0, &resultCode, ASN1_ENUM) != ASN1_ERR_NOERROR)
982     return;
983
984   if (resultCode != 0) {
985           if (check_col(pinfo->cinfo, COL_INFO))
986                   col_append_fstr(pinfo->cinfo, COL_INFO, ", %s", 
987                                   val_to_str(resultCode, LDAPResultCode_vals,
988                                              "Unknown (%u)"));
989   }
990
991   if (read_string(a, tree, hf_ldap_message_result_matcheddn, 0, 0, 0, ASN1_UNI, ASN1_OTS) != ASN1_ERR_NOERROR)
992     return;
993   if (read_string(a, tree, hf_ldap_message_result_errormsg, 0, 0, 0, ASN1_UNI, ASN1_OTS) != ASN1_ERR_NOERROR)
994     return;
995
996   if (resultCode == 10)         /* Referral */
997   {
998     int start = a->offset;
999     int end;
1000     guint length;
1001     proto_item *ti;
1002     proto_tree *referralTree;
1003
1004     ret = read_sequence(a, &length);
1005     if (ret != ASN1_ERR_NOERROR) {
1006       if (tree) {
1007         proto_tree_add_text(tree, a->tvb, start, 0,
1008             "ERROR: Couldn't parse referral URL sequence header: %s",
1009             asn1_err_to_str(ret));
1010       }
1011       return;
1012     }
1013     ti = proto_tree_add_text(tree, a->tvb, start, length, "Referral URLs");
1014     referralTree = proto_item_add_subtree(ti, ett_ldap_referrals);
1015
1016     end = a->offset + length;
1017     while (a->offset < end) {
1018       if (read_string(a, referralTree, hf_ldap_message_result_referral, 0, 0, 0, ASN1_UNI, ASN1_OTS) != ASN1_ERR_NOERROR)
1019         return;
1020     }
1021   }
1022 }
1023
1024 static void dissect_ldap_request_bind(ASN1_SCK *a, proto_tree *tree,
1025     tvbuff_t *tvb, packet_info *pinfo, ldap_conv_info_t *ldap_info)
1026 {
1027   guint cls, con, tag;
1028   gboolean def;
1029   guint length;
1030   int start;
1031   int end;
1032   int ret;
1033   char *mechanism, *s = NULL;
1034   int token_offset;
1035   gint available_length, reported_length;
1036   tvbuff_t *new_tvb;
1037
1038   if (read_integer(a, tree, hf_ldap_message_bind_version, 0, 0, ASN1_INT) != ASN1_ERR_NOERROR)
1039     return;
1040   if (read_string(a, tree, hf_ldap_message_bind_dn, 0, &s, 0, ASN1_UNI, ASN1_OTS) != ASN1_ERR_NOERROR)
1041     return;
1042
1043   if (check_col(pinfo->cinfo, COL_INFO))
1044     col_append_fstr(pinfo->cinfo, COL_INFO, ", DN=%s", s != NULL ? s : "(null)");
1045   g_free(s);
1046
1047   start = a->offset;
1048   ret = asn1_header_decode(a, &cls, &con, &tag, &def, &length);
1049   if (ret == ASN1_ERR_NOERROR) {
1050     if (cls != ASN1_CTX) {
1051       /* RFCs 1777 and 2251 say these are context-specific types */
1052       ret = ASN1_ERR_WRONG_TYPE;
1053     }
1054   }
1055   if (ret != ASN1_ERR_NOERROR) {
1056     proto_tree_add_text(tree, a->tvb, start, 0,
1057       "%s: ERROR: Couldn't parse header: %s",
1058       proto_registrar_get_name(hf_ldap_message_bind_auth),
1059       asn1_err_to_str(ret));
1060     return;
1061   }
1062   proto_tree_add_uint(tree, hf_ldap_message_bind_auth, a->tvb, start,
1063                         a->offset - start, tag);
1064   end = a->offset + length;
1065   switch (tag)
1066   {
1067    case LDAP_AUTH_SIMPLE:
1068     if (read_string_value(a, tree, hf_ldap_message_bind_auth_password, NULL,
1069                           NULL, start, length) != ASN1_ERR_NOERROR)
1070       return;
1071     break;
1072
1073     /* For Kerberos V4, dissect it as a ticket. */
1074
1075    case LDAP_AUTH_SASL:
1076     mechanism = NULL;
1077     if (read_string(a, tree, hf_ldap_message_bind_auth_mechanism, NULL,
1078                     &mechanism, 0, ASN1_UNI, ASN1_OTS) != ASN1_ERR_NOERROR)
1079       return;
1080
1081     /*
1082      * We need to remember the authentication type and mechanism for this
1083      * conversation.
1084      *
1085      * XXX - actually, we might need to remember more than one
1086      * type and mechanism, if you can unbind and rebind with a
1087      * different type and/or mechanism.
1088      */
1089     ldap_info->auth_type = tag;
1090     ldap_info->auth_mech = mechanism;
1091     ldap_info->first_auth_frame = 0;    /* not known until we see the bind reply */
1092     /*
1093      * If the mechanism in this request is an empty string (which is
1094      * returned as a null pointer), use the saved mechanism instead.
1095      * Otherwise, if the saved mechanism is an empty string (null),
1096      * save this mechanism.
1097      */
1098     if (mechanism == NULL)
1099         mechanism = ldap_info->auth_mech;
1100     else {
1101       if (ldap_info->auth_mech == NULL) {
1102         g_free(ldap_info->auth_mech);
1103       }
1104       ldap_info->auth_mech = mechanism;
1105     }
1106
1107     if (a->offset < end) {
1108       if (mechanism != NULL && strcmp(mechanism, "GSS-SPNEGO") == 0) {
1109         /*
1110          * This is a GSS-API token ancapsulated within GSS-SPNEGO.
1111          * Find out how big it is by parsing the ASN.1 header for the
1112          * OCTET STREAM that contains it.
1113          */
1114         token_offset = a->offset;
1115         ret = asn1_header_decode(a, &cls, &con, &tag, &def, &length);
1116         if (ret != ASN1_ERR_NOERROR) {
1117           proto_tree_add_text(tree, a->tvb, token_offset, 0,
1118             "%s: ERROR: Couldn't parse header: %s",
1119             proto_registrar_get_name(hf_ldap_message_bind_auth_credentials),
1120             asn1_err_to_str(ret));
1121           return;
1122         }
1123         available_length = tvb_length_remaining(tvb, token_offset);
1124         reported_length = tvb_reported_length_remaining(tvb, token_offset);
1125         g_assert(available_length >= 0);
1126         g_assert(reported_length >= 0);
1127         if (available_length > reported_length)
1128           available_length = reported_length;
1129         if ((guint)available_length > length)
1130           available_length = length;
1131         if ((guint)reported_length > length)
1132           reported_length = length;
1133         new_tvb = tvb_new_subset(tvb, a->offset, available_length, reported_length);
1134         call_dissector(gssapi_handle, new_tvb, pinfo, tree);
1135         a->offset += length;
1136       } else if (mechanism != NULL && strcmp(mechanism, "GSSAPI") == 0) {
1137         /*
1138          * This is a raw GSS-API token.
1139          * Find out how big it is by parsing the ASN.1 header for the
1140          * OCTET STREAM that contains it.
1141          */
1142         token_offset = a->offset;
1143         ret = asn1_header_decode(a, &cls, &con, &tag, &def, &length);
1144         if (ret != ASN1_ERR_NOERROR) {
1145           proto_tree_add_text(tree, a->tvb, token_offset, 0,
1146             "%s: ERROR: Couldn't parse header: %s",
1147             proto_registrar_get_name(hf_ldap_message_bind_auth_credentials),
1148             asn1_err_to_str(ret));
1149           return;
1150         }
1151         if(length==0){
1152           /* for GSSAPI the third pdu will sometimes be "empty" */
1153           return;
1154         }
1155         available_length = tvb_length_remaining(tvb, token_offset);
1156         reported_length = tvb_reported_length_remaining(tvb, token_offset);
1157         g_assert(available_length >= 0);
1158         g_assert(reported_length >= 0);
1159         if (available_length > reported_length)
1160           available_length = reported_length;
1161         if ((guint)available_length > length)
1162           available_length = length;
1163         if ((guint)reported_length > length)
1164           reported_length = length;
1165         new_tvb = tvb_new_subset(tvb, a->offset, available_length, reported_length);
1166         call_dissector(gssapi_handle, new_tvb, pinfo, tree);
1167         a->offset += length;
1168       } else {
1169         if (read_bytestring(a, tree, hf_ldap_message_bind_auth_credentials,
1170                             NULL, NULL, ASN1_UNI, ASN1_OTS) != ASN1_ERR_NOERROR)
1171           return;
1172       }
1173     }
1174     break;
1175   }
1176 }
1177
1178 static void dissect_ldap_response_bind(ASN1_SCK *a, proto_tree *tree,
1179                 int start, guint length, tvbuff_t *tvb, packet_info *pinfo, ldap_conv_info_t *ldap_info)
1180 {
1181   guint cls, con, tag;
1182   gboolean def;
1183   guint cred_length;
1184   int end;
1185   int ret;
1186   int token_offset;
1187   gint available_length, reported_length;
1188   tvbuff_t *new_tvb;
1189
1190   end = start + length;
1191   dissect_ldap_result(a, tree, pinfo);
1192   if (a->offset < end) {
1193     switch (ldap_info->auth_type) {
1194
1195       /* For Kerberos V4, dissect it as a ticket. */
1196       /* XXX - what about LDAP_AUTH_SIMPLE? */
1197
1198     case LDAP_AUTH_SASL:
1199       /*
1200        * All frames after this are assumed to use a security layer.
1201        *
1202        * XXX - won't work if there's another reply, with the security
1203        * layer, starting in the same TCP segment that ends this
1204        * reply, but as LDAP is a request/response protocol, and
1205        * as the client probably can't start using authentication until
1206        * it gets the bind reply and the server won't send a reply until
1207        * it gets a request, that probably won't happen.
1208        *
1209        * XXX - that assumption is invalid; it's not clear where the
1210        * hell you find out whether there's any security layer.  In
1211        * one capture, we have two GSS-SPNEGO negotiations, both of
1212        * which select MS KRB5, and the only differences in the tokens
1213        * is in the RC4-HMAC ciphertext.  The various
1214        * draft-ietf--cat-sasl-gssapi-NN.txt drafts seem to imply
1215        * that the RFC 2222 spoo with the bitmask and maximum
1216        * output message size stuff is done - but where does that
1217        * stuff show up?  Is it in the ciphertext, which means it's
1218        * presumably encrypted?
1219        *
1220        * Grrr.  We have to do a gross heuristic, checking whether the
1221        * putative LDAP message begins with 0x00 or not, making the
1222        * assumption that we won't have more than 2^24 bytes of
1223        * encapsulated stuff.
1224        */
1225       ldap_info->first_auth_frame = pinfo->fd->num + 1;
1226       if (ldap_info->auth_mech != NULL &&
1227           strcmp(ldap_info->auth_mech, "GSS-SPNEGO") == 0) {
1228         /*
1229          * This is a GSS-API token.
1230          * Find out how big it is by parsing the ASN.1 header for the
1231          * OCTET STREAM that contains it.
1232          */
1233         token_offset = a->offset;
1234         ret = asn1_header_decode(a, &cls, &con, &tag, &def, &cred_length);
1235         if (ret != ASN1_ERR_NOERROR) {
1236           proto_tree_add_text(tree, a->tvb, token_offset, 0,
1237             "%s: ERROR: Couldn't parse header: %s",
1238             proto_registrar_get_name(hf_ldap_message_bind_auth_credentials),
1239             asn1_err_to_str(ret));
1240           return;
1241         }
1242         available_length = tvb_length_remaining(tvb, token_offset);
1243         reported_length = tvb_reported_length_remaining(tvb, token_offset);
1244         g_assert(available_length >= 0);
1245         g_assert(reported_length >= 0);
1246         if (available_length > reported_length)
1247           available_length = reported_length;
1248         if ((guint)available_length > cred_length)
1249           available_length = cred_length;
1250         if ((guint)reported_length > cred_length)
1251           reported_length = cred_length;
1252         new_tvb = tvb_new_subset(tvb, a->offset, available_length, reported_length);
1253         call_dissector(gssapi_handle, new_tvb, pinfo, tree);
1254         a->offset += cred_length;
1255       } else if (ldap_info->auth_mech != NULL &&
1256           strcmp(ldap_info->auth_mech, "GSSAPI") == 0) {
1257         /*
1258          * This is a GSS-API token.
1259          * Find out how big it is by parsing the ASN.1 header for the
1260          * OCTET STREAM that contains it.
1261          */
1262         token_offset = a->offset;
1263         ret = asn1_header_decode(a, &cls, &con, &tag, &def, &cred_length);
1264         if (ret != ASN1_ERR_NOERROR) {
1265           proto_tree_add_text(tree, a->tvb, token_offset, 0,
1266             "%s: ERROR: Couldn't parse header: %s",
1267             proto_registrar_get_name(hf_ldap_message_bind_auth_credentials),
1268             asn1_err_to_str(ret));
1269           return;
1270         }
1271         available_length = tvb_length_remaining(tvb, token_offset);
1272         reported_length = tvb_reported_length_remaining(tvb, token_offset);
1273         g_assert(available_length >= 0);
1274         g_assert(reported_length >= 0);
1275         if (available_length > reported_length)
1276           available_length = reported_length;
1277         if ((guint)available_length > cred_length)
1278           available_length = cred_length;
1279         if ((guint)reported_length > cred_length)
1280           reported_length = cred_length;
1281         new_tvb = tvb_new_subset(tvb, a->offset, available_length, reported_length);
1282         call_dissector(gssapi_handle, new_tvb, pinfo, tree);
1283         a->offset += cred_length;
1284       } else {
1285         if (read_bytestring(a, tree, hf_ldap_message_bind_server_credentials,
1286                             NULL, NULL, ASN1_UNI, ASN1_OTS) != ASN1_ERR_NOERROR)
1287           return;
1288       }
1289       break;
1290
1291     default:
1292       if (read_bytestring(a, tree, hf_ldap_message_bind_server_credentials,
1293                           NULL, NULL, ASN1_CTX, 7) != ASN1_ERR_NOERROR)
1294         return;
1295       break;
1296     }
1297   }
1298 }
1299
1300 static void dissect_ldap_request_search(ASN1_SCK *a, proto_tree *tree, packet_info *pinfo)
1301 {
1302   guint seq_length;
1303   int end;
1304   int ret;
1305   char *s = NULL;
1306
1307   if (read_string(a, tree, hf_ldap_message_search_base, 0, &s, 0, ASN1_UNI, ASN1_OTS) != ASN1_ERR_NOERROR)
1308     return;
1309
1310   if (check_col(pinfo->cinfo, COL_INFO))
1311     col_append_fstr(pinfo->cinfo, COL_INFO, ", Base DN=%s", s != NULL ? s : "(null)");
1312   g_free(s);
1313
1314   if (read_integer(a, tree, hf_ldap_message_search_scope, 0, 0, ASN1_ENUM) != ASN1_ERR_NOERROR)
1315     return;
1316   if (read_integer(a, tree, hf_ldap_message_search_deref, 0, 0, ASN1_ENUM) != ASN1_ERR_NOERROR)
1317     return;
1318   if (read_integer(a, tree, hf_ldap_message_search_sizeLimit, 0, 0, ASN1_INT) != ASN1_ERR_NOERROR)
1319     return;
1320   if (read_integer(a, tree, hf_ldap_message_search_timeLimit, 0, 0, ASN1_INT) != ASN1_ERR_NOERROR)
1321     return;
1322   if (read_boolean(a, tree, hf_ldap_message_search_typesOnly, 0, 0) != ASN1_ERR_NOERROR)
1323     return;
1324   if (!read_filter(a, tree, hf_ldap_message_search_filter))
1325     return;
1326   ret = read_sequence(a, &seq_length);
1327   if (ret != ASN1_ERR_NOERROR) {
1328     if (tree) {
1329       proto_tree_add_text(tree, a->tvb, a->offset, 0,
1330           "ERROR: Couldn't parse LDAP attribute sequence header: %s",
1331           asn1_err_to_str(ret));
1332     }
1333     return;
1334   }
1335   end = a->offset + seq_length;
1336   while (a->offset < end) {
1337     if (read_string(a, tree, hf_ldap_message_attribute, 0, 0, 0, ASN1_UNI,
1338                     ASN1_OTS) != ASN1_ERR_NOERROR)
1339       return;
1340   }
1341 }
1342
1343 static int dissect_mscldap_string(tvbuff_t *tvb, int offset, char *str, int maxlen, gboolean prepend_dot)
1344 {
1345   guint8 len;
1346
1347   len=tvb_get_guint8(tvb, offset);
1348   offset+=1;
1349   *str=0;
1350
1351   while(len){
1352     /* add potential field separation dot */
1353     if(prepend_dot){
1354       if(!maxlen){
1355         *str=0;
1356         return offset;
1357       }
1358       maxlen--;
1359       *str++='.';
1360       *str=0;
1361     }
1362
1363     if(len==0xc0){
1364       int new_offset;
1365       /* ops its a mscldap compressed string */
1366
1367       new_offset=tvb_get_guint8(tvb, offset);
1368       if (new_offset == offset - 1)
1369         THROW(ReportedBoundsError);
1370       offset+=1;
1371
1372       dissect_mscldap_string(tvb, new_offset, str, maxlen, FALSE);
1373
1374       return offset;
1375     }
1376
1377     prepend_dot=TRUE;
1378
1379     if(maxlen<=len){
1380       if(maxlen>3){
1381         *str++='.';
1382         *str++='.';
1383         *str++='.';
1384       }
1385       *str=0;
1386       return offset; /* will mess up offset in caller, is unlikely */
1387     }
1388     tvb_memcpy(tvb, str, offset, len);
1389     str+=len;
1390     *str=0;
1391     maxlen-=len;
1392     offset+=len;
1393
1394
1395     len=tvb_get_guint8(tvb, offset);
1396     offset+=1;
1397   }
1398   *str=0;
1399   return offset;
1400 }
1401
1402
1403 /* These flag bits were found to be defined in the samba sources.
1404  * I hope they are correct (but have serious doubts about the CLOSEST
1405  * bit being used or being meaningful).
1406  */
1407 static const true_false_string tfs_ads_pdc = {
1408         "This is a PDC",
1409         "This is NOT a pdc"
1410 };
1411 static const true_false_string tfs_ads_gc = {
1412         "This is a GLOBAL CATALOGUE of forest",
1413         "This is NOT a global catalog of forest"
1414 };
1415 static const true_false_string tfs_ads_ldap = {
1416         "This is an LDAP server",
1417         "This is NOT an ldap server"
1418 };
1419 static const true_false_string tfs_ads_ds = {
1420         "This dc supports DS",
1421         "This dc does NOT support ds"
1422 };
1423 static const true_false_string tfs_ads_kdc = {
1424         "This is a KDC (kerberos)",
1425         "This is NOT a kdc (kerberos)"
1426 };
1427 static const true_false_string tfs_ads_timeserv = {
1428         "This dc is running TIME SERVICES (ntp)",
1429         "This dc is NOT running time services (ntp)"
1430 };
1431 static const true_false_string tfs_ads_closest = {
1432         "This is the CLOSEST dc (unreliable?)",
1433         "This is NOT the closest dc"
1434 };
1435 static const true_false_string tfs_ads_writable = {
1436         "This dc is WRITABLE",
1437         "This dc is NOT writable"
1438 };
1439 static const true_false_string tfs_ads_good_timeserv = {
1440         "This dc has a GOOD TIME SERVICE (i.e. hardware clock)",
1441         "This dc does NOT have a good time service (i.e. no hardware clock)"
1442 };
1443 static const true_false_string tfs_ads_ndnc = {
1444         "Domain is NON-DOMAIN NC serviced by ldap server",
1445         "Domain is NOT non-domain nc serviced by ldap server"
1446 };
1447 static int dissect_mscldap_netlogon_flags(proto_tree *parent_tree, tvbuff_t *tvb, int offset)
1448 {
1449   guint32 flags;
1450   proto_item *item;
1451   proto_tree *tree=NULL;
1452
1453   flags=tvb_get_letohl(tvb, offset);
1454   item=proto_tree_add_item(parent_tree, hf_mscldap_netlogon_flags, tvb, offset, 4, TRUE);
1455   if(parent_tree){
1456     tree = proto_item_add_subtree(item, ett_mscldap_netlogon_flags);
1457   }
1458
1459   proto_tree_add_boolean(tree, hf_mscldap_netlogon_flags_ndnc,
1460     tvb, offset, 4, flags);
1461   proto_tree_add_boolean(tree, hf_mscldap_netlogon_flags_good_timeserv,
1462     tvb, offset, 4, flags);
1463   proto_tree_add_boolean(tree, hf_mscldap_netlogon_flags_writable,
1464     tvb, offset, 4, flags);
1465   proto_tree_add_boolean(tree, hf_mscldap_netlogon_flags_closest,
1466     tvb, offset, 4, flags);
1467   proto_tree_add_boolean(tree, hf_mscldap_netlogon_flags_timeserv,
1468     tvb, offset, 4, flags);
1469   proto_tree_add_boolean(tree, hf_mscldap_netlogon_flags_kdc,
1470     tvb, offset, 4, flags);
1471   proto_tree_add_boolean(tree, hf_mscldap_netlogon_flags_ds,
1472     tvb, offset, 4, flags);
1473   proto_tree_add_boolean(tree, hf_mscldap_netlogon_flags_ldap,
1474     tvb, offset, 4, flags);
1475   proto_tree_add_boolean(tree, hf_mscldap_netlogon_flags_gc,
1476     tvb, offset, 4, flags);
1477   proto_tree_add_boolean(tree, hf_mscldap_netlogon_flags_pdc,
1478     tvb, offset, 4, flags);
1479
1480   offset += 4;
1481
1482   return offset;
1483 }
1484
1485 static void dissect_mscldap_response_netlogon(proto_tree *tree, tvbuff_t *tvb)
1486 {
1487   int old_offset, offset=0;
1488   char str[256];
1489
1490 /*qqq*/
1491
1492   /* Type */
1493   /*XXX someone that knows what the type means should add that knowledge here*/
1494   proto_tree_add_item(tree, hf_mscldap_netlogon_type, tvb, offset, 4, TRUE);
1495   offset += 4;
1496
1497   /* Flags */
1498   offset = dissect_mscldap_netlogon_flags(tree, tvb, offset);
1499
1500   /* Domain GUID */
1501   proto_tree_add_item(tree, hf_mscldap_domain_guid, tvb, offset, 16, TRUE);
1502   offset += 16;
1503
1504   /* Forest */
1505   old_offset=offset;
1506   offset=dissect_mscldap_string(tvb, offset, str, 255, FALSE);
1507   proto_tree_add_string(tree, hf_mscldap_forest, tvb, old_offset, offset-old_offset, str);
1508   
1509   /* Domain */
1510   old_offset=offset;
1511   offset=dissect_mscldap_string(tvb, offset, str, 255, FALSE);
1512   proto_tree_add_string(tree, hf_mscldap_domain, tvb, old_offset, offset-old_offset, str);
1513   
1514   /* Hostname */
1515   old_offset=offset;
1516   offset=dissect_mscldap_string(tvb, offset, str, 255, FALSE);
1517   proto_tree_add_string(tree, hf_mscldap_hostname, tvb, old_offset, offset-old_offset, str);
1518   
1519   /* NetBios Domain */
1520   old_offset=offset;
1521   offset=dissect_mscldap_string(tvb, offset, str, 255, FALSE);
1522   proto_tree_add_string(tree, hf_mscldap_nb_domain, tvb, old_offset, offset-old_offset, str);
1523   
1524   /* NetBios Hostname */
1525   old_offset=offset;
1526   offset=dissect_mscldap_string(tvb, offset, str, 255, FALSE);
1527   proto_tree_add_string(tree, hf_mscldap_nb_hostname, tvb, old_offset, offset-old_offset, str);
1528   
1529   /* User */
1530   old_offset=offset;
1531   offset=dissect_mscldap_string(tvb, offset, str, 255, FALSE);
1532   proto_tree_add_string(tree, hf_mscldap_username, tvb, old_offset, offset-old_offset, str);
1533   
1534   /* Site */
1535   old_offset=offset;
1536   offset=dissect_mscldap_string(tvb, offset, str, 255, FALSE);
1537   proto_tree_add_string(tree, hf_mscldap_sitename, tvb, old_offset, offset-old_offset, str);
1538   
1539   /* Client Site */
1540   old_offset=offset;
1541   offset=dissect_mscldap_string(tvb, offset, str, 255, FALSE);
1542   proto_tree_add_string(tree, hf_mscldap_clientsitename, tvb, old_offset, offset-old_offset, str);
1543   
1544   /* Version */
1545   proto_tree_add_item(tree, hf_mscldap_netlogon_version, tvb, offset, 4, TRUE);
1546   offset += 4;
1547
1548   /* LM Token */
1549   proto_tree_add_item(tree, hf_mscldap_netlogon_lm_token, tvb, offset, 2, TRUE);
1550   offset += 2;
1551
1552   /* NT Token */
1553   proto_tree_add_item(tree, hf_mscldap_netlogon_nt_token, tvb, offset, 2, TRUE);
1554   offset += 2;
1555
1556 }
1557
1558 static void dissect_mscldap_response(proto_tree *tree, tvbuff_t *tvb, guint32 rpc)
1559 {
1560   switch(rpc){
1561   case MSCLDAP_RPC_NETLOGON:
1562     dissect_mscldap_response_netlogon(tree, tvb);
1563     break;
1564   default:
1565     proto_tree_add_text(tree, tvb, 0, tvb_length(tvb),
1566       "ERROR: Unknown type of MS-CLDAP RPC call");
1567   }
1568 }
1569
1570
1571 static void dissect_ldap_response_search_entry(ASN1_SCK *a, proto_tree *tree,
1572                 gboolean is_mscldap)
1573 {
1574   guint seq_length;
1575   int end_of_sequence;
1576   int ret;
1577   char *str=NULL;
1578   guint32 len;
1579   guint32 mscldap_rpc;
1580
1581   if (read_string(a, tree, hf_ldap_message_dn, 0, 0, 0, ASN1_UNI, ASN1_OTS) != ASN1_ERR_NOERROR)
1582     return;
1583   ret = read_sequence(a, &seq_length);
1584   if (ret != ASN1_ERR_NOERROR) {
1585     if (tree) {
1586       proto_tree_add_text(tree, a->tvb, a->offset, 0,
1587           "ERROR: Couldn't parse search entry response sequence header: %s",
1588           asn1_err_to_str(ret));
1589     }
1590     return;
1591   }
1592
1593   end_of_sequence = a->offset + seq_length;
1594   while (a->offset < end_of_sequence)
1595   {
1596     proto_item *ti;
1597     proto_tree *attr_tree;
1598     guint set_length;
1599     int end_of_set;
1600
1601     ret = read_sequence(a, 0);
1602     if (ret != ASN1_ERR_NOERROR) {
1603       if (tree) {
1604         proto_tree_add_text(tree, a->tvb, a->offset, 0,
1605             "ERROR: Couldn't parse LDAP attribute sequence header: %s",
1606             asn1_err_to_str(ret));
1607       }
1608       return;
1609     }
1610     if (read_string(a, tree, hf_ldap_message_attribute, &ti, &str, &len, ASN1_UNI, ASN1_OTS) != ASN1_ERR_NOERROR)
1611       return;
1612
1613     mscldap_rpc=0;
1614     if(is_mscldap){
1615         if(str && !strncmp(str, "netlogon", 8)){
1616                 mscldap_rpc=MSCLDAP_RPC_NETLOGON;
1617         }
1618     }
1619     g_free(str);
1620     str=NULL;
1621
1622
1623     attr_tree = proto_item_add_subtree(ti, ett_ldap_attribute);
1624
1625     ret = read_set(a, &set_length);
1626     if (ret != ASN1_ERR_NOERROR) {
1627       if (tree) {
1628         proto_tree_add_text(attr_tree, a->tvb, a->offset, 0,
1629             "ERROR: Couldn't parse LDAP value set header: %s",
1630             asn1_err_to_str(ret));
1631       }
1632       return;
1633     }
1634     end_of_set = a->offset + set_length;
1635     while (a->offset < end_of_set) {
1636       if(!is_mscldap){
1637         if (read_string(a, attr_tree, hf_ldap_message_value, 0, 0, 0, ASN1_UNI,
1638                         ASN1_OTS) != ASN1_ERR_NOERROR){
1639           return;
1640         }
1641       } else {
1642         guint cls, con, tag;
1643         gboolean def;
1644         guint len;
1645         int start = a->offset;
1646         int ret;
1647         tvbuff_t *mscldap_tvb=NULL;
1648
1649         ret = asn1_header_decode(a, &cls, &con, &tag, &def, &len);
1650         if (ret == ASN1_ERR_NOERROR) {
1651           if (cls != ASN1_UNI || con != ASN1_PRI || tag != ASN1_OTS)
1652             ret = ASN1_ERR_WRONG_TYPE;
1653         }
1654         if (ret != ASN1_ERR_NOERROR) {
1655           if (tree) {
1656             proto_tree_add_text(tree, a->tvb, start, 0,
1657               "%s: ERROR: Couldn't parse header: %s",
1658             proto_registrar_get_name(hf_ldap_message_value), asn1_err_to_str(ret));
1659           }
1660           return;
1661         }
1662         mscldap_tvb=tvb_new_subset(a->tvb, a->offset, len, len);
1663         dissect_mscldap_response(attr_tree, mscldap_tvb, mscldap_rpc);
1664         a->offset+=len;
1665       }
1666
1667     }
1668   }
1669 }
1670
1671 static void dissect_ldap_response_search_ref(ASN1_SCK *a, proto_tree *tree)
1672 {
1673   read_string(a, tree, hf_ldap_message_search_reference, 0, 0, 0, ASN1_UNI, ASN1_OTS);
1674 }
1675
1676 static void dissect_ldap_request_add(ASN1_SCK *a, proto_tree *tree, packet_info *pinfo)
1677 {
1678   guint seq_length;
1679   int end_of_sequence;
1680   int ret;
1681   char *s = NULL;
1682
1683   if (read_string(a, tree, hf_ldap_message_dn, 0, &s, 0, ASN1_UNI, ASN1_OTS) != ASN1_ERR_NOERROR)
1684     return;
1685
1686   if (check_col(pinfo->cinfo, COL_INFO))
1687     col_append_fstr(pinfo->cinfo, COL_INFO, ", DN=%s", s != NULL ? s : "(null)");
1688   g_free(s);  
1689
1690   ret = read_sequence(a, &seq_length);
1691   if (ret != ASN1_ERR_NOERROR) {
1692     if (tree) {
1693       proto_tree_add_text(tree, a->tvb, a->offset, 0,
1694           "ERROR: Couldn't parse add request sequence header: %s",
1695           asn1_err_to_str(ret));
1696     }
1697     return;
1698   }
1699
1700   end_of_sequence = a->offset + seq_length;
1701   while (a->offset < end_of_sequence)
1702   {
1703     proto_item *ti;
1704     proto_tree *attr_tree;
1705     guint set_length;
1706     int end_of_set;
1707
1708     ret = read_sequence(a, 0);
1709     if (ret != ASN1_ERR_NOERROR) {
1710       if (tree) {
1711         proto_tree_add_text(tree, a->tvb, a->offset, 0,
1712             "ERROR: Couldn't parse LDAP attribute sequence header: %s",
1713             asn1_err_to_str(ret));
1714       }
1715       return;
1716     }
1717     if (read_string(a, tree, hf_ldap_message_attribute, &ti, 0, 0, ASN1_UNI,
1718                     ASN1_OTS) != ASN1_ERR_NOERROR)
1719       return;
1720     attr_tree = proto_item_add_subtree(ti, ett_ldap_attribute);
1721
1722     ret = read_set(a, &set_length);
1723     if (ret != ASN1_ERR_NOERROR) {
1724       if (tree) {
1725         proto_tree_add_text(attr_tree, a->tvb, a->offset, 0,
1726             "ERROR: Couldn't parse LDAP value set header: %s",
1727             asn1_err_to_str(ret));
1728       }
1729       return;
1730     }
1731     end_of_set = a->offset + set_length;
1732     while (a->offset < end_of_set) {
1733       if (read_string(a, attr_tree, hf_ldap_message_value, 0, 0, 0, ASN1_UNI, ASN1_OTS) != ASN1_ERR_NOERROR)
1734         return;
1735     }
1736   }
1737 }
1738
1739 static void dissect_ldap_request_delete(ASN1_SCK *a, proto_tree *tree,
1740                 int start, guint length)
1741 {
1742   read_string_value(a, tree, hf_ldap_message_dn, NULL, NULL, start, length);
1743 }
1744
1745 static void dissect_ldap_request_modifyrdn(ASN1_SCK *a, proto_tree *tree,
1746                 guint length)
1747 {
1748   int start = a->offset;
1749
1750   if (read_string(a, tree, hf_ldap_message_dn, 0, 0, 0, ASN1_UNI, ASN1_OTS) != ASN1_ERR_NOERROR)
1751     return;
1752   if (read_string(a, tree, hf_ldap_message_modrdn_name, 0, 0, 0, ASN1_UNI, ASN1_OTS) != ASN1_ERR_NOERROR)
1753     return;
1754   if (read_boolean(a, tree, hf_ldap_message_modrdn_delete, 0, 0) != ASN1_ERR_NOERROR)
1755     return;
1756
1757   if (a->offset < (int) (start + length)) {
1758     /* LDAP V3 Modify DN operation, with newSuperior */
1759     /*      "newSuperior     [0] LDAPDN OPTIONAL" (0x80) */
1760     if (read_string(a, tree, hf_ldap_message_modrdn_superior, 0, 0, 0, ASN1_CTX, 0) != ASN1_ERR_NOERROR)
1761       return;
1762   }
1763 }
1764
1765 static void dissect_ldap_request_compare(ASN1_SCK *a, proto_tree *tree)
1766 {
1767   int start;
1768   int length;
1769   char *string1 = NULL;
1770   char *string2 = NULL;
1771   char *s1, *s2;
1772   char *compare;
1773   int ret;
1774
1775   if (read_string(a, tree, hf_ldap_message_dn, 0, 0, 0, ASN1_UNI, ASN1_OTS) != ASN1_ERR_NOERROR)
1776     return;
1777   ret = read_sequence(a, 0);
1778   if (ret != ASN1_ERR_NOERROR) {
1779     if (tree) {
1780       proto_tree_add_text(tree, a->tvb, a->offset, 0,
1781           "ERROR: Couldn't parse compare request sequence header: %s",
1782           asn1_err_to_str(ret));
1783     }
1784     return;
1785   }
1786
1787   start = a->offset;
1788   ret = read_string(a, 0, -1, 0, &string1, 0, ASN1_UNI, ASN1_OTS);
1789   if (ret != ASN1_ERR_NOERROR) {
1790     if (tree) {
1791       proto_tree_add_text(tree, a->tvb, start, 0,
1792         "ERROR: Couldn't parse compare type: %s", asn1_err_to_str(ret));
1793     }
1794     return;
1795   }
1796   ret = read_string(a, 0, -1, 0, &string2, 0, ASN1_UNI, ASN1_OTS);
1797   if (ret != ASN1_ERR_NOERROR) {
1798     if (tree) {
1799       proto_tree_add_text(tree, a->tvb, start, 0,
1800         "ERROR: Couldn't parse compare value: %s", asn1_err_to_str(ret));
1801     }
1802     g_free(string1);
1803     return;
1804   }
1805
1806   s1 = (string1 == NULL) ? "(null)" : string1;
1807   s2 = (string2 == NULL) ? "(null)" : string2;
1808   length = 2 + strlen(s1) + strlen(s2);
1809   compare = g_malloc0(length);
1810   snprintf(compare, length, "%s=%s", s1, s2);
1811   proto_tree_add_string(tree, hf_ldap_message_compare, a->tvb, start,
1812       a->offset-start, compare);
1813
1814   g_free(string1);
1815   g_free(string2);
1816   g_free(compare);
1817
1818   return;
1819 }
1820
1821 static void dissect_ldap_request_modify(ASN1_SCK *a, proto_tree *tree)
1822 {
1823   guint seq_length;
1824   int end_of_sequence;
1825   int ret;
1826
1827   if (read_string(a, tree, hf_ldap_message_dn, 0, 0, 0, ASN1_UNI, ASN1_OTS) != ASN1_ERR_NOERROR)
1828     return;
1829   ret = read_sequence(a, &seq_length);
1830   if (ret != ASN1_ERR_NOERROR) {
1831     if (tree) {
1832       proto_tree_add_text(tree, a->tvb, a->offset, 0,
1833           "ERROR: Couldn't parse modify request sequence header: %s",
1834           asn1_err_to_str(ret));
1835     }
1836     return;
1837   }
1838   end_of_sequence = a->offset + seq_length;
1839   while (a->offset < end_of_sequence)
1840   {
1841     proto_item *ti;
1842     proto_tree *attr_tree;
1843     guint set_length;
1844     int end_of_set;
1845     guint operation;
1846
1847     ret = read_sequence(a, 0);
1848     if (ret != ASN1_ERR_NOERROR) {
1849       if (tree) {
1850         proto_tree_add_text(tree, a->tvb, a->offset, 0,
1851             "ERROR: Couldn't parse modify request item sequence header: %s",
1852             asn1_err_to_str(ret));
1853       }
1854       return;
1855     }
1856     ret = read_integer(a, 0, -1, 0, &operation, ASN1_ENUM);
1857     if (ret != ASN1_ERR_NOERROR) {
1858       if (tree) {
1859         proto_tree_add_text(tree, a->tvb, a->offset, 0,
1860           "ERROR: Couldn't parse modify operation: %s",
1861           asn1_err_to_str(ret));
1862         return;
1863       }
1864     }
1865     ret = read_sequence(a, 0);
1866     if (ret != ASN1_ERR_NOERROR) {
1867       if (tree) {
1868         proto_tree_add_text(tree, a->tvb, a->offset, 0,
1869             "ERROR: Couldn't parse modify request operation sequence header: %s",
1870             asn1_err_to_str(ret));
1871       }
1872       return;
1873     }
1874
1875     switch (operation)
1876     {
1877      case LDAP_MOD_ADD:
1878       if (read_string(a, tree, hf_ldap_message_modify_add, &ti, 0, 0, ASN1_UNI,
1879                       ASN1_OTS) != ASN1_ERR_NOERROR)
1880         return;
1881       break;
1882
1883      case LDAP_MOD_REPLACE:
1884       if (read_string(a, tree, hf_ldap_message_modify_replace, &ti, 0, 0,
1885                       ASN1_UNI, ASN1_OTS) != ASN1_ERR_NOERROR)
1886         return;
1887       break;
1888
1889      case LDAP_MOD_DELETE:
1890       if (read_string(a, tree, hf_ldap_message_modify_delete, &ti, 0, 0,
1891                       ASN1_UNI, ASN1_OTS) != ASN1_ERR_NOERROR)
1892         return;
1893       break;
1894
1895      default:
1896        proto_tree_add_text(tree, a->tvb, a->offset, 0,
1897             "Unknown LDAP modify operation (%u)", operation);
1898        return;
1899     }
1900     attr_tree = proto_item_add_subtree(ti, ett_ldap_attribute);
1901
1902     ret = read_set(a, &set_length);
1903     if (ret != ASN1_ERR_NOERROR) {
1904       if (tree) {
1905         proto_tree_add_text(attr_tree, a->tvb, a->offset, 0,
1906             "ERROR: Couldn't parse LDAP value set header: %s",
1907             asn1_err_to_str(ret));
1908       }
1909       return;
1910     }
1911     end_of_set = a->offset + set_length;
1912     while (a->offset < end_of_set) {
1913       if (read_string(a, attr_tree, hf_ldap_message_value, 0, 0, 0, ASN1_UNI,
1914                       ASN1_OTS) != ASN1_ERR_NOERROR)
1915         return;
1916     }
1917   }
1918 }
1919
1920 static void dissect_ldap_request_abandon(ASN1_SCK *a, proto_tree *tree,
1921                 int start, guint length)
1922 {
1923   read_integer_value(a, tree, hf_ldap_message_abandon_msgid, NULL, NULL,
1924                             start, length);
1925 }
1926
1927 static void dissect_ldap_controls(ASN1_SCK *a, proto_tree *tree)
1928 {
1929   guint cls, con, tag;
1930   gboolean def;
1931   guint length;
1932   int ret;
1933   proto_item *ctrls_item = NULL;
1934   proto_tree *ctrls_tree = NULL;
1935   int start = a->offset;
1936   int end;
1937   guint ctrls_length;
1938
1939   ret = asn1_header_decode(a, &cls, &con, &tag, &def, &length);
1940   if (ret != ASN1_ERR_NOERROR) {
1941     proto_tree_add_text(tree, a->tvb, a->offset, 0,
1942                         "ERROR: Couldn't parse LDAP Controls: %s",
1943                         asn1_err_to_str(ret));
1944     return;
1945   }
1946   if (cls != ASN1_CTX || con != ASN1_CON || tag != ASN1_EOC) {
1947     proto_tree_add_text(tree, a->tvb, a->offset, 0,
1948                         "ERROR: Couldn't parse LDAP Controls: %s",
1949                         asn1_err_to_str(ASN1_ERR_WRONG_TYPE));
1950     return;
1951   }
1952
1953   ctrls_length = (a->offset - start) + length;
1954   ctrls_item = proto_tree_add_text(tree, a->tvb, start, ctrls_length, "LDAP Controls");
1955   ctrls_tree = proto_item_add_subtree(ctrls_item, ett_ldap_controls);
1956
1957   end = a->offset + length;
1958   while (a->offset < end) {
1959     proto_item *ctrl_item = NULL;
1960     proto_tree *ctrl_tree = NULL;
1961     guint seq_length;
1962     int seq_start = a->offset;
1963     int seq_end;
1964     guint ctrl_length;
1965
1966     ret = read_sequence(a, &seq_length);
1967     if (ret != ASN1_ERR_NOERROR) {
1968       proto_tree_add_text(ctrls_tree, a->tvb, a->offset, 0,
1969                           "ERROR: Couldn't parse LDAP Control: %s",
1970                           asn1_err_to_str(ret));
1971       return;
1972     }
1973
1974     ctrl_length = (a->offset - seq_start) + seq_length;
1975     ctrl_item = proto_tree_add_text(ctrls_tree, a->tvb, seq_start, ctrl_length, "LDAP Control");
1976     ctrl_tree = proto_item_add_subtree(ctrl_item, ett_ldap_control);
1977
1978     seq_end = a->offset + seq_length;
1979
1980     ret = read_string(a, ctrl_tree, hf_ldap_message_controls_oid, 0, 0, 0, ASN1_UNI, ASN1_OTS);
1981     if (ret != ASN1_ERR_NOERROR) {
1982       return;
1983     }
1984
1985     if (a->offset >= seq_end) {
1986       /* skip optional data */
1987       break;
1988     }
1989
1990     ret = check_optional_tag(a, ASN1_UNI, ASN1_PRI, ASN1_BOL);
1991     if (ret == ASN1_ERR_NOERROR) {
1992       ret = read_boolean(a, ctrl_tree, hf_ldap_message_controls_critical, 0, 0);
1993       if (ret != ASN1_ERR_NOERROR) {
1994         return;
1995       }
1996     }
1997
1998     if (a->offset >= seq_end) {
1999       /* skip optional data */
2000       break;
2001     }
2002
2003     ret = check_optional_tag(a, ASN1_UNI, ASN1_PRI, ASN1_OTS);
2004     if (ret == ASN1_ERR_NOERROR) {
2005       ret = read_bytestring(a, ctrl_tree, hf_ldap_message_controls_value, NULL, NULL, ASN1_UNI, ASN1_OTS);
2006       if (ret != ASN1_ERR_NOERROR) {
2007         return;
2008       }
2009     }
2010   }
2011 }
2012
2013 static ldap_call_response_t *
2014 ldap_match_call_response(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, ldap_conv_info_t *ldap_info, guint messageId, guint protocolOpTag)
2015 {
2016   ldap_call_response_t lcr, *lcrp=NULL;
2017
2018   if (!pinfo->fd->flags.visited) {
2019     switch(protocolOpTag){
2020       case LDAP_REQ_BIND:
2021       case LDAP_REQ_SEARCH:
2022       case LDAP_REQ_MODIFY:
2023       case LDAP_REQ_ADD:
2024       case LDAP_REQ_DELETE:
2025       case LDAP_REQ_MODRDN:
2026       case LDAP_REQ_COMPARE:
2027       /*case LDAP_REQ_ABANDON: we dont match for this one*/
2028       /*case LDAP_REQ_UNBIND: we dont match for this one*/
2029         /* check that we dont already have one of those in the
2030            unmatched list and if so remove it */
2031         lcr.messageId=messageId;
2032         lcrp=g_hash_table_lookup(ldap_info->unmatched, &lcr);
2033         if(lcrp){
2034           g_hash_table_remove(ldap_info->unmatched, lcrp);
2035         }
2036         /* if we cant reuse the old one, grab a new chunk */
2037         if(!lcrp){
2038           lcrp=g_mem_chunk_alloc(ldap_call_response_chunk);
2039         }
2040         lcrp->messageId=messageId;
2041         lcrp->req_frame=pinfo->fd->num;
2042         lcrp->req_time.secs=pinfo->fd->abs_secs;
2043         lcrp->req_time.nsecs=pinfo->fd->abs_usecs*1000;
2044         lcrp->rep_frame=0;
2045         lcrp->protocolOpTag=protocolOpTag;
2046         lcrp->is_request=TRUE;
2047         g_hash_table_insert(ldap_info->unmatched, lcrp, lcrp);
2048         return NULL;
2049         break;
2050       case LDAP_RES_BIND:
2051       case LDAP_RES_SEARCH_ENTRY:
2052       case LDAP_RES_SEARCH_REF:
2053       case LDAP_RES_SEARCH_RESULT:
2054       case LDAP_RES_MODIFY:
2055       case LDAP_RES_ADD:
2056       case LDAP_RES_DELETE:
2057       case LDAP_RES_MODRDN:
2058       case LDAP_RES_COMPARE:
2059         lcr.messageId=messageId;
2060         lcrp=g_hash_table_lookup(ldap_info->unmatched, &lcr);
2061         if(lcrp){
2062           if(!lcrp->rep_frame){
2063             g_hash_table_remove(ldap_info->unmatched, lcrp);
2064             lcrp->rep_frame=pinfo->fd->num;
2065             lcrp->is_request=FALSE;
2066             g_hash_table_insert(ldap_info->matched, lcrp, lcrp);
2067           }
2068         }
2069     }
2070   }
2071
2072   if(!lcrp){
2073     lcr.messageId=messageId;
2074     switch(protocolOpTag){
2075       case LDAP_REQ_BIND:
2076       case LDAP_REQ_SEARCH:
2077       case LDAP_REQ_MODIFY:
2078       case LDAP_REQ_ADD:
2079       case LDAP_REQ_DELETE:
2080       case LDAP_REQ_MODRDN:
2081       case LDAP_REQ_COMPARE:
2082       /*case LDAP_REQ_ABANDON: we dont match for this one*/
2083       /*case LDAP_REQ_UNBIND: we dont match for this one*/
2084         lcr.is_request=TRUE;
2085         lcr.req_frame=pinfo->fd->num;
2086         lcr.rep_frame=0;
2087         break;
2088       case LDAP_RES_BIND:
2089       case LDAP_RES_SEARCH_ENTRY:
2090       case LDAP_RES_SEARCH_REF:
2091       case LDAP_RES_SEARCH_RESULT:
2092       case LDAP_RES_MODIFY:
2093       case LDAP_RES_ADD:
2094       case LDAP_RES_DELETE:
2095       case LDAP_RES_MODRDN:
2096       case LDAP_RES_COMPARE:
2097         lcr.is_request=FALSE;
2098         lcr.req_frame=0;
2099         lcr.rep_frame=pinfo->fd->num;
2100         break;
2101     }
2102     lcrp=g_hash_table_lookup(ldap_info->matched, &lcr);
2103     if(lcrp){
2104       lcrp->is_request=lcr.is_request;
2105     }
2106   }
2107   if(lcrp){
2108     if(lcrp->is_request){
2109       proto_tree_add_uint(tree, hf_ldap_response_in, tvb, 0, 0, lcrp->rep_frame);
2110     } else {
2111       nstime_t ns;
2112       proto_tree_add_uint(tree, hf_ldap_response_to, tvb, 0, 0, lcrp->req_frame);
2113       ns.secs=pinfo->fd->abs_secs-lcrp->req_time.secs;
2114       ns.nsecs=pinfo->fd->abs_usecs*1000-lcrp->req_time.nsecs;
2115       if(ns.nsecs<0){
2116         ns.nsecs+=1000000000;
2117         ns.secs--;
2118       }
2119       proto_tree_add_time(tree, hf_ldap_time, tvb, 0, 0, &ns);
2120     }
2121     return lcrp;
2122   }
2123   return NULL;
2124 }
2125
2126
2127 static void
2128 dissect_ldap_message(tvbuff_t *tvb, int offset, packet_info *pinfo,
2129                 proto_tree *ldap_tree, proto_item *ldap_item, 
2130                 gboolean first_time, ldap_conv_info_t *ldap_info,
2131                 gboolean is_mscldap)
2132 {
2133   int message_id_start;
2134   int message_id_length;
2135   guint messageLength;
2136   guint messageId;
2137   int next_offset;
2138   guint protocolOpCls, protocolOpCon, protocolOpTag;
2139   gchar *typestr;
2140   guint opLen;
2141   ASN1_SCK a;
2142   int start;
2143   int ret;
2144   ldap_call_response_t *lcrp;
2145
2146   asn1_open(&a, tvb, offset);
2147
2148   ret = read_sequence(&a, &messageLength);
2149   if (ret != ASN1_ERR_NOERROR)
2150   {
2151     if (first_time)
2152     {
2153       if (check_col(pinfo->cinfo, COL_INFO))
2154       {
2155         col_add_fstr(pinfo->cinfo, COL_INFO,
2156                     "Invalid LDAP message (Can't parse sequence header: %s)",
2157                     asn1_err_to_str(ret));
2158       }
2159     }
2160     if (ldap_tree)
2161     {
2162       proto_tree_add_text(ldap_tree, tvb, offset, -1,
2163                           "Invalid LDAP message (Can't parse sequence header: %s)",
2164                           asn1_err_to_str(ret));
2165     }
2166     return;
2167   }
2168
2169   message_id_start = a.offset;
2170   ret = read_integer(&a, 0, hf_ldap_message_id, 0, &messageId, ASN1_INT);
2171   if (ret != ASN1_ERR_NOERROR)
2172   {
2173     if (first_time && check_col(pinfo->cinfo, COL_INFO))
2174       col_add_fstr(pinfo->cinfo, COL_INFO, "Invalid LDAP packet (Can't parse Message ID: %s)",
2175                    asn1_err_to_str(ret));
2176     if (ldap_tree)
2177       proto_tree_add_text(ldap_tree, tvb, message_id_start, 1,
2178                           "Invalid LDAP packet (Can't parse Message ID: %s)",
2179                           asn1_err_to_str(ret));
2180       return;
2181   }
2182   message_id_length = a.offset - message_id_start;
2183
2184   start = a.offset;
2185   asn1_id_decode(&a, &protocolOpCls, &protocolOpCon, &protocolOpTag);
2186   if (protocolOpCls != ASN1_APL)
2187     typestr = "Bad message type (not Application)";
2188   else
2189     typestr = val_to_str(protocolOpTag, msgTypes, "Unknown message type (%u)");
2190
2191   if (first_time)
2192   {
2193     if (check_col(pinfo->cinfo, COL_INFO))
2194       col_add_fstr(pinfo->cinfo, COL_INFO, "MsgId=%u %s",
2195                    messageId, typestr);
2196   }
2197
2198   if (ldap_item)
2199           proto_item_append_text(ldap_item, ", %s", 
2200                                  val_to_str(protocolOpTag, msgTypes,
2201                                             "Unknown message type (%u)"));
2202
2203   if (ldap_tree)
2204   {
2205     proto_tree_add_uint(ldap_tree, hf_ldap_message_id, tvb, message_id_start, message_id_length, messageId);
2206     if (protocolOpCls == ASN1_APL)
2207     {
2208       proto_tree_add_uint(ldap_tree, hf_ldap_message_type, tvb,
2209                           start, a.offset - start, protocolOpTag);
2210     }
2211     else
2212     {
2213       proto_tree_add_text(ldap_tree, tvb, start, a.offset - start,
2214                           "%s", typestr);
2215     }
2216   }
2217   start = a.offset;
2218   if (read_length(&a, ldap_tree, hf_ldap_message_length, &opLen) != ASN1_ERR_NOERROR)
2219     return;
2220
2221   if (protocolOpCls == ASN1_APL)
2222   {
2223     lcrp=ldap_match_call_response(tvb, pinfo, ldap_tree, ldap_info, messageId, protocolOpTag);
2224     if(lcrp){
2225       tap_queue_packet(ldap_tap, pinfo, lcrp);
2226     }
2227
2228     /*
2229      * XXX - we should check for errors from these routines (and they
2230      * should return errors), and not try to dissect the LDAP controls
2231      * if they get an error.
2232      */
2233     switch (protocolOpTag)
2234     {
2235      case LDAP_REQ_BIND:
2236       dissect_ldap_request_bind(&a, ldap_tree, tvb, pinfo, ldap_info);
2237       break;
2238      case LDAP_REQ_UNBIND:
2239       /* Nothing to dissect */
2240       break;
2241      case LDAP_REQ_SEARCH:
2242       dissect_ldap_request_search(&a, ldap_tree, pinfo);
2243       break;
2244      case LDAP_REQ_MODIFY:
2245       dissect_ldap_request_modify(&a, ldap_tree);
2246       break;
2247      case LDAP_REQ_ADD:
2248       dissect_ldap_request_add(&a, ldap_tree, pinfo);
2249       break;
2250      case LDAP_REQ_DELETE:
2251       dissect_ldap_request_delete(&a, ldap_tree, start, opLen);
2252       break;
2253      case LDAP_REQ_MODRDN:
2254       dissect_ldap_request_modifyrdn(&a, ldap_tree, opLen);
2255       break;
2256      case LDAP_REQ_COMPARE:
2257       dissect_ldap_request_compare(&a, ldap_tree);
2258       break;
2259      case LDAP_REQ_ABANDON:
2260       dissect_ldap_request_abandon(&a, ldap_tree, start, opLen);
2261       break;
2262      case LDAP_RES_BIND:
2263       dissect_ldap_response_bind(&a, ldap_tree, start, opLen, tvb, pinfo, ldap_info);
2264       break;
2265      case LDAP_RES_SEARCH_ENTRY: {
2266             /*
2267              * XXX - this assumes that the LDAP_RES_SEARCH_ENTRY and
2268              * LDAP_RES_SEARCH_RESULT appear in the same frame.
2269              */
2270             guint32 *num_results = p_get_proto_data(pinfo->fd, proto_ldap);
2271
2272             if (!num_results) {
2273                     num_results = g_malloc(sizeof(guint32));
2274                     *num_results = 0;
2275                     p_add_proto_data(pinfo->fd, proto_ldap, num_results);
2276             }
2277
2278             *num_results += 1;
2279             dissect_ldap_response_search_entry(&a, ldap_tree, is_mscldap);
2280
2281             break;
2282      }
2283      case LDAP_RES_SEARCH_REF:
2284       dissect_ldap_response_search_ref(&a, ldap_tree);
2285       break;
2286
2287      case LDAP_RES_SEARCH_RESULT: {
2288              guint32 *num_results = p_get_proto_data(pinfo->fd, proto_ldap);
2289
2290              if (num_results) {
2291                      if (check_col(pinfo->cinfo, COL_INFO))
2292                              col_append_fstr(pinfo->cinfo, COL_INFO, ", %d result%s", 
2293                                              *num_results, *num_results == 1 ? "" : "s");
2294                      g_free(num_results);
2295                      p_rem_proto_data(pinfo->fd, proto_ldap);
2296              }
2297
2298              dissect_ldap_result(&a, ldap_tree, pinfo);
2299
2300              break;
2301      }
2302
2303      case LDAP_RES_MODIFY:
2304      case LDAP_RES_ADD:
2305      case LDAP_RES_DELETE:
2306      case LDAP_RES_MODRDN:
2307      case LDAP_RES_COMPARE:
2308         dissect_ldap_result(&a, ldap_tree, pinfo);
2309       break;
2310      default:
2311       if (ldap_tree)
2312       {
2313         proto_tree_add_text(ldap_tree, a.tvb, a.offset, opLen,
2314                             "Unknown LDAP operation (%u)", protocolOpTag);
2315       }
2316       break;
2317     }
2318   }
2319
2320   if ((int)messageLength > 0 && (message_id_start + (int)messageLength) > a.offset) {
2321     dissect_ldap_controls(&a, ldap_tree);
2322   }
2323
2324   /*
2325    * XXX - what if "next_offset" is past the offset of the next top-level
2326    * sequence?  Show that as an error?
2327    */
2328   asn1_close(&a, &next_offset); /* XXX - use the new value of next_offset? */
2329 }
2330
2331 static void
2332 dissect_ldap_payload(tvbuff_t *tvb, packet_info *pinfo,
2333                      proto_tree *tree, ldap_conv_info_t *ldap_info,
2334                      gboolean rest_is_pad, gboolean is_mscldap)
2335 {
2336   int offset = 0;
2337   gboolean first_time = TRUE;
2338   guint length_remaining;
2339   ASN1_SCK a;
2340   int ret;
2341   guint msg_len;
2342   int messageOffset;
2343   guint headerLength;
2344   guint length;
2345   tvbuff_t *msg_tvb = NULL;
2346   proto_item *msg_item = NULL;
2347   proto_tree *msg_tree = NULL;
2348
2349   while (tvb_reported_length_remaining(tvb, offset) > 0) {
2350     /*
2351      * This will throw an exception if we don't have any data left.
2352      * That's what we want.  (See "tcp_dissect_pdus()", which is
2353      * similar)
2354      */
2355     length_remaining = tvb_ensure_length_remaining(tvb, offset);
2356
2357     if (rest_is_pad && length_remaining < 6) return;
2358
2359     /*
2360      * The frame begins
2361      * with a "Sequence Of" header.
2362      * Can we do reassembly?
2363      */
2364     if (ldap_desegment && pinfo->can_desegment) {
2365         /*
2366          * Yes - is the "Sequence Of" header split across segment
2367          * boundaries?  We require at least 6 bytes for the header
2368          * which allows for a 4 byte length (ASN.1 BER).
2369          */
2370         if (length_remaining < 6) {
2371           /* stop if the caller says that we are given all data and the rest is padding
2372            * this is for the SASL GSSAPI case when the data is only signed and not sealed
2373            */
2374           pinfo->desegment_offset = offset;
2375           pinfo->desegment_len = 6 - length_remaining;
2376           return;
2377         }
2378     }
2379
2380     /*
2381      * OK, try to read the "Sequence Of" header; this gets the total
2382      * length of the LDAP message.
2383      */
2384     asn1_open(&a, tvb, offset);
2385     ret = read_sequence(&a, &msg_len);
2386     asn1_close(&a, &messageOffset);
2387
2388     if (ret == ASN1_ERR_NOERROR) {
2389         /*
2390          * Add the length of the "Sequence Of" header to the message
2391          * length.
2392          */
2393         headerLength = messageOffset - offset;
2394         msg_len += headerLength;
2395         if (msg_len < headerLength) {
2396             /*
2397              * The message length was probably so large that the total length
2398              * overflowed.
2399              *
2400              * Report this as an error.
2401              */
2402             show_reported_bounds_error(tvb, pinfo, tree);
2403             return;
2404         }
2405     } else {
2406         /*
2407          * We couldn't parse the header; just make it the amount of data
2408          * remaining in the tvbuff, so we'll give up on this segment
2409          * after attempting to parse the message - there's nothing more
2410          * we can do.  "dissect_ldap_message()" will display the error.
2411          */
2412         msg_len = length_remaining;
2413     }
2414
2415     /*
2416      * Is the message split across segment boundaries?
2417      */
2418     if (length_remaining < msg_len) {
2419         /* provide a hint to TCP where the next PDU starts */
2420         pinfo->want_pdu_tracking=2;
2421         pinfo->bytes_until_next_pdu= msg_len - length_remaining;
2422         /*
2423          * Can we do reassembly?
2424          */
2425         if (ldap_desegment && pinfo->can_desegment) {
2426             /*
2427              * Yes.  Tell the TCP dissector where the data for this message
2428              * starts in the data it handed us, and how many more bytes
2429              * we need, and return.
2430              */
2431             pinfo->desegment_offset = offset;
2432             pinfo->desegment_len = msg_len - length_remaining;
2433             return;
2434         }
2435     }
2436
2437     /*
2438      * Construct a tvbuff containing the amount of the payload we have
2439      * available.  Make its reported length the amount of data in the
2440      * LDAP message.
2441      *
2442      * XXX - if reassembly isn't enabled. the subdissector will throw a
2443      * BoundsError exception, rather than a ReportedBoundsError exception.
2444      * We really want a tvbuff where the length is "length", the reported
2445      * length is "plen", and the "if the snapshot length were infinite"
2446      * length is the minimum of the reported length of the tvbuff handed
2447      * to us and "plen", with a new type of exception thrown if the offset
2448      * is within the reported length but beyond that third length, with
2449      * that exception getting the "Unreassembled Packet" error.
2450      */
2451     length = length_remaining;
2452     if (length > msg_len) length = msg_len;
2453     msg_tvb = tvb_new_subset(tvb, offset, length, msg_len);
2454
2455     /*
2456      * Now dissect the LDAP message.
2457      */
2458     if (tree) {
2459         msg_item = proto_tree_add_text(tree, msg_tvb, 0, msg_len, "LDAP Message");
2460         msg_tree = proto_item_add_subtree(msg_item, ett_ldap_msg);
2461     }
2462
2463     dissect_ldap_message(msg_tvb, 0, pinfo, msg_tree, msg_item, first_time, ldap_info, is_mscldap);
2464
2465     offset += msg_len;
2466
2467     first_time = FALSE;
2468   }
2469 }
2470
2471
2472 static void
2473 dissect_ldap_pdu(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, gboolean is_mscldap)
2474 {
2475   int offset = 0;
2476   conversation_t *conversation;
2477   gboolean doing_sasl_security = FALSE;
2478   guint length_remaining;
2479   ldap_conv_info_t *ldap_info = NULL;
2480   proto_item *ldap_item = NULL;
2481   proto_tree *ldap_tree = NULL;
2482
2483   /*
2484    * Do we have a conversation for this connection?
2485    */
2486   conversation = find_conversation(pinfo->fd->num, &pinfo->src, &pinfo->dst,
2487                                    pinfo->ptype, pinfo->srcport,
2488                                    pinfo->destport, 0);
2489   if (conversation == NULL) {
2490     /* We don't yet have a conversation, so create one. */
2491     conversation = conversation_new(pinfo->fd->num, &pinfo->src, &pinfo->dst,
2492                                     pinfo->ptype, pinfo->srcport,
2493                                     pinfo->destport, 0);
2494   }
2495
2496   /*
2497    * Do we already have a type and mechanism?
2498    */
2499   ldap_info = conversation_get_proto_data(conversation, proto_ldap);
2500   if (ldap_info == NULL) {
2501     /* No.  Attach that information to the conversation, and add
2502      * it to the list of information structures.
2503      */
2504     ldap_info = g_mem_chunk_alloc(ldap_conv_info_chunk);
2505     ldap_info->auth_type = 0;
2506     ldap_info->auth_mech = 0;
2507     ldap_info->first_auth_frame = 0;
2508     ldap_info->matched=g_hash_table_new(ldap_info_hash_matched, ldap_info_equal_matched);
2509     ldap_info->unmatched=g_hash_table_new(ldap_info_hash_unmatched, ldap_info_equal_unmatched);
2510     conversation_add_proto_data(conversation, proto_ldap, ldap_info);
2511     ldap_info->next = ldap_info_items;
2512     ldap_info_items = ldap_info;
2513   } 
2514
2515   switch (ldap_info->auth_type) {
2516     case LDAP_AUTH_SASL:
2517     /*
2518      * It's SASL; are we using a security layer?
2519      */
2520     if (ldap_info->first_auth_frame != 0 &&
2521        pinfo->fd->num >= ldap_info->first_auth_frame) {
2522         doing_sasl_security = TRUE;     /* yes */
2523     }
2524   }
2525
2526   while (tvb_reported_length_remaining(tvb, offset) > 0) {
2527
2528     /*
2529      * This will throw an exception if we don't have any data left.
2530      * That's what we want.  (See "tcp_dissect_pdus()", which is
2531      * similar, but doesn't have to deal with the SASL issues.
2532      * XXX - can we make "tcp_dissect_pdus()" provide enough information
2533      * to the "get_pdu_len" routine so that we could have one dealing
2534      * with the SASL issues, have that routine deal with SASL and
2535      * ASN.1, and just use "tcp_dissect_pdus()"?)
2536      */
2537     length_remaining = tvb_ensure_length_remaining(tvb, offset);
2538
2539     /*
2540      * Try to find out if we have a plain LDAP buffer
2541      * with a "Sequence Of" header or a SASL buffer with
2542      * Can we do reassembly?
2543      */
2544     if (ldap_desegment && pinfo->can_desegment) {
2545         /*
2546          * Yes - is the "Sequence Of" header split across segment
2547          * boundaries?  We require at least 6 bytes for the header
2548          * which allows for a 4 byte length (ASN.1 BER).
2549          * For the SASL case we need at least 4 bytes, so this is 
2550          * no problem here because we check for 6 bytes ans sasl buffers
2551          * with less than 2 bytes should not exist...
2552          */
2553         if (length_remaining < 6) {
2554             pinfo->desegment_offset = offset;
2555             pinfo->desegment_len = 6 - length_remaining;
2556             return;
2557         }
2558     }
2559
2560     /* It might still be a packet containing a SASL security layer
2561      * but its just that we never saw the BIND packet.
2562      * check if it looks like it could be a SASL blob here
2563      * and in that case just assume it is GSS-SPNEGO
2564      */
2565     if(!doing_sasl_security && (tvb_bytes_exist(tvb, offset, 5))
2566       &&(tvb_get_ntohl(tvb, offset)<=(guint)(tvb_reported_length_remaining(tvb, offset)-4))
2567       &&(tvb_get_guint8(tvb, offset+4)==0x60) ){
2568         ldap_info->auth_type=LDAP_AUTH_SASL;
2569         ldap_info->first_auth_frame=pinfo->fd->num;
2570         ldap_info->auth_mech=g_strdup("GSS-SPNEGO");
2571         doing_sasl_security=TRUE;
2572     }
2573
2574     /*
2575      * This is the first PDU, set the Protocol column and clear the
2576      * Info column.
2577      */
2578     if (check_col(pinfo->cinfo, COL_PROTOCOL)) col_set_str(pinfo->cinfo, COL_PROTOCOL, pinfo->current_proto);
2579     if (check_col(pinfo->cinfo, COL_INFO)) col_clear(pinfo->cinfo, COL_INFO);
2580
2581     ldap_item = proto_tree_add_item(tree, proto_ldap, tvb, 0, -1, FALSE);
2582     ldap_tree = proto_item_add_subtree(ldap_item, ett_ldap);
2583
2584     /*
2585      * Might we be doing a SASL security layer and, if so, *are* we doing
2586      * one?
2587      *
2588      * Just because we've seen a bind reply for SASL, that doesn't mean
2589      * that we're using a SASL security layer; I've seen captures in
2590      * which some SASL negotiations lead to a security layer being used
2591      * and other negotiations don't, and it's not obvious what's different
2592      * in the two negotiations.  Therefore, we assume that if the first
2593      * byte is 0, it's a length for a SASL security layer (that way, we
2594      * never reassemble more than 16 megabytes, protecting us from
2595      * chewing up *too* much memory), and otherwise that it's an LDAP
2596      * message (actually, if it's an LDAP message it should begin with 0x30,
2597      * but we want to parse garbage as LDAP messages rather than really
2598      * huge lengths).
2599      */
2600
2601     if (doing_sasl_security && tvb_get_guint8(tvb, offset) == 0) {
2602       proto_item *sasl_item = NULL;
2603       proto_tree *sasl_tree = NULL;
2604       tvbuff_t *sasl_tvb;
2605       guint sasl_len, sasl_msg_len, length;
2606       /*
2607        * Yes.  The frame begins with a 4-byte big-endian length.
2608        * And we know we have at least 6 bytes
2609        */
2610
2611       /*
2612        * Get the SASL length, which is the length of data in the buffer
2613        * following the length (i.e., it's 4 less than the total length).
2614        *
2615        * XXX - do we need to reassemble buffers?  For now, we
2616        * assume that each LDAP message is entirely contained within
2617        * a buffer.
2618        */
2619       sasl_len = tvb_get_ntohl(tvb, offset);
2620       sasl_msg_len = sasl_len + 4;
2621       if (sasl_msg_len < 4) {
2622         /*
2623          * The message length was probably so large that the total length
2624          * overflowed.
2625          *
2626          * Report this as an error.
2627          */
2628         show_reported_bounds_error(tvb, pinfo, tree);
2629         return;
2630       }
2631
2632       /*
2633        * Is the buffer split across segment boundaries?
2634        */
2635       if (length_remaining < sasl_msg_len) {
2636         /* provide a hint to TCP where the next PDU starts */
2637         pinfo->want_pdu_tracking = 2;
2638         pinfo->bytes_until_next_pdu= sasl_msg_len - length_remaining;
2639         /*
2640          * Can we do reassembly?
2641          */
2642         if (ldap_desegment && pinfo->can_desegment) {
2643           /*
2644            * Yes.  Tell the TCP dissector where the data for this message
2645            * starts in the data it handed us, and how many more bytes we
2646            * need, and return.
2647            */
2648           pinfo->desegment_offset = offset;
2649           pinfo->desegment_len = sasl_msg_len - length_remaining;
2650           return;
2651         }
2652       }
2653
2654       /*
2655        * Construct a tvbuff containing the amount of the payload we have
2656        * available.  Make its reported length the amount of data in the PDU.
2657        *
2658        * XXX - if reassembly isn't enabled. the subdissector will throw a
2659        * BoundsError exception, rather than a ReportedBoundsError exception.
2660        * We really want a tvbuff where the length is "length", the reported
2661        * length is "plen", and the "if the snapshot length were infinite"
2662        * length is the minimum of the reported length of the tvbuff handed
2663        * to us and "plen", with a new type of exception thrown if the offset
2664        * is within the reported length but beyond that third length, with
2665        * that exception getting the "Unreassembled Packet" error.
2666        */
2667       length = length_remaining;
2668       if (length > sasl_msg_len) length = sasl_msg_len;
2669       sasl_tvb = tvb_new_subset(tvb, offset, length, sasl_msg_len);
2670
2671       if (ldap_tree) {
2672         proto_tree_add_uint(ldap_tree, hf_ldap_sasl_buffer_length, sasl_tvb, 0, 4,
2673                             sasl_len);
2674
2675         sasl_item = proto_tree_add_text(ldap_tree, sasl_tvb, 0,  sasl_msg_len, "SASL buffer");
2676         sasl_tree = proto_item_add_subtree(sasl_item, ett_ldap_sasl_blob);
2677       }
2678
2679       if (ldap_info->auth_mech != NULL &&
2680           strcmp(ldap_info->auth_mech, "GSS-SPNEGO") == 0) {
2681           tvbuff_t *gssapi_tvb, *plain_tvb = NULL, *decr_tvb= NULL;
2682           int ver_len;
2683           int length;
2684
2685           /*
2686            * This is GSS-API (using SPNEGO, but we should be done with
2687            * the negotiation by now).
2688            *
2689            * Dissect the GSS_Wrap() token; it'll return the length of
2690            * the token, from which we compute the offset in the tvbuff at
2691            * which the plaintext data, i.e. the LDAP message, begins.
2692            */
2693           length = tvb_length_remaining(sasl_tvb, 4);
2694           if ((guint)length > sasl_len)
2695               length = sasl_len;
2696           gssapi_tvb = tvb_new_subset(sasl_tvb, 4, length, sasl_len);
2697
2698           /* Attempt decryption of the GSSAPI wrapped data if possible */
2699           pinfo->decrypt_gssapi_tvb=DECRYPT_GSSAPI_NORMAL;
2700           pinfo->gssapi_wrap_tvb=NULL;
2701           pinfo->gssapi_encrypted_tvb=NULL;
2702           pinfo->gssapi_decrypted_tvb=NULL;
2703           ver_len = call_dissector(gssapi_wrap_handle, gssapi_tvb, pinfo, sasl_tree);
2704           /* if we could unwrap, do a tvb shuffle */
2705           if(pinfo->gssapi_decrypted_tvb){
2706                 decr_tvb=pinfo->gssapi_decrypted_tvb;
2707           }
2708           /* tidy up */
2709           pinfo->decrypt_gssapi_tvb=0;
2710           pinfo->gssapi_wrap_tvb=NULL;
2711           pinfo->gssapi_encrypted_tvb=NULL;
2712           pinfo->gssapi_decrypted_tvb=NULL;
2713
2714           /*
2715            * if len is 0 it probably mean that we got a PDU that is not
2716            * aligned to the start of the segment.
2717            */
2718           if(ver_len==0){
2719              return;
2720           }
2721
2722           /*
2723            * if we don't have unwrapped data,
2724            * see if the wrapping involved encryption of the
2725            * data; if not, just use the plaintext data.
2726            */
2727           if (!decr_tvb) {
2728             if(!pinfo->gssapi_data_encrypted){
2729               plain_tvb = tvb_new_subset(gssapi_tvb,  ver_len, -1, -1);
2730             }
2731           }
2732
2733           if (decr_tvb) {
2734             proto_item *enc_item = NULL;
2735             proto_tree *enc_tree = NULL;
2736
2737             /*
2738              * The LDAP message was encrypted in the packet, and has
2739              * been decrypted; dissect the decrypted LDAP message.
2740              */
2741             if (sasl_tree) {
2742               enc_item = proto_tree_add_text(sasl_tree, gssapi_tvb, ver_len, -1,
2743                                 "GSS-API Encrypted payload (%d byte%s)",
2744                                 sasl_len - ver_len,
2745                                 plurality(sasl_len - ver_len, "", "s"));
2746               enc_tree = proto_item_add_subtree(enc_item, ett_ldap_payload);
2747             }
2748             dissect_ldap_payload(decr_tvb, pinfo, enc_tree, ldap_info, TRUE, is_mscldap);
2749           } else if (plain_tvb) {
2750             proto_item *plain_item = NULL;
2751             proto_tree *plain_tree = NULL;
2752
2753             /*
2754              * The LDAP message wasn't encrypted in the packet;
2755              * dissect the plain LDAP message.
2756              */
2757             if (sasl_tree) {
2758               plain_item = proto_tree_add_text(sasl_tree, gssapi_tvb, ver_len, -1,
2759                                 "GSS-API payload (%d byte%s)",
2760                                 sasl_len - ver_len,
2761                                 plurality(sasl_len - ver_len, "", "s"));
2762               plain_tree = proto_item_add_subtree(plain_item, ett_ldap_payload);
2763             }
2764             dissect_ldap_payload(plain_tvb, pinfo, plain_tree, ldap_info, TRUE, is_mscldap);
2765           } else {
2766             /*
2767              * The LDAP message was encrypted in the packet, and was
2768              * not decrypted; just show it as encrypted data.
2769              */
2770             if (check_col(pinfo->cinfo, COL_INFO)) {
2771                     col_add_fstr(pinfo->cinfo, COL_INFO, "LDAP GSS-API Encrypted payload (%d byte%s)",
2772                                  sasl_len - ver_len,
2773                                  plurality(sasl_len - ver_len, "", "s"));
2774             }
2775             if (sasl_tree) {
2776               proto_tree_add_text(sasl_tree, gssapi_tvb, ver_len, -1,
2777                                 "GSS-API Encrypted payload (%d byte%s)",
2778                                 sasl_len - ver_len,
2779                                 plurality(sasl_len - ver_len, "", "s"));
2780             }
2781           }
2782       }
2783       offset += sasl_msg_len;
2784     } else {
2785         /* plain LDAP, so dissect the payload */
2786         dissect_ldap_payload(tvb, pinfo, ldap_tree, ldap_info, FALSE, is_mscldap);
2787         /* dissect_ldap_payload() has it's own loop so go out here */
2788         break;
2789     }
2790   }
2791 }
2792
2793
2794 static void
2795 dissect_ldap(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
2796 {
2797         dissect_ldap_pdu(tvb, pinfo, tree, FALSE);
2798         return;
2799 }
2800
2801 static void
2802 dissect_mscldap(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
2803 {
2804         dissect_ldap_pdu(tvb, pinfo, tree, TRUE);
2805         return;
2806 }
2807
2808 static void
2809 ldap_reinit(void)
2810 {
2811   ldap_conv_info_t *ldap_info;
2812
2813   /* Free up state attached to the ldap_info structures */
2814   for (ldap_info = ldap_info_items; ldap_info != NULL; ldap_info = ldap_info->next) {
2815     if (ldap_info->auth_mech != NULL) {
2816       g_free(ldap_info->auth_mech);
2817       ldap_info->auth_mech=NULL;
2818     }
2819     g_hash_table_destroy(ldap_info->matched);
2820     ldap_info->matched=NULL;
2821     g_hash_table_destroy(ldap_info->unmatched);
2822     ldap_info->unmatched=NULL;
2823   }
2824
2825   if (ldap_conv_info_chunk != NULL)
2826     g_mem_chunk_destroy(ldap_conv_info_chunk);
2827
2828   ldap_info_items = NULL;
2829
2830   ldap_conv_info_chunk = g_mem_chunk_new("ldap_conv_info_chunk",
2831                 sizeof(ldap_conv_info_t),
2832                 ldap_conv_info_chunk_count * sizeof(ldap_conv_info_t),
2833                 G_ALLOC_ONLY);
2834
2835   if (ldap_call_response_chunk != NULL)
2836     g_mem_chunk_destroy(ldap_call_response_chunk);
2837
2838   ldap_call_response_chunk = g_mem_chunk_new("ldap_call_response_chunk",
2839                 sizeof(ldap_call_response_t),
2840                 ldap_call_response_chunk_count * sizeof(ldap_call_response_t),
2841                 G_ALLOC_ONLY);
2842 }
2843
2844 void
2845 proto_register_ldap(void)
2846 {
2847   static value_string auth_types[] = {
2848     {LDAP_AUTH_SIMPLE,    "Simple"},
2849     {LDAP_AUTH_KRBV4LDAP, "Kerberos V4 to the LDAP server"},
2850     {LDAP_AUTH_KRBV4DSA,  "Kerberos V4 to the DSA"},
2851     {LDAP_AUTH_SASL,      "SASL"},
2852     {0, NULL},
2853   };
2854
2855   static value_string search_scope[] = {
2856     {0x00, "Base"},
2857     {0x01, "Single"},
2858     {0x02, "Subtree"},
2859     {0x00, NULL},
2860   };
2861
2862   static value_string search_dereference[] = {
2863     {0x00, "Never"},
2864     {0x01, "Searching"},
2865     {0x02, "Base Object"},
2866     {0x03, "Always"},
2867     {0x00, NULL},
2868   };
2869
2870   static hf_register_info hf[] = {
2871     { &hf_ldap_response_in,
2872       { "Response In", "ldap.response_in",
2873         FT_FRAMENUM, BASE_DEC, NULL, 0x0,
2874         "The response to this packet is in this frame", HFILL }},
2875
2876     { &hf_ldap_response_to,
2877       { "Response To", "ldap.response_to",
2878         FT_FRAMENUM, BASE_DEC, NULL, 0x0,
2879         "This is a response to the LDAP command in this frame", HFILL }},
2880
2881     { &hf_ldap_time,
2882       { "Time", "ldap.time",
2883         FT_RELATIVE_TIME, BASE_NONE, NULL, 0x0,
2884         "The time between the Call and the Reply", HFILL }},
2885
2886     { &hf_ldap_sasl_buffer_length,
2887       { "SASL Buffer Length",   "ldap.sasl_buffer_length",
2888         FT_UINT32, BASE_DEC, NULL, 0x0,
2889         "SASL Buffer Length", HFILL }},
2890
2891     { &hf_ldap_length,
2892       { "Length",               "ldap.length",
2893         FT_UINT32, BASE_DEC, NULL, 0x0,
2894         "LDAP Length", HFILL }},
2895
2896     { &hf_ldap_message_id,
2897       { "Message Id",           "ldap.message_id",
2898         FT_UINT32, BASE_DEC, NULL, 0x0,
2899         "LDAP Message Id", HFILL }},
2900     { &hf_ldap_message_type,
2901       { "Message Type",         "ldap.message_type",
2902         FT_UINT8, BASE_HEX, &msgTypes, 0x0,
2903         "LDAP Message Type", HFILL }},
2904     { &hf_ldap_message_length,
2905       { "Message Length",               "ldap.message_length",
2906         FT_UINT32, BASE_DEC, NULL, 0x0,
2907         "LDAP Message Length", HFILL }},
2908
2909     { &hf_ldap_message_result,
2910       { "Result Code",          "ldap.result.code",
2911         FT_UINT8, BASE_HEX, VALS(LDAPResultCode_vals), 0x0,
2912         "LDAP Result Code", HFILL }},
2913     { &hf_ldap_message_result_matcheddn,
2914       { "Matched DN",           "ldap.result.matcheddn",
2915         FT_STRING, BASE_NONE, NULL, 0x0,
2916         "LDAP Result Matched DN", HFILL }},
2917     { &hf_ldap_message_result_errormsg,
2918       { "Error Message",                "ldap.result.errormsg",
2919         FT_STRING, BASE_NONE, NULL, 0x0,
2920         "LDAP Result Error Message", HFILL }},
2921     { &hf_ldap_message_result_referral,
2922       { "Referral",             "ldap.result.referral",
2923         FT_STRING, BASE_NONE, NULL, 0x0,
2924         "LDAP Result Referral URL", HFILL }},
2925
2926     { &hf_ldap_message_bind_version,
2927       { "Version",              "ldap.bind.version",
2928         FT_UINT32, BASE_DEC, NULL, 0x0,
2929         "LDAP Bind Version", HFILL }},
2930     { &hf_ldap_message_bind_dn,
2931       { "DN",                   "ldap.bind.dn",
2932         FT_STRING, BASE_NONE, NULL, 0x0,
2933         "LDAP Bind Distinguished Name", HFILL }},
2934     { &hf_ldap_message_bind_auth,
2935       { "Auth Type",            "ldap.bind.auth_type",
2936         FT_UINT8, BASE_HEX, auth_types, 0x0,
2937         "LDAP Bind Auth Type", HFILL }},
2938     { &hf_ldap_message_bind_auth_password,
2939       { "Password",             "ldap.bind.password",
2940         FT_STRING, BASE_NONE, NULL, 0x0,
2941         "LDAP Bind Password", HFILL }},
2942     { &hf_ldap_message_bind_auth_mechanism,
2943       { "Mechanism",            "ldap.bind.mechanism",
2944         FT_STRING, BASE_NONE, NULL, 0x0,
2945         "LDAP Bind Mechanism", HFILL }},
2946     { &hf_ldap_message_bind_auth_credentials,
2947       { "Credentials",          "ldap.bind.credentials",
2948         FT_BYTES, BASE_NONE, NULL, 0x0,
2949         "LDAP Bind Credentials", HFILL }},
2950     { &hf_ldap_message_bind_server_credentials,
2951       { "Server Credentials",   "ldap.bind.server_credentials",
2952         FT_BYTES, BASE_NONE, NULL, 0x0,
2953         "LDAP Bind Server Credentials", HFILL }},
2954
2955     { &hf_ldap_message_search_base,
2956       { "Base DN",              "ldap.search.basedn",
2957         FT_STRING, BASE_NONE, NULL, 0x0,
2958         "LDAP Search Base Distinguished Name", HFILL }},
2959     { &hf_ldap_message_search_scope,
2960       { "Scope",                        "ldap.search.scope",
2961         FT_UINT8, BASE_HEX, search_scope, 0x0,
2962         "LDAP Search Scope", HFILL }},
2963     { &hf_ldap_message_search_deref,
2964       { "Dereference",          "ldap.search.dereference",
2965         FT_UINT8, BASE_HEX, search_dereference, 0x0,
2966         "LDAP Search Dereference", HFILL }},
2967     { &hf_ldap_message_search_sizeLimit,
2968       { "Size Limit",           "ldap.search.sizelimit",
2969         FT_UINT32, BASE_DEC, NULL, 0x0,
2970         "LDAP Search Size Limit", HFILL }},
2971     { &hf_ldap_message_search_timeLimit,
2972       { "Time Limit",           "ldap.search.timelimit",
2973         FT_UINT32, BASE_DEC, NULL, 0x0,
2974         "LDAP Search Time Limit", HFILL }},
2975     { &hf_ldap_message_search_typesOnly,
2976       { "Attributes Only",      "ldap.search.typesonly",
2977         FT_BOOLEAN, BASE_NONE, NULL, 0x0,
2978         "LDAP Search Attributes Only", HFILL }},
2979     { &hf_ldap_message_search_filter,
2980       { "Filter",               "ldap.search.filter",
2981         FT_STRING, BASE_NONE, NULL, 0x0,
2982         "LDAP Search Filter", HFILL }},
2983     { &hf_ldap_message_search_reference,
2984       { "Reference URL",        "ldap.search.reference",
2985         FT_STRING, BASE_NONE, NULL, 0x0,
2986         "LDAP Search Reference URL", HFILL }},
2987     { &hf_ldap_message_dn,
2988       { "Distinguished Name",   "ldap.dn",
2989         FT_STRING, BASE_NONE, NULL, 0x0,
2990         "LDAP Distinguished Name", HFILL }},
2991     { &hf_ldap_message_attribute,
2992       { "Attribute",            "ldap.attribute",
2993         FT_STRING, BASE_NONE, NULL, 0x0,
2994         "LDAP Attribute", HFILL }},
2995     /*
2996      * XXX - not all LDAP values are text strings; we'd need a file
2997      * describing which values (by name) are text strings and which are
2998      * binary.
2999      *
3000      * Some values that are, at least in Microsoft's schema, binary
3001      * are:
3002      *
3003      *  invocationId
3004      *  nTSecurityDescriptor
3005      *  objectGUID
3006      */
3007     { &hf_ldap_message_value,
3008       { "Value",                "ldap.value",
3009         FT_STRING, BASE_NONE, NULL, 0x0,
3010         "LDAP Value", HFILL }},
3011
3012     { &hf_ldap_message_modrdn_name,
3013       { "New Name",             "ldap.modrdn.name",
3014         FT_STRING, BASE_NONE, NULL, 0x0,
3015         "LDAP New Name", HFILL }},
3016     { &hf_ldap_message_modrdn_delete,
3017       { "Delete Values",        "ldap.modrdn.delete",
3018         FT_BOOLEAN, BASE_NONE, NULL, 0x0,
3019         "LDAP Modify RDN - Delete original values", HFILL }},
3020     { &hf_ldap_message_modrdn_superior,
3021       { "New Location",         "ldap.modrdn.superior",
3022         FT_STRING, BASE_NONE, NULL, 0x0,
3023         "LDAP Modify RDN - New Location", HFILL }},
3024
3025     { &hf_ldap_message_compare,
3026       { "Test",         "ldap.compare.test",
3027         FT_STRING, BASE_NONE, NULL, 0x0,
3028         "LDAP Compare Test", HFILL }},
3029
3030     { &hf_ldap_message_modify_add,
3031       { "Add",                  "ldap.modify.add",
3032         FT_STRING, BASE_NONE, NULL, 0x0,
3033         "LDAP Add", HFILL }},
3034     { &hf_ldap_message_modify_replace,
3035       { "Replace",              "ldap.modify.replace",
3036         FT_STRING, BASE_NONE, NULL, 0x0,
3037         "LDAP Replace", HFILL }},
3038     { &hf_ldap_message_modify_delete,
3039       { "Delete",               "ldap.modify.delete",
3040         FT_STRING, BASE_NONE, NULL, 0x0,
3041         "LDAP Delete", HFILL }},
3042
3043     { &hf_ldap_message_abandon_msgid,
3044       { "Abandon Msg Id",       "ldap.abandon.msgid",
3045         FT_UINT32, BASE_DEC, NULL, 0x0,
3046         "LDAP Abandon Msg Id", HFILL }},
3047
3048     { &hf_ldap_message_controls_oid,
3049       { "Control OID",  "ldap.controls.oid",
3050         FT_STRING, BASE_NONE, NULL, 0x0,
3051         "LDAP Control OID", HFILL }},
3052
3053     { &hf_ldap_message_controls_critical,
3054       { "Control Critical",     "ldap.controls.critical",
3055         FT_BOOLEAN, BASE_NONE, NULL, 0x0,
3056         "LDAP Control Critical", HFILL }},
3057
3058     { &hf_ldap_message_controls_value,
3059       { "Control Value",        "ldap.controls.value",
3060         FT_BYTES, BASE_NONE, NULL, 0x0,
3061         "LDAP Control Value", HFILL }},
3062
3063     { &hf_mscldap_netlogon_type,
3064       { "Type", "mscldap.netlogon.type",
3065         FT_UINT32, BASE_DEC, NULL, 0x0,
3066         "Type of <please tell ethereal developers what this type is>", HFILL }},
3067
3068     { &hf_mscldap_netlogon_version,
3069       { "Version", "mscldap.netlogon.version",
3070         FT_UINT32, BASE_DEC, NULL, 0x0,
3071         "Version of <please tell ethereal developers what this type is>", HFILL }},
3072
3073     { &hf_mscldap_netlogon_lm_token,
3074       { "LM Token", "mscldap.netlogon.lm_token",
3075         FT_UINT16, BASE_HEX, NULL, 0x0,
3076         "LM Token", HFILL }},
3077
3078     { &hf_mscldap_netlogon_nt_token,
3079       { "NT Token", "mscldap.netlogon.nt_token",
3080         FT_UINT16, BASE_HEX, NULL, 0x0,
3081         "NT Token", HFILL }},
3082
3083     { &hf_mscldap_netlogon_flags,
3084       { "Flags", "mscldap.netlogon.flags",
3085         FT_UINT32, BASE_HEX, NULL, 0x0,
3086         "Netlogon flags describing the DC properties", HFILL }},
3087
3088     { &hf_mscldap_domain_guid,
3089       { "Domain GUID", "mscldap.domain.guid",
3090         FT_BYTES, BASE_HEX, NULL, 0x0,
3091         "Domain GUID", HFILL }},
3092
3093     { &hf_mscldap_forest,
3094       { "Forest", "mscldap.forest",
3095         FT_STRING, BASE_NONE, NULL, 0x0,
3096         "Forest", HFILL }},
3097
3098     { &hf_mscldap_domain,
3099       { "Domain", "mscldap.domain",
3100         FT_STRING, BASE_NONE, NULL, 0x0,
3101         "Domainname", HFILL }},
3102
3103     { &hf_mscldap_hostname,
3104       { "Hostname", "mscldap.hostname",
3105         FT_STRING, BASE_NONE, NULL, 0x0,
3106         "Hostname", HFILL }},
3107
3108     { &hf_mscldap_nb_domain,
3109       { "NetBios Domain", "mscldap.nb_domain",
3110         FT_STRING, BASE_NONE, NULL, 0x0,
3111         "NetBios Domainname", HFILL }},
3112
3113     { &hf_mscldap_nb_hostname,
3114       { "NetBios Hostname", "mscldap.nb_hostname",
3115         FT_STRING, BASE_NONE, NULL, 0x0,
3116         "NetBios Hostname", HFILL }},
3117
3118     { &hf_mscldap_username,
3119       { "User", "mscldap.username",
3120         FT_STRING, BASE_NONE, NULL, 0x0,
3121         "User name", HFILL }},
3122
3123     { &hf_mscldap_sitename,
3124       { "Site", "mscldap.sitename",
3125         FT_STRING, BASE_NONE, NULL, 0x0,
3126         "Site name", HFILL }},
3127
3128     { &hf_mscldap_clientsitename,
3129       { "Client Site", "mscldap.clientsitename",
3130         FT_STRING, BASE_NONE, NULL, 0x0,
3131         "Client Site name", HFILL }},
3132
3133     { &hf_mscldap_netlogon_flags_pdc,
3134       { "PDC", "mscldap.netlogon.flags.pdc", FT_BOOLEAN, 32,
3135         TFS(&tfs_ads_pdc), 0x00000001, "Is this DC a PDC or not?", HFILL }},
3136
3137     { &hf_mscldap_netlogon_flags_gc,
3138       { "GC", "mscldap.netlogon.flags.gc", FT_BOOLEAN, 32,
3139         TFS(&tfs_ads_gc), 0x00000004, "Does this dc service as a GLOBAL CATALOGUE?", HFILL }},
3140
3141     { &hf_mscldap_netlogon_flags_ldap,
3142       { "LDAP", "mscldap.netlogon.flags.ldap", FT_BOOLEAN, 32,
3143         TFS(&tfs_ads_ldap), 0x00000008, "Does this DC act as an LDAP server?", HFILL }},
3144
3145     { &hf_mscldap_netlogon_flags_ds,
3146       { "DS", "mscldap.netlogon.flags.ds", FT_BOOLEAN, 32,
3147         TFS(&tfs_ads_ds), 0x00000010, "Does this dc provide DS services?", HFILL }},
3148
3149     { &hf_mscldap_netlogon_flags_kdc,
3150       { "KDC", "mscldap.netlogon.flags.kdc", FT_BOOLEAN, 32,
3151         TFS(&tfs_ads_kdc), 0x00000020, "Does this dc act as a KDC?", HFILL }},
3152
3153     { &hf_mscldap_netlogon_flags_timeserv,
3154       { "Time Serv", "mscldap.netlogon.flags.timeserv", FT_BOOLEAN, 32,
3155         TFS(&tfs_ads_timeserv), 0x00000040, "Does this dc provide time services (ntp) ?", HFILL }},
3156
3157     { &hf_mscldap_netlogon_flags_closest,
3158       { "Closest", "mscldap.netlogon.flags.closest", FT_BOOLEAN, 32,
3159         TFS(&tfs_ads_closest), 0x00000080, "Is this the closest dc? (is this used at all?)", HFILL }},
3160
3161     { &hf_mscldap_netlogon_flags_writable,
3162       { "Writable", "mscldap.netlogon.flags.writable", FT_BOOLEAN, 32,
3163         TFS(&tfs_ads_writable), 0x00000100, "Is this dc writable? (i.e. can it update the AD?)", HFILL }},
3164
3165     { &hf_mscldap_netlogon_flags_good_timeserv,
3166       { "Good Time Serv", "mscldap.netlogon.flags.good_timeserv", FT_BOOLEAN, 32,
3167         TFS(&tfs_ads_good_timeserv), 0x00000200, "Is this a Good Time Server? (i.e. does it have a hardware clock)", HFILL }},
3168
3169     { &hf_mscldap_netlogon_flags_ndnc,
3170       { "NDNC", "mscldap.netlogon.flags.ndnc", FT_BOOLEAN, 32,
3171         TFS(&tfs_ads_ndnc), 0x00000400, "Is this an NDNC dc?", HFILL }},
3172
3173   };
3174
3175   static gint *ett[] = {
3176     &ett_ldap,
3177     &ett_ldap_msg,
3178     &ett_ldap_payload,
3179     &ett_ldap_sasl_blob,
3180     &ett_ldap_referrals,
3181     &ett_ldap_attribute,
3182     &ett_ldap_controls,
3183     &ett_ldap_control,
3184     &ett_mscldap_netlogon_flags
3185   };
3186   module_t *ldap_module;
3187
3188   proto_ldap = proto_register_protocol("Lightweight Directory Access Protocol",
3189                                        "LDAP", "ldap");
3190   proto_register_field_array(proto_ldap, hf, array_length(hf));
3191   proto_register_subtree_array(ett, array_length(ett));
3192
3193   ldap_module = prefs_register_protocol(proto_ldap, NULL);
3194   prefs_register_bool_preference(ldap_module, "desegment_ldap_messages",
3195     "Reassemble LDAP messages spanning multiple TCP segments",
3196     "Whether the LDAP dissector should reassemble messages spanning multiple TCP segments."
3197     " To use this option, you must also enable \"Allow subdissectors to reassemble TCP streams\" in the TCP protocol settings.",
3198     &ldap_desegment);
3199
3200   proto_cldap = proto_register_protocol(
3201           "Connectionless Lightweight Directory Access Protocol",
3202           "CLDAP", "cldap");
3203
3204   register_init_routine(ldap_reinit);
3205   ldap_tap=register_tap("ldap");
3206 }
3207
3208 void
3209 proto_reg_handoff_ldap(void)
3210 {
3211   dissector_handle_t ldap_handle, cldap_handle;
3212
3213   ldap_handle = create_dissector_handle(dissect_ldap, proto_ldap);
3214   dissector_add("tcp.port", TCP_PORT_LDAP, ldap_handle);
3215   dissector_add("tcp.port", TCP_PORT_GLOBALCAT_LDAP, ldap_handle);
3216
3217   cldap_handle = create_dissector_handle(dissect_mscldap, proto_cldap);
3218   dissector_add("udp.port", UDP_PORT_CLDAP, cldap_handle);
3219
3220   gssapi_handle = find_dissector("gssapi");
3221   gssapi_wrap_handle = find_dissector("gssapi_verf");
3222 }