Guy suggested that the dcerpc opnum value_string code could be simplified
[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.62 2003/07/31 18:09:07 guy 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 #ifdef HAVE_CONFIG_H
52 # include "config.h"
53 #endif
54
55 #include <stdio.h>
56
57 #include <string.h>
58 #include <glib.h>
59
60 #ifdef NEED_SNPRINTF_H
61 # include "snprintf.h"
62 #endif
63
64 #include <epan/packet.h>
65
66 #include "packet-ldap.h"
67 #include "asn1.h"
68 #include "prefs.h"
69 #include <epan/conversation.h>
70 #include "packet-frame.h"
71
72 static int proto_ldap = -1;
73 static int hf_ldap_sasl_buffer_length = -1;
74 static int hf_ldap_length = -1;
75 static int hf_ldap_message_id = -1;
76 static int hf_ldap_message_type = -1;
77 static int hf_ldap_message_length = -1;
78
79 static int hf_ldap_message_result = -1;
80 static int hf_ldap_message_result_matcheddn = -1;
81 static int hf_ldap_message_result_errormsg = -1;
82 static int hf_ldap_message_result_referral = -1;
83
84 static int hf_ldap_message_bind_version = -1;
85 static int hf_ldap_message_bind_dn = -1;
86 static int hf_ldap_message_bind_auth = -1;
87 static int hf_ldap_message_bind_auth_password = -1;
88 static int hf_ldap_message_bind_auth_mechanism = -1;
89 static int hf_ldap_message_bind_auth_credentials = -1;
90 static int hf_ldap_message_bind_server_credentials = -1;
91
92 static int hf_ldap_message_search_base = -1;
93 static int hf_ldap_message_search_scope = -1;
94 static int hf_ldap_message_search_deref = -1;
95 static int hf_ldap_message_search_sizeLimit = -1;
96 static int hf_ldap_message_search_timeLimit = -1;
97 static int hf_ldap_message_search_typesOnly = -1;
98 static int hf_ldap_message_search_filter = -1;
99 static int hf_ldap_message_search_reference = -1;
100
101 static int hf_ldap_message_dn = -1;
102 static int hf_ldap_message_attribute = -1;
103 static int hf_ldap_message_value = -1;
104
105 static int hf_ldap_message_modrdn_name = -1;
106 static int hf_ldap_message_modrdn_delete = -1;
107 static int hf_ldap_message_modrdn_superior = -1;
108
109 static int hf_ldap_message_compare = -1;
110
111 static int hf_ldap_message_modify_add = -1;
112 static int hf_ldap_message_modify_replace = -1;
113 static int hf_ldap_message_modify_delete = -1;
114
115 static int hf_ldap_message_abandon_msgid = -1;
116
117 static gint ett_ldap = -1;
118 static gint ett_ldap_gssapi_token = -1;
119 static gint ett_ldap_referrals = -1;
120 static gint ett_ldap_attribute = -1;
121
122 /* desegmentation of LDAP */
123 static gboolean ldap_desegment = TRUE;
124
125 #define TCP_PORT_LDAP                   389
126 #define UDP_PORT_CLDAP                  389
127 #define TCP_PORT_GLOBALCAT_LDAP         3268 /* Windows 2000 Global Catalog */
128
129 static dissector_handle_t gssapi_handle;
130 static dissector_handle_t gssapi_wrap_handle;
131
132 /*
133  * Data structure attached to a conversation, giving authentication
134  * information from a bind request.
135  * We keep a linked list of them, so that we can free up all the
136  * authentication mechanism strings.
137  */
138 typedef struct ldap_auth_info_t {
139   guint auth_type;              /* authentication type */
140   char *auth_mech;              /* authentication mechanism */
141   guint32 first_auth_frame;     /* first frame that would use a security layer */
142   struct ldap_auth_info_t *next;
143 } ldap_auth_info_t;
144
145 static GMemChunk *ldap_auth_info_chunk = NULL;
146
147 static guint ldap_auth_info_chunk_count = 200;
148
149 static ldap_auth_info_t *auth_info_items;
150
151 static value_string msgTypes [] = {
152   {LDAP_REQ_BIND, "Bind Request"},
153   {LDAP_REQ_UNBIND, "Unbind Request"},
154   {LDAP_REQ_SEARCH, "Search Request"},
155   {LDAP_REQ_MODIFY, "Modify Request"},
156   {LDAP_REQ_ADD, "Add Request"},
157   {LDAP_REQ_DELETE, "Delete Request"},
158   {LDAP_REQ_MODRDN, "Modify RDN Request"},
159   {LDAP_REQ_COMPARE, "Compare Request"},
160   {LDAP_REQ_ABANDON, "Abandon Request"},
161   {LDAP_REQ_EXTENDED, "Extended Request"},
162
163   {LDAP_RES_BIND, "Bind Result"},
164   {LDAP_RES_SEARCH_ENTRY, "Search Entry"},
165   {LDAP_RES_SEARCH_RESULT, "Search Result"},
166   {LDAP_RES_SEARCH_REF, "Search Result Reference"},
167   {LDAP_RES_MODIFY, "Modify Result"},
168   {LDAP_RES_ADD, "Add Result"},
169   {LDAP_RES_DELETE, "Delete Result"},
170   {LDAP_RES_MODRDN, "Modify RDN Result"},
171   {LDAP_RES_COMPARE, "Compare Result"},
172   {LDAP_RES_EXTENDED, "Extended Response"},
173   {0, NULL},
174 };
175
176 static value_string result_codes[] = {
177     {0, "Success"},
178     {1, "Operations error"},
179     {2, "Protocol error"},
180     {3, "Time limit exceeded"},
181     {4, "Size limit exceeded"},
182     {5, "Compare false"},
183     {6, "Compare true"},
184     {7, "Authentication method not supported"},
185     {8, "Strong authentication required"},
186     {10, "Referral"},
187     {11, "Administrative limit exceeded"},
188     {12, "Unavailable critical extension"},
189     {13, "Confidentiality required"},
190     {14, "SASL bind in progress"},
191     {16, "No such attribute"},
192     {17, "Undefined attribute type"},
193     {18, "Inappropriate matching"},
194     {19, "Constraint violation"},
195     {20, "Attribute or value exists"},
196     {21, "Invalid attribute syntax"},
197     {32, "No such object"},
198     {33, "Alias problem"},
199     {34, "Invalid DN syntax"},
200     {36, "Alias derefetencing problem"},
201     {48, "Inappropriate authentication"},
202     {49, "Invalid credentials"},
203     {50, "Insufficient access rights"},
204     {51, "Busy"},
205     {52, "Unavailable"},
206     {53, "Unwilling to perform"},
207     {54, "Loop detected"},
208     {64, "Naming violation"},
209     {65, "Objectclass violation"},
210     {66, "Not allowed on non-leaf"},
211     {67, "Not allowed on RDN"},
212     {68, "Entry already exists"},
213     {69, "Objectclass modification prohibited"},
214     {71, "Affects multiple DSAs"},
215     {80, "Other"},
216     {0,  NULL},
217 };
218
219 static int read_length(ASN1_SCK *a, proto_tree *tree, int hf_id, guint *len)
220 {
221   guint length = 0;
222   gboolean def = FALSE;
223   int start = a->offset;
224   int ret;
225
226   ret = asn1_length_decode(a, &def, &length);
227   if (ret != ASN1_ERR_NOERROR) {
228     if (tree) {
229       proto_tree_add_text(tree, a->tvb, start, 0,
230         "%s: ERROR: Couldn't parse length: %s",
231         proto_registrar_get_name(hf_id), asn1_err_to_str(ret));
232     }
233     return ret;
234   }
235
236   if (len)
237     *len = length;
238
239   if (tree)
240     proto_tree_add_uint(tree, hf_id, a->tvb, start, a->offset-start, length);
241
242   return ASN1_ERR_NOERROR;
243 }
244
245 static int read_sequence(ASN1_SCK *a, guint *len)
246 {
247   guint cls, con, tag;
248   gboolean def;
249   guint length;
250   int ret;
251
252   ret = asn1_header_decode(a, &cls, &con, &tag, &def, &length);
253   if (ret != ASN1_ERR_NOERROR)
254     return ret;
255   if (cls != ASN1_UNI || con != ASN1_CON || tag != ASN1_SEQ)
256     return ASN1_ERR_WRONG_TYPE;
257
258   if (len)
259     *len = length;
260
261   return ASN1_ERR_NOERROR;
262 }
263
264 static int read_set(ASN1_SCK *a, guint *len)
265 {
266   guint cls, con, tag;
267   gboolean def;
268   guint length;
269   int ret;
270
271   ret = asn1_header_decode(a, &cls, &con, &tag, &def, &length);
272   if (ret != ASN1_ERR_NOERROR)
273     return ret;
274   if (cls != ASN1_UNI || con != ASN1_CON || tag != ASN1_SET)
275     return ASN1_ERR_WRONG_TYPE;
276
277   if (len)
278     *len = length;
279
280   return ASN1_ERR_NOERROR;
281 }
282
283 static int read_integer_value(ASN1_SCK *a, proto_tree *tree, int hf_id,
284         proto_item **new_item, guint *i, int start, guint length)
285 {
286   guint integer = 0;
287   proto_item *temp_item = NULL;
288   int ret;
289
290   ret = asn1_uint32_value_decode(a, length, &integer);
291   if (ret != ASN1_ERR_NOERROR) {
292     if (tree) {
293       proto_tree_add_text(tree, a->tvb, start, 0,
294        "%s: ERROR: Couldn't parse value: %s",
295         proto_registrar_get_name(hf_id), asn1_err_to_str(ret));
296     }
297     return ret;
298   }
299
300   if (i)
301     *i = integer;
302
303   if (tree)
304     temp_item = proto_tree_add_uint(tree, hf_id, a->tvb, start, a->offset-start, integer);
305
306   if (new_item)
307     *new_item = temp_item;
308
309   return ASN1_ERR_NOERROR;
310 }
311
312 static int read_integer(ASN1_SCK *a, proto_tree *tree, int hf_id,
313         proto_item **new_item, guint *i, guint expected_tag)
314 {
315   guint cls, con, tag;
316   gboolean def;
317   guint length;
318   int start = a->offset;
319   int ret;
320
321   ret = asn1_header_decode(a, &cls, &con, &tag, &def, &length);
322   if (ret == ASN1_ERR_NOERROR) {
323     if (cls != ASN1_UNI || con != ASN1_PRI || tag != expected_tag)
324       ret = ASN1_ERR_WRONG_TYPE;
325   }
326   if (ret != ASN1_ERR_NOERROR) {
327     if (tree) {
328       proto_tree_add_text(tree, a->tvb, start, 0,
329         "%s: ERROR: Couldn't parse header: %s",
330         (hf_id != -1) ? proto_registrar_get_name(hf_id) : "LDAP message",
331         asn1_err_to_str(ret));
332     }
333     return ret;
334   }
335
336   return read_integer_value(a, tree, hf_id, new_item, i, start, length);
337 }
338
339 static int read_boolean_value(ASN1_SCK *a, proto_tree *tree, int hf_id,
340         proto_item **new_item, guint *i, int start, guint length)
341 {
342   guint integer = 0;
343   proto_item *temp_item = NULL;
344   int ret;
345
346   ret = asn1_uint32_value_decode(a, length, &integer);
347   if (ret != ASN1_ERR_NOERROR) {
348     if (tree) {
349       proto_tree_add_text(tree, a->tvb, start, 0,
350         "%s: ERROR: Couldn't parse value: %s",
351         proto_registrar_get_name(hf_id), asn1_err_to_str(ret));
352     }
353     return ret;
354   }
355
356   if (i)
357     *i = integer;
358
359   if (tree)
360     temp_item = proto_tree_add_boolean(tree, hf_id, a->tvb, start, a->offset-start, integer);
361   if (new_item)
362     *new_item = temp_item;
363
364   return ASN1_ERR_NOERROR;
365 }
366
367 static int read_boolean(ASN1_SCK *a, proto_tree *tree, int hf_id,
368         proto_item **new_item, guint *i)
369 {
370   guint cls, con, tag;
371   gboolean def;
372   guint length;
373   int start = a->offset;
374   int ret;
375
376   ret = asn1_header_decode(a, &cls, &con, &tag, &def, &length);
377   if (ret == ASN1_ERR_NOERROR) {
378     if (cls != ASN1_UNI || con != ASN1_PRI || tag != ASN1_BOL)
379       ret = ASN1_ERR_WRONG_TYPE;
380   }
381   if (ret != ASN1_ERR_NOERROR) {
382     if (tree) {
383       proto_tree_add_text(tree, a->tvb, start, 0,
384         "%s: ERROR: Couldn't parse header: %s",
385         proto_registrar_get_name(hf_id), asn1_err_to_str(ret));
386     }
387     return ret;
388   }
389
390   return read_boolean_value(a, tree, hf_id, new_item, i, start, length);
391 }
392
393 static int read_string_value(ASN1_SCK *a, proto_tree *tree, int hf_id,
394         proto_item **new_item, char **s, int start, guint length)
395 {
396   guchar *string;
397   proto_item *temp_item = NULL;
398   int ret;
399
400   if (length)
401   {
402     ret = asn1_string_value_decode(a, length, &string);
403     if (ret != ASN1_ERR_NOERROR) {
404       if (tree) {
405         proto_tree_add_text(tree, a->tvb, start, 0,
406           "%s: ERROR: Couldn't parse value: %s",
407           proto_registrar_get_name(hf_id), asn1_err_to_str(ret));
408       }
409       return ret;
410     }
411     string = g_realloc(string, length + 1);
412     string[length] = '\0';
413   }
414   else
415     string = "(null)";
416
417   if (tree)
418     temp_item = proto_tree_add_string(tree, hf_id, a->tvb, start, a->offset - start, string);
419   if (new_item)
420     *new_item = temp_item;
421
422   if (s && length)
423     *s = string;
424   else if (length)
425     g_free(string);
426
427   return ASN1_ERR_NOERROR;
428 }
429
430 static int read_string(ASN1_SCK *a, proto_tree *tree, int hf_id,
431         proto_item **new_item, char **s, guint expected_cls, guint expected_tag)
432 {
433   guint cls, con, tag;
434   gboolean def;
435   guint length;
436   int start = a->offset;
437   int ret;
438
439   ret = asn1_header_decode(a, &cls, &con, &tag, &def, &length);
440   if (ret == ASN1_ERR_NOERROR) {
441     if (cls != expected_cls || con != ASN1_PRI || tag != expected_tag)
442       ret = ASN1_ERR_WRONG_TYPE;
443   }
444   if (ret != ASN1_ERR_NOERROR) {
445     if (tree) {
446       proto_tree_add_text(tree, a->tvb, start, 0,
447         "%s: ERROR: Couldn't parse header: %s",
448         proto_registrar_get_name(hf_id), asn1_err_to_str(ret));
449     }
450     return ret;
451   }
452
453   return read_string_value(a, tree, hf_id, new_item, s, start, length);
454 }
455
456 static int read_bytestring_value(ASN1_SCK *a, proto_tree *tree, int hf_id,
457         proto_item **new_item, char **s, int start, guint length)
458 {
459   guchar *string;
460   proto_item *temp_item = NULL;
461   int ret;
462
463   if (length)
464   {
465     ret = asn1_string_value_decode(a, length, &string);
466     if (ret != ASN1_ERR_NOERROR) {
467       if (tree) {
468         proto_tree_add_text(tree, a->tvb, start, 0,
469           "%s: ERROR: Couldn't parse value: %s",
470           proto_registrar_get_name(hf_id), asn1_err_to_str(ret));
471       }
472       return ret;
473     }
474     string = g_realloc(string, length + 1);
475     string[length] = '\0';
476   }
477   else
478     string = "(null)";
479
480   if (tree)
481     temp_item = proto_tree_add_bytes(tree, hf_id, a->tvb, start, a->offset - start, string);
482   if (new_item)
483     *new_item = temp_item;
484
485   if (s && length)
486     *s = string;
487   else if (length)
488     g_free(string);
489
490   return ASN1_ERR_NOERROR;
491 }
492
493 static int read_bytestring(ASN1_SCK *a, proto_tree *tree, int hf_id,
494         proto_item **new_item, char **s, guint expected_cls, guint expected_tag)
495 {
496   guint cls, con, tag;
497   gboolean def;
498   guint length;
499   int start = a->offset;
500   int ret;
501
502   ret = asn1_header_decode(a, &cls, &con, &tag, &def, &length);
503   if (ret == ASN1_ERR_NOERROR) {
504     if (cls != expected_cls || con != ASN1_PRI || tag != expected_tag)
505       ret = ASN1_ERR_WRONG_TYPE;
506   }
507   if (ret != ASN1_ERR_NOERROR) {
508     if (tree) {
509       proto_tree_add_text(tree, a->tvb, start, 0,
510         "%s: ERROR: Couldn't parse header: %s",
511         proto_registrar_get_name(hf_id), asn1_err_to_str(ret));
512     }
513     return ret;
514   }
515
516   return read_bytestring_value(a, tree, hf_id, new_item, s, start, length);
517 }
518
519 static int parse_filter_strings(ASN1_SCK *a, char **filter, guint *filter_length, const guchar *operation)
520 {
521   guchar *string;
522   guchar *string2;
523   guint string_length;
524   guint string2_length;
525   guint string_bytes;
526   char *filterp;
527   int ret;
528
529   ret = asn1_octet_string_decode(a, &string, &string_length, &string_bytes);
530   if (ret != ASN1_ERR_NOERROR)
531     return ret;
532   ret = asn1_octet_string_decode(a, &string2, &string2_length, &string_bytes);
533   if (ret != ASN1_ERR_NOERROR)
534     return ret;
535   *filter_length += 2 + strlen(operation) + string_length + string2_length;
536   *filter = g_realloc(*filter, *filter_length);
537   filterp = *filter + strlen(*filter);
538   *filterp++ = '(';
539   if (string_length != 0) {
540         memcpy(filterp, string, string_length);
541         filterp += string_length;
542   }
543   strcpy(filterp, operation);
544   filterp += strlen(operation);
545   if (string2_length != 0) {
546         memcpy(filterp, string2, string2_length);
547         filterp += string2_length;
548   }
549   *filterp++ = ')';
550   *filterp = '\0';
551   g_free(string);
552   g_free(string2);
553   return ASN1_ERR_NOERROR;
554 }
555
556 /* Richard Dawe: To parse substring filters, I added this function. */
557 static int parse_filter_substrings(ASN1_SCK *a, char **filter, guint *filter_length)
558 {
559   int end;
560   guchar *string;
561   char *filterp;
562   guint string_length;
563   guint string_bytes;
564   guint seq_len;
565   guint header_bytes;
566   int ret, any_valued;
567
568   /* For ASN.1 parsing of octet strings */
569   guint        cls;
570   guint        con;
571   guint        tag;
572   gboolean     def;
573
574   ret = asn1_octet_string_decode(a, &string, &string_length, &string_bytes);
575   if (ret != ASN1_ERR_NOERROR)
576     return ret;
577
578   ret = asn1_sequence_decode(a, &seq_len, &header_bytes);
579   if (ret != ASN1_ERR_NOERROR)
580     return ret;
581
582   *filter_length += 2 + 1 + string_length;
583   *filter = g_realloc(*filter, *filter_length);
584
585   filterp = *filter + strlen(*filter);
586   *filterp++ = '(';
587   if (string_length != 0) {
588     memcpy(filterp, string, string_length);
589     filterp += string_length;
590   }
591   *filterp++ = '=';
592   *filterp = '\0';
593   g_free(string);
594
595   /* Now decode seq_len's worth of octet strings. */
596   any_valued = 0;
597   end = a->offset + seq_len;
598
599   while (a->offset < end) {
600     /* Octet strings here are context-specific, which
601      * asn1_octet_string_decode() barfs on. Emulate it, but don't barf. */
602     ret = asn1_header_decode (a, &cls, &con, &tag, &def, &string_length);
603     if (ret != ASN1_ERR_NOERROR)
604       return ret;
605
606     /* XXX - check the tag? */
607     if (cls != ASN1_CTX || con != ASN1_PRI) {
608         /* XXX - handle the constructed encoding? */
609         return ASN1_ERR_WRONG_TYPE;
610     }
611     if (!def)
612         return ASN1_ERR_LENGTH_NOT_DEFINITE;
613
614     ret = asn1_string_value_decode(a, (int) string_length, &string);
615     if (ret != ASN1_ERR_NOERROR)
616       return ret;
617
618     /* If we have an 'any' component with a string value, we need to append
619      * an extra asterisk before final component. */
620     if ((tag == 1) && (string_length != 0))
621       any_valued = 1;
622
623     if ( (tag == 1) || ((tag == 2) && any_valued) )
624       (*filter_length)++;
625     *filter_length += string_length;
626     *filter = g_realloc(*filter, *filter_length);
627
628     filterp = *filter + strlen(*filter);
629     if ( (tag == 1) || ((tag == 2) && any_valued) )
630       *filterp++ = '*';
631     if (tag == 2)
632       any_valued = 0;
633     if (string_length != 0) {
634       memcpy(filterp, string, string_length);
635       filterp += string_length;
636     }
637     *filterp = '\0';
638     g_free(string);
639   }
640
641   if (any_valued)
642   {
643     (*filter_length)++;
644     *filter = g_realloc(*filter, *filter_length);
645     filterp = *filter + strlen(*filter);
646     *filterp++ = '*';
647   }
648
649   /* NB: Allocated byte for this earlier */
650   *filterp++ = ')';
651   *filterp = '\0';
652
653   return ASN1_ERR_NOERROR;
654 }
655
656 /* Returns -1 if we're at the end, returns an ASN1_ERR value otherwise. */
657 static int parse_filter(ASN1_SCK *a, char **filter, guint *filter_length,
658                         int *end)
659 {
660   guint cls, con, tag;
661   guint length;
662   gboolean def;
663   int ret;
664
665   ret = asn1_header_decode(a, &cls, &con, &tag, &def, &length);
666   if (ret != ASN1_ERR_NOERROR)
667     return ret;
668
669   if (*end == 0)
670   {
671     *end = a->offset + length;
672     *filter_length = 1;
673     *filter = g_malloc0(*filter_length);
674   }
675
676   if (cls == ASN1_CTX)  /* XXX - handle other types as errors? */
677   {
678     switch (tag)
679     {
680      case LDAP_FILTER_AND:
681       {
682         int add_end;
683
684         if (con != ASN1_CON)
685           return ASN1_ERR_WRONG_TYPE;
686         add_end = a->offset + length;
687         *filter_length += 3;
688         *filter = g_realloc(*filter, *filter_length);
689         strcat(*filter, "(&");
690         while ((ret = parse_filter(a, filter, filter_length, &add_end))
691                 == ASN1_ERR_NOERROR)
692           continue;
693         if (ret != -1)
694           return ret;
695         strcat(*filter, ")");
696       }
697       break;
698      case LDAP_FILTER_OR:
699       {
700         int or_end;
701
702         if (con != ASN1_CON)
703           return ASN1_ERR_WRONG_TYPE;
704         or_end = a->offset + length;
705         *filter_length += 3;
706         *filter = g_realloc(*filter, *filter_length);
707         strcat(*filter, "(|");
708         while ((ret = parse_filter(a, filter, filter_length, &or_end))
709                 == ASN1_ERR_NOERROR)
710           continue;
711         if (ret != -1)
712           return ret;
713         strcat(*filter, ")");
714       }
715       break;
716      case LDAP_FILTER_NOT:
717       {
718         int not_end;
719
720         if (con != ASN1_CON)
721           return ASN1_ERR_WRONG_TYPE;
722         not_end = a->offset + length;
723         *filter_length += 3;
724         *filter = g_realloc(*filter, *filter_length);
725         strcat(*filter, "(!");
726         ret = parse_filter(a, filter, filter_length, &not_end);
727         if (ret != -1 && ret != ASN1_ERR_NOERROR)
728           return ret;
729         strcat(*filter, ")");
730       }
731       break;
732      case LDAP_FILTER_EQUALITY:
733       if (con != ASN1_CON)
734         return ASN1_ERR_WRONG_TYPE;
735       ret = parse_filter_strings(a, filter, filter_length, "=");
736       if (ret != ASN1_ERR_NOERROR)
737         return ret;
738       break;
739      case LDAP_FILTER_GE:
740       if (con != ASN1_CON)
741         return ASN1_ERR_WRONG_TYPE;
742       ret = parse_filter_strings(a, filter, filter_length, ">=");
743       if (ret != ASN1_ERR_NOERROR)
744         return ret;
745       break;
746      case LDAP_FILTER_LE:
747       if (con != ASN1_CON)
748         return ASN1_ERR_WRONG_TYPE;
749       ret = parse_filter_strings(a, filter, filter_length, "<=");
750       if (ret != -1 && ret != ASN1_ERR_NOERROR)
751         return ret;
752       break;
753      case LDAP_FILTER_APPROX:
754       if (con != ASN1_CON)
755         return ASN1_ERR_WRONG_TYPE;
756       ret = parse_filter_strings(a, filter, filter_length, "~=");
757       if (ret != ASN1_ERR_NOERROR)
758         return ret;
759       break;
760      case LDAP_FILTER_PRESENT:
761       {
762         guchar *string;
763         char *filterp;
764
765         if (con != ASN1_PRI)
766           return ASN1_ERR_WRONG_TYPE;
767         ret = asn1_string_value_decode(a, length, &string);
768         if (ret != ASN1_ERR_NOERROR)
769           return ret;
770         *filter_length += 4 + length;
771         *filter = g_realloc(*filter, *filter_length);
772         filterp = *filter + strlen(*filter);
773         *filterp++ = '(';
774         if (length != 0) {
775           memcpy(filterp, string, length);
776           filterp += length;
777         }
778         *filterp++ = '=';
779         *filterp++ = '*';
780         *filterp++ = ')';
781         *filterp = '\0';
782         g_free(string);
783       }
784       break;
785      case LDAP_FILTER_SUBSTRINGS:
786       if (con != ASN1_CON)
787         return ASN1_ERR_WRONG_TYPE;
788       /* Richard Dawe: Handle substrings */
789       ret = parse_filter_substrings(a, filter, filter_length);
790       if (ret != ASN1_ERR_NOERROR)
791         return ret;
792       break;
793      default:
794       return ASN1_ERR_WRONG_TYPE;
795     }
796   }
797
798   if (a->offset == *end)
799     return -1;
800   else
801     return ASN1_ERR_NOERROR;
802 }
803
804 static gboolean read_filter(ASN1_SCK *a, proto_tree *tree, int hf_id)
805 {
806   int start = a->offset;
807   char *filter = 0;
808   guint filter_length = 0;
809   int end = 0;
810   int ret;
811
812   while ((ret = parse_filter(a, &filter, &filter_length, &end))
813         == ASN1_ERR_NOERROR)
814     continue;
815
816   if (tree) {
817     if (ret != -1) {
818       proto_tree_add_text(tree, a->tvb, start, 0,
819         "%s: ERROR: Can't parse filter: %s",
820         proto_registrar_get_name(hf_id), asn1_err_to_str(ret));
821     } else
822       proto_tree_add_string(tree, hf_id, a->tvb, start, a->offset-start, filter);
823   }
824
825   g_free(filter);
826
827   return (ret == -1) ? TRUE : FALSE;
828 }
829
830 /********************************************************************************************/
831
832 static void dissect_ldap_result(ASN1_SCK *a, proto_tree *tree, packet_info *pinfo)
833 {
834   guint resultCode = 0;
835   int ret;
836   if (read_integer(a, tree, hf_ldap_message_result, 0, &resultCode, ASN1_ENUM) != ASN1_ERR_NOERROR)
837     return;
838
839   if (resultCode != 0) {
840           if (check_col(pinfo->cinfo, COL_INFO))
841                   col_append_fstr(pinfo->cinfo, COL_INFO, ", %s", 
842                                   val_to_str(resultCode, result_codes,
843                                              "Unknown (%u)"));
844   }
845
846   if (read_string(a, tree, hf_ldap_message_result_matcheddn, 0, 0, ASN1_UNI, ASN1_OTS) != ASN1_ERR_NOERROR)
847     return;
848   if (read_string(a, tree, hf_ldap_message_result_errormsg, 0, 0, ASN1_UNI, ASN1_OTS) != ASN1_ERR_NOERROR)
849     return;
850
851   if (resultCode == 10)         /* Referral */
852   {
853     int start = a->offset;
854     int end;
855     guint length;
856     proto_item *ti;
857     proto_tree *referralTree;
858
859     ret = read_sequence(a, &length);
860     if (ret != ASN1_ERR_NOERROR) {
861       if (tree) {
862         proto_tree_add_text(tree, a->tvb, start, 0,
863             "ERROR: Couldn't parse referral URL sequence header: %s",
864             asn1_err_to_str(ret));
865       }
866       return;
867     }
868     ti = proto_tree_add_text(tree, a->tvb, start, length, "Referral URLs");
869     referralTree = proto_item_add_subtree(ti, ett_ldap_referrals);
870
871     end = a->offset + length;
872     while (a->offset < end) {
873       if (read_string(a, referralTree, hf_ldap_message_result_referral, 0, 0, ASN1_UNI, ASN1_OTS) != ASN1_ERR_NOERROR)
874         return;
875     }
876   }
877 }
878
879 static void dissect_ldap_request_bind(ASN1_SCK *a, proto_tree *tree,
880     tvbuff_t *tvb, packet_info *pinfo)
881 {
882   guint cls, con, tag;
883   gboolean def;
884   guint length;
885   int start;
886   int end;
887   int ret;
888   conversation_t *conversation;
889   ldap_auth_info_t *auth_info;
890   char *mechanism, *s = NULL;
891   int token_offset;
892   gint available_length, reported_length;
893   tvbuff_t *new_tvb;
894   proto_item *gitem;
895   proto_tree *gtree = NULL;
896
897   if (read_integer(a, tree, hf_ldap_message_bind_version, 0, 0, ASN1_INT) != ASN1_ERR_NOERROR)
898     return;
899   if (read_string(a, tree, hf_ldap_message_bind_dn, 0, &s, ASN1_UNI, ASN1_OTS) != ASN1_ERR_NOERROR)
900     return;
901
902   if (check_col(pinfo->cinfo, COL_INFO))
903     col_append_fstr(pinfo->cinfo, COL_INFO, ", DN=%s", s != NULL ? s : "(null)");
904   g_free(s);
905
906   start = a->offset;
907   ret = asn1_header_decode(a, &cls, &con, &tag, &def, &length);
908   if (ret == ASN1_ERR_NOERROR) {
909     if (cls != ASN1_CTX) {
910       /* RFCs 1777 and 2251 say these are context-specific types */
911       ret = ASN1_ERR_WRONG_TYPE;
912     }
913   }
914   if (ret != ASN1_ERR_NOERROR) {
915     proto_tree_add_text(tree, a->tvb, start, 0,
916       "%s: ERROR: Couldn't parse header: %s",
917       proto_registrar_get_name(hf_ldap_message_bind_auth),
918       asn1_err_to_str(ret));
919     return;
920   }
921   proto_tree_add_uint(tree, hf_ldap_message_bind_auth, a->tvb, start,
922                         a->offset - start, tag);
923   end = a->offset + length;
924   switch (tag)
925   {
926    case LDAP_AUTH_SIMPLE:
927     if (read_string_value(a, tree, hf_ldap_message_bind_auth_password, NULL,
928                           NULL, start, length) != ASN1_ERR_NOERROR)
929       return;
930     break;
931
932     /* For Kerberos V4, dissect it as a ticket. */
933
934    case LDAP_AUTH_SASL:
935     mechanism = NULL;
936     if (read_string(a, tree, hf_ldap_message_bind_auth_mechanism, NULL,
937                     &mechanism, ASN1_UNI, ASN1_OTS) != ASN1_ERR_NOERROR)
938       return;
939
940     /*
941      * We need to remember the authentication type and mechanism for this
942      * conversation.
943      *
944      * XXX - actually, we might need to remember more than one
945      * type and mechanism, if you can unbind and rebind with a
946      * different type and/or mechanism.
947      */
948     conversation = find_conversation(&pinfo->src, &pinfo->dst,
949                                      pinfo->ptype, pinfo->srcport,
950                                      pinfo->destport, 0);
951     if (conversation == NULL) {
952       /* We don't yet have a conversation, so create one. */
953       conversation = conversation_new(&pinfo->src, &pinfo->dst,
954                                       pinfo->ptype, pinfo->srcport,
955                                       pinfo->destport, 0);
956     }
957
958     /*
959      * Do we already have a type and mechanism?
960      */
961     auth_info = conversation_get_proto_data(conversation, proto_ldap);
962     if (auth_info == NULL) {
963       /* No.  Attach that information to the conversation, and add
964          it to the list of information structures. */
965       auth_info = g_mem_chunk_alloc(ldap_auth_info_chunk);
966       auth_info->auth_type = tag;
967       auth_info->auth_mech = mechanism;
968       auth_info->first_auth_frame = 0;  /* not known until we see the bind reply */
969       conversation_add_proto_data(conversation, proto_ldap, auth_info);
970       auth_info->next = auth_info_items;
971       auth_info_items = auth_info;
972     } else {
973       /*
974        * Yes.
975        *
976        * If the mechanism in this request is an empty string (which is
977        * returned as a null pointer), use the saved mechanism instead.
978        * Otherwise, if the saved mechanism is an empty string (null),
979        * save this mechanism.
980        */
981       if (mechanism == NULL)
982         mechanism = auth_info->auth_mech;
983       else {
984         if (auth_info->auth_mech == NULL)
985           auth_info->auth_mech = mechanism;
986       }
987     }
988
989     if (a->offset < end) {
990       if (mechanism != NULL && strcmp(mechanism, "GSS-SPNEGO") == 0) {
991         /*
992          * This is a GSS-API token.
993          * Find out how big it is by parsing the ASN.1 header for the
994          * OCTET STREAM that contains it.
995          */
996         token_offset = a->offset;
997         ret = asn1_header_decode(a, &cls, &con, &tag, &def, &length);
998         if (ret != ASN1_ERR_NOERROR) {
999           proto_tree_add_text(tree, a->tvb, token_offset, 0,
1000             "%s: ERROR: Couldn't parse header: %s",
1001             proto_registrar_get_name(hf_ldap_message_bind_auth_credentials),
1002             asn1_err_to_str(ret));
1003           return;
1004         }
1005         if (tree) {
1006           gitem = proto_tree_add_text(tree, tvb, token_offset,
1007             (a->offset + length) - token_offset, "GSS-API Token");
1008           gtree = proto_item_add_subtree(gitem, ett_ldap_gssapi_token);
1009         }
1010         available_length = tvb_length_remaining(tvb, token_offset);
1011         reported_length = tvb_reported_length_remaining(tvb, token_offset);
1012         g_assert(available_length >= 0);
1013         g_assert(reported_length >= 0);
1014         if (available_length > reported_length)
1015           available_length = reported_length;
1016         if ((guint)available_length > length)
1017           available_length = length;
1018         if ((guint)reported_length > length)
1019           reported_length = length;
1020         new_tvb = tvb_new_subset(tvb, a->offset, available_length, reported_length);
1021         call_dissector(gssapi_handle, new_tvb, pinfo, gtree);
1022         a->offset += length;
1023       } else {
1024         if (read_bytestring(a, tree, hf_ldap_message_bind_auth_credentials,
1025                             NULL, NULL, ASN1_UNI, ASN1_OTS) != ASN1_ERR_NOERROR)
1026           return;
1027       }
1028     }
1029     break;
1030   }
1031 }
1032
1033 static void dissect_ldap_response_bind(ASN1_SCK *a, proto_tree *tree,
1034                 int start, guint length, tvbuff_t *tvb, packet_info *pinfo)
1035 {
1036   guint cls, con, tag;
1037   gboolean def;
1038   guint cred_length;
1039   int end;
1040   int ret;
1041   conversation_t *conversation;
1042   ldap_auth_info_t *auth_info;
1043   int token_offset;
1044   gint available_length, reported_length;
1045   tvbuff_t *new_tvb;
1046   proto_item *gitem;
1047   proto_tree *gtree = NULL;
1048
1049   end = start + length;
1050   dissect_ldap_result(a, tree, pinfo);
1051   if (a->offset < end) {
1052     conversation = find_conversation(&pinfo->src, &pinfo->dst,
1053                                      pinfo->ptype, pinfo->srcport,
1054                                      pinfo->destport, 0);
1055     if (conversation != NULL) {
1056       auth_info = conversation_get_proto_data(conversation, proto_ldap);
1057       if (auth_info != NULL) {
1058         switch (auth_info->auth_type) {
1059
1060           /* For Kerberos V4, dissect it as a ticket. */
1061           /* XXX - what about LDAP_AUTH_SIMPLE? */
1062
1063         case LDAP_AUTH_SASL:
1064           /*
1065            * All frames after this are assumed to use a security layer.
1066            *
1067            * XXX - won't work if there's another reply, with the security
1068            * layer, starting in the same TCP segment that ends this
1069            * reply, but as LDAP is a request/response protocol, and
1070            * as the client probably can't start using authentication until
1071            * it gets the bind reply and the server won't send a reply until
1072            * it gets a request, that probably won't happen.
1073            *
1074            * XXX - that assumption is invalid; it's not clear where the
1075            * hell you find out whether there's any security layer.  In
1076            * one capture, we have two GSS-SPNEGO negotiations, both of
1077            * which select MS KRB5, and the only differences in the tokens
1078            * is in the RC4-HMAC ciphertext.  The various
1079            * draft-ietf--cat-sasl-gssapi-NN.txt drafts seem to imply
1080            * that the RFC 2222 spoo with the bitmask and maximum
1081            * output message size stuff is done - but where does that
1082            * stuff show up?  Is it in the ciphertext, which means it's
1083            * presumably encrypted?
1084            *
1085            * Grrr.  We have to do a gross heuristic, checking whether the
1086            * putative LDAP message begins with 0x00 or not, making the
1087            * assumption that we won't have more than 2^24 bytes of
1088            * encapsulated stuff.
1089            */
1090           auth_info->first_auth_frame = pinfo->fd->num + 1;
1091           if (auth_info->auth_mech != NULL &&
1092               strcmp(auth_info->auth_mech, "GSS-SPNEGO") == 0) {
1093             /*
1094              * This is a GSS-API token.
1095              * Find out how big it is by parsing the ASN.1 header for the
1096              * OCTET STREAM that contains it.
1097              */
1098             token_offset = a->offset;
1099             ret = asn1_header_decode(a, &cls, &con, &tag, &def, &cred_length);
1100             if (ret != ASN1_ERR_NOERROR) {
1101               proto_tree_add_text(tree, a->tvb, token_offset, 0,
1102                 "%s: ERROR: Couldn't parse header: %s",
1103                 proto_registrar_get_name(hf_ldap_message_bind_auth_credentials),
1104                 asn1_err_to_str(ret));
1105               return;
1106             }
1107             if (tree) {
1108               gitem = proto_tree_add_text(tree, tvb, token_offset,
1109                 (a->offset + cred_length) - token_offset, "GSS-API Token");
1110               gtree = proto_item_add_subtree(gitem, ett_ldap_gssapi_token);
1111             }
1112             available_length = tvb_length_remaining(tvb, token_offset);
1113             reported_length = tvb_reported_length_remaining(tvb, token_offset);
1114             g_assert(available_length >= 0);
1115             g_assert(reported_length >= 0);
1116             if (available_length > reported_length)
1117               available_length = reported_length;
1118             if ((guint)available_length > cred_length)
1119               available_length = cred_length;
1120             if ((guint)reported_length > cred_length)
1121               reported_length = cred_length;
1122             new_tvb = tvb_new_subset(tvb, a->offset, available_length, reported_length);
1123             call_dissector(gssapi_handle, new_tvb, pinfo, gtree);
1124             a->offset += cred_length;
1125           } else {
1126             if (read_bytestring(a, tree, hf_ldap_message_bind_server_credentials,
1127                                 NULL, NULL, ASN1_UNI, ASN1_OTS) != ASN1_ERR_NOERROR)
1128               return;
1129           }
1130           break;
1131
1132         default:
1133           if (read_bytestring(a, tree, hf_ldap_message_bind_server_credentials,
1134                               NULL, NULL, ASN1_CTX, 7) != ASN1_ERR_NOERROR)
1135             return;
1136           break;
1137         }
1138       } else {
1139         if (read_bytestring(a, tree, hf_ldap_message_bind_server_credentials,
1140                             NULL, NULL, ASN1_CTX, 7) != ASN1_ERR_NOERROR)
1141           return;
1142       }
1143     } else {
1144       if (read_bytestring(a, tree, hf_ldap_message_bind_server_credentials,
1145                           NULL, NULL, ASN1_CTX, 7) != ASN1_ERR_NOERROR)
1146         return;
1147     }
1148   }
1149 }
1150
1151 static void dissect_ldap_request_search(ASN1_SCK *a, proto_tree *tree, packet_info *pinfo)
1152 {
1153   guint seq_length;
1154   int end;
1155   int ret;
1156   char *s = NULL;
1157
1158   if (read_string(a, tree, hf_ldap_message_search_base, 0, &s, ASN1_UNI, ASN1_OTS) != ASN1_ERR_NOERROR)
1159     return;
1160
1161   if (check_col(pinfo->cinfo, COL_INFO))
1162     col_append_fstr(pinfo->cinfo, COL_INFO, ", Base DN=%s", s != NULL ? s : "(null)");
1163   g_free(s);
1164
1165   if (read_integer(a, tree, hf_ldap_message_search_scope, 0, 0, ASN1_ENUM) != ASN1_ERR_NOERROR)
1166     return;
1167   if (read_integer(a, tree, hf_ldap_message_search_deref, 0, 0, ASN1_ENUM) != ASN1_ERR_NOERROR)
1168     return;
1169   if (read_integer(a, tree, hf_ldap_message_search_sizeLimit, 0, 0, ASN1_INT) != ASN1_ERR_NOERROR)
1170     return;
1171   if (read_integer(a, tree, hf_ldap_message_search_timeLimit, 0, 0, ASN1_INT) != ASN1_ERR_NOERROR)
1172     return;
1173   if (read_boolean(a, tree, hf_ldap_message_search_typesOnly, 0, 0) != ASN1_ERR_NOERROR)
1174     return;
1175   if (!read_filter(a, tree, hf_ldap_message_search_filter))
1176     return;
1177   ret = read_sequence(a, &seq_length);
1178   if (ret != ASN1_ERR_NOERROR) {
1179     if (tree) {
1180       proto_tree_add_text(tree, a->tvb, a->offset, 0,
1181           "ERROR: Couldn't parse LDAP attribute sequence header: %s",
1182           asn1_err_to_str(ret));
1183     }
1184     return;
1185   }
1186   end = a->offset + seq_length;
1187   while (a->offset < end) {
1188     if (read_string(a, tree, hf_ldap_message_attribute, 0, 0, ASN1_UNI,
1189                     ASN1_OTS) != ASN1_ERR_NOERROR)
1190       return;
1191   }
1192 }
1193
1194 static void dissect_ldap_response_search_entry(ASN1_SCK *a, proto_tree *tree)
1195 {
1196   guint seq_length;
1197   int end_of_sequence;
1198   int ret;
1199
1200   if (read_string(a, tree, hf_ldap_message_dn, 0, 0, ASN1_UNI, ASN1_OTS) != ASN1_ERR_NOERROR)
1201     return;
1202   ret = read_sequence(a, &seq_length);
1203   if (ret != ASN1_ERR_NOERROR) {
1204     if (tree) {
1205       proto_tree_add_text(tree, a->tvb, a->offset, 0,
1206           "ERROR: Couldn't parse search entry response sequence header: %s",
1207           asn1_err_to_str(ret));
1208     }
1209     return;
1210   }
1211
1212   end_of_sequence = a->offset + seq_length;
1213   while (a->offset < end_of_sequence)
1214   {
1215     proto_item *ti;
1216     proto_tree *attr_tree;
1217     guint set_length;
1218     int end_of_set;
1219
1220     ret = read_sequence(a, 0);
1221     if (ret != ASN1_ERR_NOERROR) {
1222       if (tree) {
1223         proto_tree_add_text(tree, a->tvb, a->offset, 0,
1224             "ERROR: Couldn't parse LDAP attribute sequence header: %s",
1225             asn1_err_to_str(ret));
1226       }
1227       return;
1228     }
1229     if (read_string(a, tree, hf_ldap_message_attribute, &ti, 0, ASN1_UNI, ASN1_OTS) != ASN1_ERR_NOERROR)
1230       return;
1231     attr_tree = proto_item_add_subtree(ti, ett_ldap_attribute);
1232
1233     ret = read_set(a, &set_length);
1234     if (ret != ASN1_ERR_NOERROR) {
1235       if (tree) {
1236         proto_tree_add_text(attr_tree, a->tvb, a->offset, 0,
1237             "ERROR: Couldn't parse LDAP value set header: %s",
1238             asn1_err_to_str(ret));
1239       }
1240       return;
1241     }
1242     end_of_set = a->offset + set_length;
1243     while (a->offset < end_of_set) {
1244       if (read_string(a, attr_tree, hf_ldap_message_value, 0, 0, ASN1_UNI,
1245                       ASN1_OTS) != ASN1_ERR_NOERROR)
1246         return;
1247     }
1248   }
1249 }
1250
1251 static void dissect_ldap_response_search_ref(ASN1_SCK *a, proto_tree *tree)
1252 {
1253   read_string(a, tree, hf_ldap_message_search_reference, 0, 0, ASN1_UNI, ASN1_OTS);
1254 }
1255
1256 static void dissect_ldap_request_add(ASN1_SCK *a, proto_tree *tree, packet_info *pinfo)
1257 {
1258   guint seq_length;
1259   int end_of_sequence;
1260   int ret;
1261   char *s = NULL;
1262
1263   if (read_string(a, tree, hf_ldap_message_dn, 0, &s, ASN1_UNI, ASN1_OTS) != ASN1_ERR_NOERROR)
1264     return;
1265
1266   if (check_col(pinfo->cinfo, COL_INFO))
1267     col_append_fstr(pinfo->cinfo, COL_INFO, ", DN=%s", s != NULL ? s : "(null)");
1268   g_free(s);  
1269
1270   ret = read_sequence(a, &seq_length);
1271   if (ret != ASN1_ERR_NOERROR) {
1272     if (tree) {
1273       proto_tree_add_text(tree, a->tvb, a->offset, 0,
1274           "ERROR: Couldn't parse add request sequence header: %s",
1275           asn1_err_to_str(ret));
1276     }
1277     return;
1278   }
1279
1280   end_of_sequence = a->offset + seq_length;
1281   while (a->offset < end_of_sequence)
1282   {
1283     proto_item *ti;
1284     proto_tree *attr_tree;
1285     guint set_length;
1286     int end_of_set;
1287
1288     ret = read_sequence(a, 0);
1289     if (ret != ASN1_ERR_NOERROR) {
1290       if (tree) {
1291         proto_tree_add_text(tree, a->tvb, a->offset, 0,
1292             "ERROR: Couldn't parse LDAP attribute sequence header: %s",
1293             asn1_err_to_str(ret));
1294       }
1295       return;
1296     }
1297     if (read_string(a, tree, hf_ldap_message_attribute, &ti, 0, ASN1_UNI,
1298                     ASN1_OTS) != ASN1_ERR_NOERROR)
1299       return;
1300     attr_tree = proto_item_add_subtree(ti, ett_ldap_attribute);
1301
1302     ret = read_set(a, &set_length);
1303     if (ret != ASN1_ERR_NOERROR) {
1304       if (tree) {
1305         proto_tree_add_text(attr_tree, a->tvb, a->offset, 0,
1306             "ERROR: Couldn't parse LDAP value set header: %s",
1307             asn1_err_to_str(ret));
1308       }
1309       return;
1310     }
1311     end_of_set = a->offset + set_length;
1312     while (a->offset < end_of_set) {
1313       if (read_string(a, attr_tree, hf_ldap_message_value, 0, 0, ASN1_UNI, ASN1_OTS) != ASN1_ERR_NOERROR)
1314         return;
1315     }
1316   }
1317 }
1318
1319 static void dissect_ldap_request_delete(ASN1_SCK *a, proto_tree *tree,
1320                 int start, guint length)
1321 {
1322   read_string_value(a, tree, hf_ldap_message_dn, NULL, NULL, start, length);
1323 }
1324
1325 static void dissect_ldap_request_modifyrdn(ASN1_SCK *a, proto_tree *tree,
1326                 guint length)
1327 {
1328   int start = a->offset;
1329
1330   if (read_string(a, tree, hf_ldap_message_dn, 0, 0, ASN1_UNI, ASN1_OTS) != ASN1_ERR_NOERROR)
1331     return;
1332   if (read_string(a, tree, hf_ldap_message_modrdn_name, 0, 0, ASN1_UNI, ASN1_OTS) != ASN1_ERR_NOERROR)
1333     return;
1334   if (read_boolean(a, tree, hf_ldap_message_modrdn_delete, 0, 0) != ASN1_ERR_NOERROR)
1335     return;
1336
1337   if (a->offset < (int) (start + length)) {
1338     /* LDAP V3 Modify DN operation, with newSuperior */
1339     /*      "newSuperior     [0] LDAPDN OPTIONAL" (0x80) */
1340     if (read_string(a, tree, hf_ldap_message_modrdn_superior, 0, 0, ASN1_CTX, 0) != ASN1_ERR_NOERROR)
1341       return;
1342   }
1343 }
1344
1345 static void dissect_ldap_request_compare(ASN1_SCK *a, proto_tree *tree)
1346 {
1347   int start;
1348   int length;
1349   char *string1 = NULL;
1350   char *string2 = NULL;
1351   char *s1, *s2;
1352   char *compare;
1353   int ret;
1354
1355   if (read_string(a, tree, hf_ldap_message_dn, 0, 0, ASN1_UNI, ASN1_OTS) != ASN1_ERR_NOERROR)
1356     return;
1357   ret = read_sequence(a, 0);
1358   if (ret != ASN1_ERR_NOERROR) {
1359     if (tree) {
1360       proto_tree_add_text(tree, a->tvb, a->offset, 0,
1361           "ERROR: Couldn't parse compare request sequence header: %s",
1362           asn1_err_to_str(ret));
1363     }
1364     return;
1365   }
1366
1367   start = a->offset;
1368   ret = read_string(a, 0, -1, 0, &string1, ASN1_UNI, ASN1_OTS);
1369   if (ret != ASN1_ERR_NOERROR) {
1370     if (tree) {
1371       proto_tree_add_text(tree, a->tvb, start, 0,
1372         "ERROR: Couldn't parse compare type: %s", asn1_err_to_str(ret));
1373     }
1374     return;
1375   }
1376   ret = read_string(a, 0, -1, 0, &string2, ASN1_UNI, ASN1_OTS);
1377   if (ret != ASN1_ERR_NOERROR) {
1378     if (tree) {
1379       proto_tree_add_text(tree, a->tvb, start, 0,
1380         "ERROR: Couldn't parse compare value: %s", asn1_err_to_str(ret));
1381     }
1382     return;
1383   }
1384
1385   s1 = (string1 == NULL) ? "(null)" : string1;
1386   s2 = (string2 == NULL) ? "(null)" : string2;
1387   length = 2 + strlen(s1) + strlen(s2);
1388   compare = g_malloc0(length);
1389   snprintf(compare, length, "%s=%s", s1, s2);
1390   proto_tree_add_string(tree, hf_ldap_message_compare, a->tvb, start,
1391       a->offset-start, compare);
1392
1393   g_free(string1);
1394   g_free(string2);
1395   g_free(compare);
1396
1397   return;
1398 }
1399
1400 static void dissect_ldap_request_modify(ASN1_SCK *a, proto_tree *tree)
1401 {
1402   guint seq_length;
1403   int end_of_sequence;
1404   int ret;
1405
1406   if (read_string(a, tree, hf_ldap_message_dn, 0, 0, ASN1_UNI, ASN1_OTS) != ASN1_ERR_NOERROR)
1407     return;
1408   ret = read_sequence(a, &seq_length);
1409   if (ret != ASN1_ERR_NOERROR) {
1410     if (tree) {
1411       proto_tree_add_text(tree, a->tvb, a->offset, 0,
1412           "ERROR: Couldn't parse modify request sequence header: %s",
1413           asn1_err_to_str(ret));
1414     }
1415     return;
1416   }
1417   end_of_sequence = a->offset + seq_length;
1418   while (a->offset < end_of_sequence)
1419   {
1420     proto_item *ti;
1421     proto_tree *attr_tree;
1422     guint set_length;
1423     int end_of_set;
1424     guint operation;
1425
1426     ret = read_sequence(a, 0);
1427     if (ret != ASN1_ERR_NOERROR) {
1428       if (tree) {
1429         proto_tree_add_text(tree, a->tvb, a->offset, 0,
1430             "ERROR: Couldn't parse modify request item sequence header: %s",
1431             asn1_err_to_str(ret));
1432       }
1433       return;
1434     }
1435     ret = read_integer(a, 0, -1, 0, &operation, ASN1_ENUM);
1436     if (ret != ASN1_ERR_NOERROR) {
1437       if (tree) {
1438         proto_tree_add_text(tree, a->tvb, a->offset, 0,
1439           "ERROR: Couldn't parse modify operation: %s",
1440           asn1_err_to_str(ret));
1441         return;
1442       }
1443     }
1444     ret = read_sequence(a, 0);
1445     if (ret != ASN1_ERR_NOERROR) {
1446       if (tree) {
1447         proto_tree_add_text(tree, a->tvb, a->offset, 0,
1448             "ERROR: Couldn't parse modify request operation sequence header: %s",
1449             asn1_err_to_str(ret));
1450       }
1451       return;
1452     }
1453
1454     switch (operation)
1455     {
1456      case LDAP_MOD_ADD:
1457       if (read_string(a, tree, hf_ldap_message_modify_add, &ti, 0, ASN1_UNI,
1458                       ASN1_OTS) != ASN1_ERR_NOERROR)
1459         return;
1460       break;
1461
1462      case LDAP_MOD_REPLACE:
1463       if (read_string(a, tree, hf_ldap_message_modify_replace, &ti, 0,
1464                       ASN1_UNI, ASN1_OTS) != ASN1_ERR_NOERROR)
1465         return;
1466       break;
1467
1468      case LDAP_MOD_DELETE:
1469       if (read_string(a, tree, hf_ldap_message_modify_delete, &ti, 0,
1470                       ASN1_UNI, ASN1_OTS) != ASN1_ERR_NOERROR)
1471         return;
1472       break;
1473
1474      default:
1475        proto_tree_add_text(tree, a->tvb, a->offset, 0,
1476             "Unknown LDAP modify operation (%u)", operation);
1477        return;
1478     }
1479     attr_tree = proto_item_add_subtree(ti, ett_ldap_attribute);
1480
1481     ret = read_set(a, &set_length);
1482     if (ret != ASN1_ERR_NOERROR) {
1483       if (tree) {
1484         proto_tree_add_text(attr_tree, a->tvb, a->offset, 0,
1485             "ERROR: Couldn't parse LDAP value set header: %s",
1486             asn1_err_to_str(ret));
1487       }
1488       return;
1489     }
1490     end_of_set = a->offset + set_length;
1491     while (a->offset < end_of_set) {
1492       if (read_string(a, attr_tree, hf_ldap_message_value, 0, 0, ASN1_UNI,
1493                       ASN1_OTS) != ASN1_ERR_NOERROR)
1494         return;
1495     }
1496   }
1497 }
1498
1499 static void dissect_ldap_request_abandon(ASN1_SCK *a, proto_tree *tree,
1500                 int start, guint length)
1501 {
1502   read_integer_value(a, tree, hf_ldap_message_abandon_msgid, NULL, NULL,
1503                             start, length);
1504 }
1505
1506 static void
1507 dissect_ldap_message(tvbuff_t *tvb, int offset, packet_info *pinfo,
1508                      proto_tree *ldap_tree, proto_item *ldap_item, gboolean first_time)
1509 {
1510   int message_id_start;
1511   int message_id_length;
1512   guint messageLength;
1513   guint messageId;
1514   int next_offset;
1515   guint protocolOpCls, protocolOpCon, protocolOpTag;
1516   gchar *typestr;
1517   guint opLen;
1518   ASN1_SCK a;
1519   int start;
1520   int ret;
1521
1522   asn1_open(&a, tvb, offset);
1523
1524   ret = read_sequence(&a, &messageLength);
1525   if (ret != ASN1_ERR_NOERROR)
1526   {
1527     if (first_time)
1528     {
1529       if (check_col(pinfo->cinfo, COL_INFO))
1530       {
1531         col_add_fstr(pinfo->cinfo, COL_INFO,
1532                     "Invalid LDAP message (Can't parse sequence header: %s)",
1533                     asn1_err_to_str(ret));
1534       }
1535     }
1536     if (ldap_tree)
1537     {
1538       proto_tree_add_text(ldap_tree, tvb, offset, -1,
1539                           "Invalid LDAP message (Can't parse sequence header: %s)",
1540                           asn1_err_to_str(ret));
1541     }
1542     return;
1543   }
1544
1545   message_id_start = a.offset;
1546   ret = read_integer(&a, 0, hf_ldap_message_id, 0, &messageId, ASN1_INT);
1547   if (ret != ASN1_ERR_NOERROR)
1548   {
1549     if (first_time && check_col(pinfo->cinfo, COL_INFO))
1550       col_add_fstr(pinfo->cinfo, COL_INFO, "Invalid LDAP packet (Can't parse Message ID: %s)",
1551                    asn1_err_to_str(ret));
1552     if (ldap_tree)
1553       proto_tree_add_text(ldap_tree, tvb, message_id_start, 1,
1554                           "Invalid LDAP packet (Can't parse Message ID: %s)",
1555                           asn1_err_to_str(ret));
1556       return;
1557   }
1558   message_id_length = a.offset - message_id_start;
1559
1560   start = a.offset;
1561   asn1_id_decode(&a, &protocolOpCls, &protocolOpCon, &protocolOpTag);
1562   if (protocolOpCls != ASN1_APL)
1563     typestr = "Bad message type (not Application)";
1564   else
1565     typestr = val_to_str(protocolOpTag, msgTypes, "Unknown message type (%u)");
1566
1567   if (first_time)
1568   {
1569     if (check_col(pinfo->cinfo, COL_INFO))
1570       col_add_fstr(pinfo->cinfo, COL_INFO, "MsgId=%u %s",
1571                    messageId, typestr);
1572   }
1573
1574   if (ldap_item)
1575           proto_item_append_text(ldap_item, ", %s", 
1576                                  val_to_str(protocolOpTag, msgTypes,
1577                                             "Unknown message type (%u)"));
1578
1579   if (ldap_tree)
1580   {
1581     proto_tree_add_uint(ldap_tree, hf_ldap_message_id, tvb, message_id_start, message_id_length, messageId);
1582     if (protocolOpCls == ASN1_APL)
1583     {
1584       proto_tree_add_uint(ldap_tree, hf_ldap_message_type, tvb,
1585                           start, a.offset - start, protocolOpTag);
1586     }
1587     else
1588     {
1589       proto_tree_add_text(ldap_tree, tvb, start, a.offset - start,
1590                           "%s", typestr);
1591     }
1592   }
1593   start = a.offset;
1594   if (read_length(&a, ldap_tree, hf_ldap_message_length, &opLen) != ASN1_ERR_NOERROR)
1595     return;
1596
1597   if (protocolOpCls == ASN1_APL)
1598   {
1599     switch (protocolOpTag)
1600     {
1601      case LDAP_REQ_BIND:
1602       dissect_ldap_request_bind(&a, ldap_tree, tvb, pinfo);
1603       break;
1604      case LDAP_REQ_UNBIND:
1605       /* Nothing to dissect */
1606       break;
1607      case LDAP_REQ_SEARCH:
1608       dissect_ldap_request_search(&a, ldap_tree, pinfo);
1609       break;
1610      case LDAP_REQ_MODIFY:
1611       dissect_ldap_request_modify(&a, ldap_tree);
1612       break;
1613      case LDAP_REQ_ADD:
1614       dissect_ldap_request_add(&a, ldap_tree, pinfo);
1615       break;
1616      case LDAP_REQ_DELETE:
1617       dissect_ldap_request_delete(&a, ldap_tree, start, opLen);
1618       break;
1619      case LDAP_REQ_MODRDN:
1620       dissect_ldap_request_modifyrdn(&a, ldap_tree, opLen);
1621       break;
1622      case LDAP_REQ_COMPARE:
1623       dissect_ldap_request_compare(&a, ldap_tree);
1624       break;
1625      case LDAP_REQ_ABANDON:
1626       dissect_ldap_request_abandon(&a, ldap_tree, start, opLen);
1627       break;
1628      case LDAP_RES_BIND:
1629       dissect_ldap_response_bind(&a, ldap_tree, start, opLen, tvb, pinfo);
1630       break;
1631      case LDAP_RES_SEARCH_ENTRY: {
1632             /*
1633              * XXX - this assumes that the LDAP_RES_SEARCH_ENTRY and
1634              * LDAP_RES_SEARCH_RESULT appear in the same frame.
1635              */
1636             guint32 *num_results = p_get_proto_data(pinfo->fd, proto_ldap);
1637
1638             if (!num_results) {
1639                     num_results = g_malloc(sizeof(guint32));
1640                     *num_results = 0;
1641                     p_add_proto_data(pinfo->fd, proto_ldap, num_results);
1642             }
1643
1644             *num_results += 1;
1645             dissect_ldap_response_search_entry(&a, ldap_tree);
1646
1647             break;
1648      }
1649      case LDAP_RES_SEARCH_REF:
1650       dissect_ldap_response_search_ref(&a, ldap_tree);
1651       break;
1652
1653      case LDAP_RES_SEARCH_RESULT: {
1654              guint32 *num_results = p_get_proto_data(pinfo->fd, proto_ldap);
1655
1656              if (num_results) {
1657                      if (check_col(pinfo->cinfo, COL_INFO))
1658                              col_append_fstr(pinfo->cinfo, COL_INFO, ", %d result%s", 
1659                                              *num_results, *num_results == 1 ? "" : "s");
1660                      g_free(num_results);
1661                      p_rem_proto_data(pinfo->fd, proto_ldap);
1662              }
1663
1664              dissect_ldap_result(&a, ldap_tree, pinfo);
1665
1666              break;
1667      }
1668
1669      case LDAP_RES_MODIFY:
1670      case LDAP_RES_ADD:
1671      case LDAP_RES_DELETE:
1672      case LDAP_RES_MODRDN:
1673      case LDAP_RES_COMPARE:
1674         dissect_ldap_result(&a, ldap_tree, pinfo);
1675       break;
1676      default:
1677       if (ldap_tree)
1678       {
1679         proto_tree_add_text(ldap_tree, a.tvb, a.offset, opLen,
1680                             "Unknown LDAP operation (%u)", protocolOpTag);
1681       }
1682       break;
1683     }
1684   }
1685
1686   /*
1687    * XXX - what if "next_offset" is past the offset of the next top-level
1688    * sequence?  Show that as an error?
1689    */
1690   asn1_close(&a, &next_offset); /* XXX - use the new value of next_offset? */
1691 }
1692
1693 static void
1694 dissect_ldap(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
1695 {
1696   int offset = 0;
1697   gboolean first_time = TRUE;
1698   conversation_t *conversation;
1699   ldap_auth_info_t *auth_info = NULL;
1700   gboolean doing_sasl_security = FALSE;
1701   guint length_remaining;
1702   guint32 sasl_length;
1703   guint32 message_data_len;
1704   proto_item *ti = NULL;
1705   proto_tree *ldap_tree = NULL;
1706   ASN1_SCK a;
1707   int ret;
1708   guint messageLength;
1709   int messageOffset;
1710   guint headerLength;
1711   guint length;
1712   gint available_length, reported_length;
1713   int len;
1714   proto_item *gitem = NULL;
1715   proto_tree *gtree = NULL;
1716   tvbuff_t *next_tvb;
1717
1718   /*
1719    * Do we have a conversation for this connection?
1720    */
1721   conversation = find_conversation(&pinfo->src, &pinfo->dst,
1722                                    pinfo->ptype, pinfo->srcport,
1723                                    pinfo->destport, 0);
1724   if (conversation != NULL) {
1725     /*
1726      * Yes - do we have any authentication mechanism for it?
1727      */
1728     auth_info = conversation_get_proto_data(conversation, proto_ldap);
1729     if (auth_info != NULL) {
1730       /*
1731        * Yes - what's the authentication type?
1732        */
1733       switch (auth_info->auth_type) {
1734
1735       case LDAP_AUTH_SASL:
1736         /*
1737          * It's SASL; are we using a security layer?
1738          */
1739         if (auth_info->first_auth_frame != 0 &&
1740             pinfo->fd->num >= auth_info->first_auth_frame)
1741           doing_sasl_security = TRUE;   /* yes */
1742       }
1743     }
1744   }
1745
1746   while (tvb_reported_length_remaining(tvb, offset) > 0) {
1747     /*
1748      * This will throw an exception if we don't have any data left.
1749      * That's what we want.  (See "tcp_dissect_pdus()", which is
1750      * similar, but doesn't have to deal with the SASL issues.
1751      * XXX - can we make "tcp_dissect_pdus()" provide enough information
1752      * to the "get_pdu_len" routine so that we could have one dealing
1753      * with the SASL issues, have that routine deal with SASL and
1754      * ASN.1, and just use "tcp_dissect_pdus()"?)
1755      */
1756     length_remaining = tvb_ensure_length_remaining(tvb, offset);
1757
1758     /*
1759      * Might we be doing a SASL security layer and, if so, *are* we doing
1760      * one?
1761      *
1762      * Just because we've seen a bind reply for SASL, that doesn't mean
1763      * that we're using a SASL security layer; I've seen captures in
1764      * which some SASL negotiations lead to a security layer being used
1765      * and other negotiations don't, and it's not obvious what's different
1766      * in the two negotiations.  Therefore, we assume that if the first
1767      * byte is 0, it's a length for a SASL security layer (that way, we
1768      * never reassemble more than 16 megabytes, protecting us from
1769      * chewing up *too* much memory), and otherwise that it's an LDAP
1770      * message (actually, if it's an LDAP message it should begin with 0x30,
1771      * but we want to parse garbage as LDAP messages rather than really
1772      * huge lengths).
1773      */
1774     if (doing_sasl_security && tvb_get_guint8(tvb, offset) == 0) {
1775       /*
1776        * Yes.  The frame begins with a 4-byte big-endian length.
1777        * Can we do reassembly?
1778        */
1779       if (ldap_desegment && pinfo->can_desegment) {
1780         /*
1781          * Yes - is the SASL length split across segment boundaries?
1782          */
1783         if (length_remaining < 4) {
1784           /*
1785            * Yes.  Tell the TCP dissector where the data for this message
1786            * starts in the data it handed us, and how many more bytes we
1787            * need, and return.
1788            */
1789           pinfo->desegment_offset = offset;
1790           pinfo->desegment_len = 4 - length_remaining;
1791           return;
1792         }
1793       }
1794
1795       /*
1796        * Get the SASL length, which is the length of data in the buffer
1797        * following the length (i.e., it's 4 less than the total length).
1798        *
1799        * XXX - do we need to reassemble buffers?  For now, we
1800        * assume that each LDAP message is entirely contained within
1801        * a buffer.
1802        */
1803       sasl_length = tvb_get_ntohl(tvb, offset);
1804       message_data_len = sasl_length + 4;
1805       if (message_data_len < 4) {
1806         /*
1807          * The message length was probably so large that the total length
1808          * overflowed.
1809          *
1810          * Report this as an error.
1811          */
1812         show_reported_bounds_error(tvb, pinfo, tree);
1813         return;
1814       }
1815
1816       /*
1817        * Can we do reassembly?
1818        */
1819       if (ldap_desegment && pinfo->can_desegment) {
1820         /*
1821          * Yes - is the buffer split across segment boundaries?
1822          */
1823         if (length_remaining < message_data_len) {
1824           /*
1825            * Yes.  Tell the TCP dissector where the data for this message
1826            * starts in the data it handed us, and how many more bytes we
1827            * need, and return.
1828            */
1829           pinfo->desegment_offset = offset;
1830           pinfo->desegment_len = message_data_len - length_remaining;
1831           return;
1832         }
1833       }
1834
1835       /*
1836        * Construct a tvbuff containing the amount of the payload we have
1837        * available.  Make its reported length the amount of data in the PDU.
1838        *
1839        * XXX - if reassembly isn't enabled. the subdissector will throw a
1840        * BoundsError exception, rather than a ReportedBoundsError exception.
1841        * We really want a tvbuff where the length is "length", the reported
1842        * length is "plen", and the "if the snapshot length were infinite"
1843        * length is the minimum of the reported length of the tvbuff handed
1844        * to us and "plen", with a new type of exception thrown if the offset
1845        * is within the reported length but beyond that third length, with
1846        * that exception getting the "Unreassembled Packet" error.
1847        */
1848       length = length_remaining;
1849       if (length > message_data_len)
1850         length = message_data_len;
1851       next_tvb = tvb_new_subset(tvb, offset, length, message_data_len);
1852
1853       /*
1854        * If this is the first PDU, set the Protocol column and clear the
1855        * Info column.
1856        */
1857       if (first_time)
1858       {
1859         if (check_col(pinfo->cinfo, COL_PROTOCOL))
1860           col_set_str(pinfo->cinfo, COL_PROTOCOL, "LDAP");
1861         if (check_col(pinfo->cinfo, COL_INFO))
1862           col_clear(pinfo->cinfo, COL_INFO);
1863       }
1864
1865       if (tree)
1866       {
1867         ti = proto_tree_add_item(tree, proto_ldap, next_tvb, 0, -1, FALSE);
1868         ldap_tree = proto_item_add_subtree(ti, ett_ldap);
1869
1870         proto_tree_add_uint(ldap_tree, hf_ldap_sasl_buffer_length, tvb, 0, 4,
1871                             sasl_length);
1872       }
1873
1874       if (auth_info->auth_mech != NULL &&
1875           strcmp(auth_info->auth_mech, "GSS-SPNEGO") == 0) {
1876           /*
1877            * This is GSS-API (using SPNEGO, but we should be done with
1878            * the negotiation by now).
1879            *
1880            * Dissect the GSS_Wrap() token; it'll return the length of
1881            * the token, from which we compute the offset in the tvbuff at
1882            * which the plaintext data, i.e. the LDAP message, begins.
1883            */
1884           available_length = tvb_length_remaining(tvb, 4);
1885           reported_length = tvb_reported_length_remaining(tvb, 4);
1886           g_assert(available_length >= 0);
1887           g_assert(reported_length >= 0);
1888           if (available_length > reported_length)
1889             available_length = reported_length;
1890           if ((guint)available_length > sasl_length - 4)
1891             available_length = sasl_length - 4;
1892           if ((guint)reported_length > sasl_length - 4)
1893             reported_length = sasl_length - 4;
1894           next_tvb = tvb_new_subset(tvb, 4, available_length, reported_length);
1895           if (tree)
1896           {
1897             gitem = proto_tree_add_text(ldap_tree, next_tvb, 0, -1, "GSS-API Token");
1898             gtree = proto_item_add_subtree(gitem, ett_ldap_gssapi_token);
1899           }
1900           len = call_dissector(gssapi_wrap_handle, next_tvb, pinfo, gtree);
1901           g_assert(len != 0);   /* GSS_Wrap() dissectors can't reject data */
1902           if (gitem != NULL)
1903               proto_item_set_len(gitem, len);
1904
1905           /*
1906            * Now dissect the LDAP message.
1907            */
1908           dissect_ldap_message(tvb, 4 + len, pinfo, ldap_tree, ti, first_time);
1909       } else {
1910         /*
1911          * We don't know how to handle other authentication mechanisms
1912          * yet, so just put in an entry for the SASL buffer.
1913          */
1914         proto_tree_add_text(ldap_tree, tvb, 4, -1, "SASL buffer");
1915       }
1916       offset += message_data_len;
1917     } else {
1918       /*
1919        * No, we're not doing a SASL security layer.  The frame begins
1920        * with a "Sequence Of" header.
1921        * Can we do reassembly?
1922        */
1923       if (ldap_desegment && pinfo->can_desegment) {
1924         /*
1925          * Yes - is the "Sequence Of" header split across segment
1926          * boundaries?  We require at least 6 bytes for the header
1927          * which allows for a 4 byte length (ASN.1 BER).
1928          */
1929         if (length_remaining < 6) {
1930           pinfo->desegment_offset = offset;
1931           pinfo->desegment_len = 6 - length_remaining;
1932           return;
1933         }
1934       }
1935
1936       /*
1937        * OK, try to read the "Sequence Of" header; this gets the total
1938        * length of the LDAP message.
1939        */
1940       asn1_open(&a, tvb, offset);
1941       ret = read_sequence(&a, &messageLength);
1942       asn1_close(&a, &messageOffset);
1943
1944       if (ret == ASN1_ERR_NOERROR) {
1945         /*
1946          * Add the length of the "Sequence Of" header to the message
1947          * length.
1948          */
1949         headerLength = messageOffset - offset;
1950         messageLength += headerLength;
1951         if (messageLength < headerLength) {
1952           /*
1953            * The message length was probably so large that the total length
1954            * overflowed.
1955            *
1956            * Report this as an error.
1957            */
1958           show_reported_bounds_error(tvb, pinfo, tree);
1959           return;
1960         }
1961       } else {
1962         /*
1963          * We couldn't parse the header; just make it the amount of data
1964          * remaining in the tvbuff, so we'll give up on this segment
1965          * after attempting to parse the message - there's nothing more
1966          * we can do.  "dissect_ldap_message()" will display the error.
1967          */
1968         messageLength = length_remaining;
1969       }
1970
1971       /*
1972        * Can we do reassembly?
1973        */
1974       if (ldap_desegment && pinfo->can_desegment) {
1975         /*
1976          * Yes - is the message split across segment boundaries?
1977          */
1978         if (length_remaining < messageLength) {
1979           /*
1980            * Yes.  Tell the TCP dissector where the data for this message
1981            * starts in the data it handed us, and how many more bytes
1982            * we need, and return.
1983            */
1984           pinfo->desegment_offset = offset;
1985           pinfo->desegment_len = messageLength - length_remaining;
1986           return;
1987         }
1988       }
1989
1990       /*
1991        * If this is the first PDU, set the Protocol column and clear the
1992        * Info column.
1993        */
1994       if (first_time) {
1995         if (check_col(pinfo->cinfo, COL_PROTOCOL))
1996           col_set_str(pinfo->cinfo, COL_PROTOCOL, "LDAP");
1997         if (check_col(pinfo->cinfo, COL_INFO))
1998           col_clear(pinfo->cinfo, COL_INFO);
1999       }
2000
2001       /*
2002        * Construct a tvbuff containing the amount of the payload we have
2003        * available.  Make its reported length the amount of data in the
2004        * LDAP message.
2005        *
2006        * XXX - if reassembly isn't enabled. the subdissector will throw a
2007        * BoundsError exception, rather than a ReportedBoundsError exception.
2008        * We really want a tvbuff where the length is "length", the reported
2009        * length is "plen", and the "if the snapshot length were infinite"
2010        * length is the minimum of the reported length of the tvbuff handed
2011        * to us and "plen", with a new type of exception thrown if the offset
2012        * is within the reported length but beyond that third length, with
2013        * that exception getting the "Unreassembled Packet" error.
2014        */
2015       length = length_remaining;
2016       if (length > messageLength)
2017         length = messageLength;
2018       next_tvb = tvb_new_subset(tvb, offset, length, messageLength);
2019
2020       /*
2021        * Now dissect the LDAP message.
2022        */
2023       if (tree) {
2024         ti = proto_tree_add_item(tree, proto_ldap, next_tvb, 0, -1, FALSE);
2025         ldap_tree = proto_item_add_subtree(ti, ett_ldap);
2026       } else
2027         ldap_tree = NULL;
2028       dissect_ldap_message(next_tvb, 0, pinfo, ldap_tree, ti, first_time);
2029
2030       offset += messageLength;
2031     }
2032
2033     first_time = FALSE;
2034   }
2035 }
2036
2037 static void
2038 ldap_reinit(void)
2039 {
2040   ldap_auth_info_t *auth_info;
2041
2042   /* Free up saved authentication mechanism strings */
2043   for (auth_info = auth_info_items; auth_info != NULL;
2044        auth_info = auth_info->next) {
2045     if (auth_info->auth_mech != NULL)
2046       g_free(auth_info->auth_mech);
2047   }
2048
2049   if (ldap_auth_info_chunk != NULL)
2050     g_mem_chunk_destroy(ldap_auth_info_chunk);
2051
2052   auth_info_items = NULL;
2053
2054   ldap_auth_info_chunk = g_mem_chunk_new("ldap_auth_info_chunk",
2055                 sizeof(ldap_auth_info_t),
2056                 ldap_auth_info_chunk_count * sizeof(ldap_auth_info_t),
2057                 G_ALLOC_ONLY);
2058 }
2059
2060 void
2061 proto_register_ldap(void)
2062 {
2063   static value_string auth_types[] = {
2064     {LDAP_AUTH_SIMPLE,    "Simple"},
2065     {LDAP_AUTH_KRBV4LDAP, "Kerberos V4 to the LDAP server"},
2066     {LDAP_AUTH_KRBV4DSA,  "Kerberos V4 to the DSA"},
2067     {LDAP_AUTH_SASL,      "SASL"},
2068     {0, NULL},
2069   };
2070
2071   static value_string search_scope[] = {
2072     {0x00, "Base"},
2073     {0x01, "Single"},
2074     {0x02, "Subtree"},
2075     {0x00, NULL},
2076   };
2077
2078   static value_string search_dereference[] = {
2079     {0x00, "Never"},
2080     {0x01, "Searching"},
2081     {0x02, "Base Object"},
2082     {0x03, "Always"},
2083     {0x00, NULL},
2084   };
2085
2086   static hf_register_info hf[] = {
2087     { &hf_ldap_sasl_buffer_length,
2088       { "SASL Buffer Length",   "ldap.sasl_buffer_length",
2089         FT_UINT32, BASE_DEC, NULL, 0x0,
2090         "SASL Buffer Length", HFILL }},
2091
2092     { &hf_ldap_length,
2093       { "Length",               "ldap.length",
2094         FT_UINT32, BASE_DEC, NULL, 0x0,
2095         "LDAP Length", HFILL }},
2096
2097     { &hf_ldap_message_id,
2098       { "Message Id",           "ldap.message_id",
2099         FT_UINT32, BASE_DEC, NULL, 0x0,
2100         "LDAP Message Id", HFILL }},
2101     { &hf_ldap_message_type,
2102       { "Message Type",         "ldap.message_type",
2103         FT_UINT8, BASE_HEX, &msgTypes, 0x0,
2104         "LDAP Message Type", HFILL }},
2105     { &hf_ldap_message_length,
2106       { "Message Length",               "ldap.message_length",
2107         FT_UINT32, BASE_DEC, NULL, 0x0,
2108         "LDAP Message Length", HFILL }},
2109
2110     { &hf_ldap_message_result,
2111       { "Result Code",          "ldap.result.code",
2112         FT_UINT8, BASE_HEX, result_codes, 0x0,
2113         "LDAP Result Code", HFILL }},
2114     { &hf_ldap_message_result_matcheddn,
2115       { "Matched DN",           "ldap.result.matcheddn",
2116         FT_STRING, BASE_NONE, NULL, 0x0,
2117         "LDAP Result Matched DN", HFILL }},
2118     { &hf_ldap_message_result_errormsg,
2119       { "Error Message",                "ldap.result.errormsg",
2120         FT_STRING, BASE_NONE, NULL, 0x0,
2121         "LDAP Result Error Message", HFILL }},
2122     { &hf_ldap_message_result_referral,
2123       { "Referral",             "ldap.result.referral",
2124         FT_STRING, BASE_NONE, NULL, 0x0,
2125         "LDAP Result Referral URL", HFILL }},
2126
2127     { &hf_ldap_message_bind_version,
2128       { "Version",              "ldap.bind.version",
2129         FT_UINT32, BASE_DEC, NULL, 0x0,
2130         "LDAP Bind Version", HFILL }},
2131     { &hf_ldap_message_bind_dn,
2132       { "DN",                   "ldap.bind.dn",
2133         FT_STRING, BASE_NONE, NULL, 0x0,
2134         "LDAP Bind Distinguished Name", HFILL }},
2135     { &hf_ldap_message_bind_auth,
2136       { "Auth Type",            "ldap.bind.auth_type",
2137         FT_UINT8, BASE_HEX, auth_types, 0x0,
2138         "LDAP Bind Auth Type", HFILL }},
2139     { &hf_ldap_message_bind_auth_password,
2140       { "Password",             "ldap.bind.password",
2141         FT_STRING, BASE_NONE, NULL, 0x0,
2142         "LDAP Bind Password", HFILL }},
2143     { &hf_ldap_message_bind_auth_mechanism,
2144       { "Mechanism",            "ldap.bind.mechanism",
2145         FT_STRING, BASE_NONE, NULL, 0x0,
2146         "LDAP Bind Mechanism", HFILL }},
2147     { &hf_ldap_message_bind_auth_credentials,
2148       { "Credentials",          "ldap.bind.credentials",
2149         FT_BYTES, BASE_NONE, NULL, 0x0,
2150         "LDAP Bind Credentials", HFILL }},
2151     { &hf_ldap_message_bind_server_credentials,
2152       { "Server Credentials",   "ldap.bind.server_credentials",
2153         FT_BYTES, BASE_NONE, NULL, 0x0,
2154         "LDAP Bind Server Credentials", HFILL }},
2155
2156     { &hf_ldap_message_search_base,
2157       { "Base DN",              "ldap.search.basedn",
2158         FT_STRING, BASE_NONE, NULL, 0x0,
2159         "LDAP Search Base Distinguished Name", HFILL }},
2160     { &hf_ldap_message_search_scope,
2161       { "Scope",                        "ldap.search.scope",
2162         FT_UINT8, BASE_HEX, search_scope, 0x0,
2163         "LDAP Search Scope", HFILL }},
2164     { &hf_ldap_message_search_deref,
2165       { "Dereference",          "ldap.search.dereference",
2166         FT_UINT8, BASE_HEX, search_dereference, 0x0,
2167         "LDAP Search Dereference", HFILL }},
2168     { &hf_ldap_message_search_sizeLimit,
2169       { "Size Limit",           "ldap.search.sizelimit",
2170         FT_UINT32, BASE_DEC, NULL, 0x0,
2171         "LDAP Search Size Limit", HFILL }},
2172     { &hf_ldap_message_search_timeLimit,
2173       { "Time Limit",           "ldap.search.timelimit",
2174         FT_UINT32, BASE_DEC, NULL, 0x0,
2175         "LDAP Search Time Limit", HFILL }},
2176     { &hf_ldap_message_search_typesOnly,
2177       { "Attributes Only",      "ldap.search.typesonly",
2178         FT_BOOLEAN, BASE_NONE, NULL, 0x0,
2179         "LDAP Search Attributes Only", HFILL }},
2180     { &hf_ldap_message_search_filter,
2181       { "Filter",               "ldap.search.filter",
2182         FT_STRING, BASE_NONE, NULL, 0x0,
2183         "LDAP Search Filter", HFILL }},
2184     { &hf_ldap_message_search_reference,
2185       { "Reference URL",        "ldap.search.reference",
2186         FT_STRING, BASE_NONE, NULL, 0x0,
2187         "LDAP Search Reference URL", HFILL }},
2188     { &hf_ldap_message_dn,
2189       { "Distinguished Name",   "ldap.dn",
2190         FT_STRING, BASE_NONE, NULL, 0x0,
2191         "LDAP Distinguished Name", HFILL }},
2192     { &hf_ldap_message_attribute,
2193       { "Attribute",            "ldap.attribute",
2194         FT_STRING, BASE_NONE, NULL, 0x0,
2195         "LDAP Attribute", HFILL }},
2196     /*
2197      * XXX - not all LDAP values are text strings; we'd need a file
2198      * describing which values (by name) are text strings and which are
2199      * binary.
2200      *
2201      * Some values that are, at least in Microsoft's schema, binary
2202      * are:
2203      *
2204      *  invocationId
2205      *  nTSecurityDescriptor
2206      *  objectGUID
2207      */
2208     { &hf_ldap_message_value,
2209       { "Value",                "ldap.value",
2210         FT_STRING, BASE_NONE, NULL, 0x0,
2211         "LDAP Value", HFILL }},
2212
2213     { &hf_ldap_message_modrdn_name,
2214       { "New Name",             "ldap.modrdn.name",
2215         FT_STRING, BASE_NONE, NULL, 0x0,
2216         "LDAP New Name", HFILL }},
2217     { &hf_ldap_message_modrdn_delete,
2218       { "Delete Values",        "ldap.modrdn.delete",
2219         FT_BOOLEAN, BASE_NONE, NULL, 0x0,
2220         "LDAP Modify RDN - Delete original values", HFILL }},
2221     { &hf_ldap_message_modrdn_superior,
2222       { "New Location",         "ldap.modrdn.superior",
2223         FT_STRING, BASE_NONE, NULL, 0x0,
2224         "LDAP Modify RDN - New Location", HFILL }},
2225
2226     { &hf_ldap_message_compare,
2227       { "Test",         "ldap.compare.test",
2228         FT_STRING, BASE_NONE, NULL, 0x0,
2229         "LDAP Compare Test", HFILL }},
2230
2231     { &hf_ldap_message_modify_add,
2232       { "Add",                  "ldap.modify.add",
2233         FT_STRING, BASE_NONE, NULL, 0x0,
2234         "LDAP Add", HFILL }},
2235     { &hf_ldap_message_modify_replace,
2236       { "Replace",              "ldap.modify.replace",
2237         FT_STRING, BASE_NONE, NULL, 0x0,
2238         "LDAP Replace", HFILL }},
2239     { &hf_ldap_message_modify_delete,
2240       { "Delete",               "ldap.modify.delete",
2241         FT_STRING, BASE_NONE, NULL, 0x0,
2242         "LDAP Delete", HFILL }},
2243
2244     { &hf_ldap_message_abandon_msgid,
2245       { "Abandon Msg Id",       "ldap.abandon.msgid",
2246         FT_UINT32, BASE_DEC, NULL, 0x0,
2247         "LDAP Abandon Msg Id", HFILL }},
2248   };
2249
2250   static gint *ett[] = {
2251     &ett_ldap,
2252     &ett_ldap_gssapi_token,
2253     &ett_ldap_referrals,
2254     &ett_ldap_attribute
2255   };
2256   module_t *ldap_module;
2257
2258   proto_ldap = proto_register_protocol("Lightweight Directory Access Protocol",
2259                                        "LDAP", "ldap");
2260   proto_register_field_array(proto_ldap, hf, array_length(hf));
2261   proto_register_subtree_array(ett, array_length(ett));
2262
2263   ldap_module = prefs_register_protocol(proto_ldap, NULL);
2264   prefs_register_bool_preference(ldap_module, "desegment_ldap_messages",
2265     "Desegment all LDAP messages spanning multiple TCP segments",
2266     "Whether the LDAP dissector should desegment all messages spanning multiple TCP segments",
2267     &ldap_desegment);
2268
2269   register_init_routine(ldap_reinit);
2270 }
2271
2272 void
2273 proto_reg_handoff_ldap(void)
2274 {
2275   dissector_handle_t ldap_handle;
2276
2277   ldap_handle = create_dissector_handle(dissect_ldap, proto_ldap);
2278   dissector_add("tcp.port", TCP_PORT_LDAP, ldap_handle);
2279   dissector_add("tcp.port", TCP_PORT_GLOBALCAT_LDAP, ldap_handle);
2280   dissector_add("udp.port", UDP_PORT_CLDAP, ldap_handle);
2281
2282   gssapi_handle = find_dissector("gssapi");
2283   gssapi_wrap_handle = find_dissector("gssapi_verf");
2284 }