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