Removed trailing whitespaces from .h and .c files using the
[obnox/wireshark/wip.git] / packet-ldap.c
1 /* packet-ldap.c
2  * Routines for ldap packet dissection
3  *
4  * $Id: packet-ldap.c,v 1.45 2002/08/26 09:21:54 guy Exp $
5  *
6  * Ethereal - Network traffic analyzer
7  * By Gerald Combs <gerald@ethereal.com>
8  * Copyright 1998 Gerald Combs
9  *
10  * This program is free software; you can redistribute it and/or
11  * modify it under the terms of the GNU General Public License
12  * as published by the Free Software Foundation; either version 2
13  * of the License, or (at your option) any later version.
14  * 
15  * This program is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU General Public License for more details.
19  * 
20  * You should have received a copy of the GNU General Public License
21  * along with this program; if not, write to the Free Software
22  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
23  */
24
25 /*
26  * This is not a complete implementation. It doesn't handle the full version 3, more specifically,
27  * it handles only the commands of version 2, but any additional characteristics of the ver3 command are supported.
28  * It's also missing extensible search filters.
29  * 
30  * There should probably be alot more error checking, I simply assume that if we have a full packet, it will be a complete
31  * and correct packet.
32  * 
33  * 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
34  * 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
35  * I can do.
36  * 
37  * Doug Nazar
38  * nazard@dragoninc.on.ca
39  */
40
41 #ifdef HAVE_CONFIG_H
42 # include "config.h"
43 #endif
44
45 #include <stdio.h>
46
47 #include <string.h>
48 #include <glib.h>
49
50 #ifdef NEED_SNPRINTF_H
51 # include "snprintf.h"
52 #endif
53
54 #include <epan/packet.h>
55
56 #include "packet-ldap.h"
57 #include "asn1.h"
58 #include "prefs.h"
59
60 static int proto_ldap = -1;
61 static int hf_ldap_length = -1;
62 static int hf_ldap_message_id = -1;
63 static int hf_ldap_message_type = -1;
64 static int hf_ldap_message_length = -1;
65
66 static int hf_ldap_message_result = -1;
67 static int hf_ldap_message_result_matcheddn = -1;
68 static int hf_ldap_message_result_errormsg = -1;
69 static int hf_ldap_message_result_referral = -1;
70
71 static int hf_ldap_message_bind_version = -1;
72 static int hf_ldap_message_bind_dn = -1;
73 static int hf_ldap_message_bind_auth = -1;
74 static int hf_ldap_message_bind_auth_password = -1;
75 static int hf_ldap_message_bind_auth_mechanism = -1;
76 static int hf_ldap_message_bind_auth_credentials = -1;
77 static int hf_ldap_message_bind_server_credentials = -1;
78
79 static int hf_ldap_message_search_base = -1;
80 static int hf_ldap_message_search_scope = -1;
81 static int hf_ldap_message_search_deref = -1;
82 static int hf_ldap_message_search_sizeLimit = -1;
83 static int hf_ldap_message_search_timeLimit = -1;
84 static int hf_ldap_message_search_typesOnly = -1;
85 static int hf_ldap_message_search_filter = -1;
86
87 static int hf_ldap_message_dn = -1;
88 static int hf_ldap_message_attribute = -1;
89 static int hf_ldap_message_value = -1;
90
91 static int hf_ldap_message_modrdn_name = -1;
92 static int hf_ldap_message_modrdn_delete = -1;
93 static int hf_ldap_message_modrdn_superior = -1;
94
95 static int hf_ldap_message_compare = -1;
96
97 static int hf_ldap_message_modify_add = -1;
98 static int hf_ldap_message_modify_replace = -1;
99 static int hf_ldap_message_modify_delete = -1;
100
101 static int hf_ldap_message_abandon_msgid = -1;
102
103 static gint ett_ldap = -1;
104 static gint ett_ldap_message = -1;
105 static gint ett_ldap_gssapi_token = -1;
106 static gint ett_ldap_referrals = -1;
107 static gint ett_ldap_attribute = -1;
108
109 /* desegmentation of LDAP */
110 static gboolean ldap_desegment = TRUE;
111
112 #define TCP_PORT_LDAP                   389
113 #define UDP_PORT_CLDAP                  389
114
115 static dissector_handle_t gssapi_handle;
116
117 static value_string msgTypes [] = {
118   {LDAP_REQ_BIND, "Bind Request"},
119   {LDAP_REQ_UNBIND, "Unbind Request"},
120   {LDAP_REQ_SEARCH, "Search Request"},
121   {LDAP_REQ_MODIFY, "Modify Request"},
122   {LDAP_REQ_ADD, "Add Request"},
123   {LDAP_REQ_DELETE, "Delete Request"},
124   {LDAP_REQ_MODRDN, "Modify RDN Request"},
125   {LDAP_REQ_COMPARE, "Compare Request"},
126   {LDAP_REQ_ABANDON, "Abandon Request"},
127   {LDAP_REQ_EXTENDED, "Extended Request"},
128     
129   {LDAP_RES_BIND, "Bind Result"},
130   {LDAP_RES_SEARCH_ENTRY, "Search Entry"},
131   {LDAP_RES_SEARCH_RESULT, "Search Result"},
132   {LDAP_RES_SEARCH_REF, "Search Result Reference"},
133   {LDAP_RES_MODIFY, "Modify Result"},
134   {LDAP_RES_ADD, "Add Result"},
135   {LDAP_RES_DELETE, "Delete Result"},
136   {LDAP_RES_MODRDN, "Modify RDN Result"},
137   {LDAP_RES_COMPARE, "Compare Result"},
138   {LDAP_REQ_EXTENDED, "Extended Response"},
139   {0, NULL},
140 };
141
142 static int read_length(ASN1_SCK *a, proto_tree *tree, int hf_id, guint *len)
143 {
144   guint length = 0;
145   gboolean def = FALSE;
146   int start = a->offset;
147   int ret;
148   
149   ret = asn1_length_decode(a, &def, &length);
150   if (ret != ASN1_ERR_NOERROR) {
151     if (tree) {
152       proto_tree_add_text(tree, a->tvb, start, 0,
153         "%s: ERROR: Couldn't parse length: %s",
154         proto_registrar_get_name(hf_id), asn1_err_to_str(ret));
155     }
156     return ret;
157   }
158
159   if (len)
160     *len = length;
161
162   if (tree)
163     proto_tree_add_uint(tree, hf_id, a->tvb, start, a->offset-start, length);
164
165   return ASN1_ERR_NOERROR;
166 }
167
168 static int read_sequence(ASN1_SCK *a, guint *len)
169 {
170   guint cls, con, tag;
171   gboolean def;
172   guint length;
173   int ret;
174   
175   ret = asn1_header_decode(a, &cls, &con, &tag, &def, &length);
176   if (ret != ASN1_ERR_NOERROR)
177     return ret;
178   if (cls != ASN1_UNI || con != ASN1_CON || tag != ASN1_SEQ)
179     return ASN1_ERR_WRONG_TYPE;
180
181   if (len)
182     *len = length;
183   
184   return ASN1_ERR_NOERROR;
185 }
186
187 static int read_set(ASN1_SCK *a, guint *len)
188 {
189   guint cls, con, tag;
190   gboolean def;
191   guint length;
192   int ret;
193   
194   ret = asn1_header_decode(a, &cls, &con, &tag, &def, &length);
195   if (ret != ASN1_ERR_NOERROR)
196     return ret;
197   if (cls != ASN1_UNI || con != ASN1_CON || tag != ASN1_SET)
198     return ASN1_ERR_WRONG_TYPE;
199   
200   if (len)
201     *len = length;
202   
203   return ASN1_ERR_NOERROR;
204 }
205
206 static int read_integer_value(ASN1_SCK *a, proto_tree *tree, int hf_id,
207         proto_item **new_item, guint *i, int start, guint length)
208 {
209   guint integer = 0;
210   proto_item *temp_item = NULL;
211   int ret;
212
213   ret = asn1_uint32_value_decode(a, length, &integer);
214   if (ret != ASN1_ERR_NOERROR) {
215     if (tree) {
216       proto_tree_add_text(tree, a->tvb, start, 0,
217        "%s: ERROR: Couldn't parse value: %s",
218         proto_registrar_get_name(hf_id), asn1_err_to_str(ret));
219     }
220     return ret;
221   }
222
223   if (i)
224     *i = integer;
225
226   if (tree)
227     temp_item = proto_tree_add_uint(tree, hf_id, a->tvb, start, a->offset-start, integer);
228
229   if (new_item)
230     *new_item = temp_item;
231
232   return ASN1_ERR_NOERROR;
233 }
234
235 static int read_integer(ASN1_SCK *a, proto_tree *tree, int hf_id,
236         proto_item **new_item, guint *i, guint expected_tag)
237 {
238   guint cls, con, tag;
239   gboolean def;
240   guint length;
241   int start = a->offset;
242   int ret;
243   
244   ret = asn1_header_decode(a, &cls, &con, &tag, &def, &length);
245   if (ret == ASN1_ERR_NOERROR) {
246     if (cls != ASN1_UNI || con != ASN1_PRI || tag != expected_tag)
247       ret = ASN1_ERR_WRONG_TYPE;
248   }
249   if (ret != ASN1_ERR_NOERROR) {
250     if (tree) {
251       proto_tree_add_text(tree, a->tvb, start, 0,
252         "%s: ERROR: Couldn't parse header: %s",
253         (hf_id != -1) ? proto_registrar_get_name(hf_id) : "LDAP message",
254         asn1_err_to_str(ret));
255     }
256     return ret;
257   }
258
259   return read_integer_value(a, tree, hf_id, new_item, i, start, length);
260 }
261
262 static int read_boolean_value(ASN1_SCK *a, proto_tree *tree, int hf_id,
263         proto_item **new_item, guint *i, int start, guint length)
264 {
265   guint integer = 0;
266   proto_item *temp_item = NULL;
267   int ret;
268
269   ret = asn1_uint32_value_decode(a, length, &integer);
270   if (ret != ASN1_ERR_NOERROR) {
271     if (tree) {
272       proto_tree_add_text(tree, a->tvb, start, 0,
273         "%s: ERROR: Couldn't parse value: %s",
274         proto_registrar_get_name(hf_id), asn1_err_to_str(ret));
275     }
276     return ret;
277   }
278
279   if (i)
280     *i = integer;
281
282   if (tree)
283     temp_item = proto_tree_add_boolean(tree, hf_id, a->tvb, start, a->offset-start, integer);
284   if (new_item)
285     *new_item = temp_item;
286
287   return ASN1_ERR_NOERROR;
288 }
289
290 static int read_boolean(ASN1_SCK *a, proto_tree *tree, int hf_id,
291         proto_item **new_item, guint *i)
292 {
293   guint cls, con, tag;
294   gboolean def;
295   guint length;
296   int start = a->offset;
297   int ret;
298   
299   ret = asn1_header_decode(a, &cls, &con, &tag, &def, &length);
300   if (ret == ASN1_ERR_NOERROR) {
301     if (cls != ASN1_UNI || con != ASN1_PRI || tag != ASN1_BOL)
302       ret = ASN1_ERR_WRONG_TYPE;
303   }
304   if (ret != ASN1_ERR_NOERROR) {
305     if (tree) {
306       proto_tree_add_text(tree, a->tvb, start, 0,
307         "%s: ERROR: Couldn't parse header: %s",
308         proto_registrar_get_name(hf_id), asn1_err_to_str(ret));
309     }
310     return ret;
311   }
312
313   return read_boolean_value(a, tree, hf_id, new_item, i, start, length);
314 }
315
316 static int read_string_value(ASN1_SCK *a, proto_tree *tree, int hf_id,
317         proto_item **new_item, char **s, int start, guint length)
318 {
319   guchar *string;
320   proto_item *temp_item = NULL;
321   int ret;
322   
323   if (length)
324   {
325     ret = asn1_string_value_decode(a, length, &string);
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 value: %s",
330           proto_registrar_get_name(hf_id), asn1_err_to_str(ret));
331       }
332       return ret;
333     }
334     string = g_realloc(string, length + 1);
335     string[length] = '\0';
336   }
337   else
338     string = "(null)";
339     
340   if (tree)
341     temp_item = proto_tree_add_string(tree, hf_id, a->tvb, start, a->offset - start, string);
342   if (new_item)
343     *new_item = temp_item;
344
345   if (s && length)
346     *s = string;
347   else if (length)
348     g_free(string);
349
350   return ASN1_ERR_NOERROR;
351 }
352
353 static int read_string(ASN1_SCK *a, proto_tree *tree, int hf_id,
354         proto_item **new_item, char **s, guint expected_cls, guint expected_tag)
355 {
356   guint cls, con, tag;
357   gboolean def;
358   guint length;
359   int start = a->offset;
360   int ret;
361   
362   ret = asn1_header_decode(a, &cls, &con, &tag, &def, &length);
363   if (ret == ASN1_ERR_NOERROR) {
364     if (cls != expected_cls || con != ASN1_PRI || tag != expected_tag)
365       ret = ASN1_ERR_WRONG_TYPE;
366   }
367   if (ret != ASN1_ERR_NOERROR) {
368     if (tree) {
369       proto_tree_add_text(tree, a->tvb, start, 0,
370         "%s: ERROR: Couldn't parse header: %s",
371         proto_registrar_get_name(hf_id), asn1_err_to_str(ret));
372     }
373     return ret;
374   }
375
376   return read_string_value(a, tree, hf_id, new_item, s, start, length);
377 }
378
379 static int read_bytestring_value(ASN1_SCK *a, proto_tree *tree, int hf_id,
380         proto_item **new_item, char **s, int start, guint length)
381 {
382   guchar *string;
383   proto_item *temp_item = NULL;
384   int ret;
385   
386   if (length)
387   {
388     ret = asn1_string_value_decode(a, length, &string);
389     if (ret != ASN1_ERR_NOERROR) {
390       if (tree) {
391         proto_tree_add_text(tree, a->tvb, start, 0,
392           "%s: ERROR: Couldn't parse value: %s",
393           proto_registrar_get_name(hf_id), asn1_err_to_str(ret));
394       }
395       return ret;
396     }
397     string = g_realloc(string, length + 1);
398     string[length] = '\0';
399   }
400   else
401     string = "(null)";
402     
403   if (tree)
404     temp_item = proto_tree_add_bytes(tree, hf_id, a->tvb, start, a->offset - start, string);
405   if (new_item)
406     *new_item = temp_item;
407
408   if (s && length)
409     *s = string;
410   else if (length)
411     g_free(string);
412
413   return ASN1_ERR_NOERROR;
414 }
415
416 static int read_bytestring(ASN1_SCK *a, proto_tree *tree, int hf_id,
417         proto_item **new_item, char **s, guint expected_cls, guint expected_tag)
418 {
419   guint cls, con, tag;
420   gboolean def;
421   guint length;
422   int start = a->offset;
423   int ret;
424   
425   ret = asn1_header_decode(a, &cls, &con, &tag, &def, &length);
426   if (ret == ASN1_ERR_NOERROR) {
427     if (cls != expected_cls || con != ASN1_PRI || tag != expected_tag)
428       ret = ASN1_ERR_WRONG_TYPE;
429   }
430   if (ret != ASN1_ERR_NOERROR) {
431     if (tree) {
432       proto_tree_add_text(tree, a->tvb, start, 0,
433         "%s: ERROR: Couldn't parse header: %s",
434         proto_registrar_get_name(hf_id), asn1_err_to_str(ret));
435     }
436     return ret;
437   }
438
439   return read_bytestring_value(a, tree, hf_id, new_item, s, start, length);
440 }
441
442 static int parse_filter_strings(ASN1_SCK *a, char **filter, guint *filter_length, const guchar *operation)
443 {
444   guchar *string;
445   guchar *string2;
446   guint string_length;
447   guint string2_length;
448   guint string_bytes;
449   char *filterp;
450   int ret;
451
452   ret = asn1_octet_string_decode(a, &string, &string_length, &string_bytes);
453   if (ret != ASN1_ERR_NOERROR)
454     return ret;
455   ret = asn1_octet_string_decode(a, &string2, &string2_length, &string_bytes);
456   if (ret != ASN1_ERR_NOERROR)
457     return ret;
458   *filter_length += 2 + strlen(operation) + string_length + string2_length;
459   *filter = g_realloc(*filter, *filter_length);
460   filterp = *filter + strlen(*filter);
461   *filterp++ = '(';
462   if (string_length != 0) {
463         memcpy(filterp, string, string_length);
464         filterp += string_length;
465   }
466   strcpy(filterp, operation);
467   filterp += strlen(operation);
468   if (string2_length != 0) {
469         memcpy(filterp, string2, string2_length);
470         filterp += string2_length;
471   }
472   *filterp++ = ')';
473   *filterp = '\0';
474   g_free(string);
475   g_free(string2);
476   return ASN1_ERR_NOERROR;
477 }
478
479 /* Richard Dawe: To parse substring filters, I added this function. */
480 static int parse_filter_substrings(ASN1_SCK *a, char **filter, guint *filter_length)
481 {
482   int end;
483   guchar *string;
484   char *filterp;
485   guint string_length;
486   guint string_bytes;
487   guint seq_len;
488   guint header_bytes;  
489   int ret, any_valued;
490
491   /* For ASN.1 parsing of octet strings */
492   guint        cls;
493   guint        con;
494   guint        tag;
495   gboolean     def;
496
497   ret = asn1_octet_string_decode(a, &string, &string_length, &string_bytes);
498   if (ret != ASN1_ERR_NOERROR)
499     return ret;
500
501   ret = asn1_sequence_decode(a, &seq_len, &header_bytes);
502   if (ret != ASN1_ERR_NOERROR)
503     return ret;
504
505   *filter_length += 2 + 1 + string_length;
506   *filter = g_realloc(*filter, *filter_length);
507   
508   filterp = *filter + strlen(*filter);
509   *filterp++ = '(';
510   if (string_length != 0) {
511     memcpy(filterp, string, string_length);
512     filterp += string_length;
513   }
514   *filterp++ = '=';
515   *filterp = '\0';
516   g_free(string);
517
518   /* Now decode seq_len's worth of octet strings. */
519   any_valued = 0;
520   end = a->offset + seq_len;
521
522   while (a->offset < end) {
523     /* Octet strings here are context-specific, which
524      * asn1_octet_string_decode() barfs on. Emulate it, but don't barf. */
525     ret = asn1_header_decode (a, &cls, &con, &tag, &def, &string_length);
526     if (ret != ASN1_ERR_NOERROR)
527       return ret;
528
529     /* XXX - check the tag? */
530     if (cls != ASN1_CTX || con != ASN1_PRI) {
531         /* XXX - handle the constructed encoding? */
532         return ASN1_ERR_WRONG_TYPE;
533     }
534     if (!def)
535         return ASN1_ERR_LENGTH_NOT_DEFINITE;
536
537     ret = asn1_string_value_decode(a, (int) string_length, &string);
538     if (ret != ASN1_ERR_NOERROR)
539       return ret;
540
541     /* If we have an 'any' component with a string value, we need to append
542      * an extra asterisk before final component. */
543     if ((tag == 1) && (string_length != 0))
544       any_valued = 1;
545
546     if ( (tag == 1) || ((tag == 2) && any_valued) )
547       (*filter_length)++;
548     *filter_length += string_length;
549     *filter = g_realloc(*filter, *filter_length);
550
551     filterp = *filter + strlen(*filter);
552     if ( (tag == 1) || ((tag == 2) && any_valued) )
553       *filterp++ = '*';
554     if (tag == 2)
555       any_valued = 0;
556     if (string_length != 0) {
557       memcpy(filterp, string, string_length);
558       filterp += string_length;
559     }
560     *filterp = '\0';
561     g_free(string);
562   }
563
564   if (any_valued)
565   {
566     (*filter_length)++;
567     *filter = g_realloc(*filter, *filter_length);
568     filterp = *filter + strlen(*filter);
569     *filterp++ = '*';
570   }
571   
572   /* NB: Allocated byte for this earlier */
573   *filterp++ = ')';
574   *filterp = '\0';
575
576   return ASN1_ERR_NOERROR;
577 }
578
579 /* Returns -1 if we're at the end, returns an ASN1_ERR value otherwise. */
580 static int parse_filter(ASN1_SCK *a, char **filter, guint *filter_length,
581                         int *end)
582 {
583   guint cls, con, tag;
584   guint length;
585   gboolean def;
586   int ret;
587
588   ret = asn1_header_decode(a, &cls, &con, &tag, &def, &length);
589   if (ret != ASN1_ERR_NOERROR)
590     return ret;
591   
592   if (*end == 0)
593   {
594     *end = a->offset + length;
595     *filter_length = 1;
596     *filter = g_malloc0(*filter_length);
597   }
598
599   if (cls == ASN1_CTX)  /* XXX - handle other types as errors? */
600   {
601     switch (tag)
602     {
603      case LDAP_FILTER_AND:
604       {
605         int add_end;
606
607         if (con != ASN1_CON)
608           return ASN1_ERR_WRONG_TYPE;
609         add_end = a->offset + length;
610         *filter_length += 3;
611         *filter = g_realloc(*filter, *filter_length);
612         strcat(*filter, "(&");
613         while ((ret = parse_filter(a, filter, filter_length, &add_end))
614                 == ASN1_ERR_NOERROR)
615           continue;
616         if (ret != -1)
617           return ret;
618         strcat(*filter, ")");
619       }
620       break;
621      case LDAP_FILTER_OR:
622       {
623         int or_end;
624
625         if (con != ASN1_CON)
626           return ASN1_ERR_WRONG_TYPE;
627         or_end = a->offset + length;
628         *filter_length += 3;
629         *filter = g_realloc(*filter, *filter_length);
630         strcat(*filter, "(|");
631         while ((ret = parse_filter(a, filter, filter_length, &or_end))
632                 == ASN1_ERR_NOERROR)
633           continue;
634         if (ret != -1)
635           return ret;
636         strcat(*filter, ")");
637       }
638       break;
639      case LDAP_FILTER_NOT:
640       {
641         int not_end;
642
643         if (con != ASN1_CON)
644           return ASN1_ERR_WRONG_TYPE;
645         not_end = a->offset + length;
646         *filter_length += 3;
647         *filter = g_realloc(*filter, *filter_length);
648         strcat(*filter, "(!");
649         ret = parse_filter(a, filter, filter_length, &not_end);
650         if (ret != -1 && ret != ASN1_ERR_NOERROR)
651           return ret;
652         strcat(*filter, ")");
653       }
654       break;
655      case LDAP_FILTER_EQUALITY:
656       if (con != ASN1_CON)
657         return ASN1_ERR_WRONG_TYPE;
658       ret = parse_filter_strings(a, filter, filter_length, "=");
659       if (ret != ASN1_ERR_NOERROR)
660         return ret;
661       break;
662      case LDAP_FILTER_GE:
663       if (con != ASN1_CON)
664         return ASN1_ERR_WRONG_TYPE;
665       ret = parse_filter_strings(a, filter, filter_length, ">=");
666       if (ret != ASN1_ERR_NOERROR)
667         return ret;
668       break;
669      case LDAP_FILTER_LE:
670       if (con != ASN1_CON)
671         return ASN1_ERR_WRONG_TYPE;
672       ret = parse_filter_strings(a, filter, filter_length, "<=");
673       if (ret != -1 && ret != ASN1_ERR_NOERROR)
674         return ret;
675       break;
676      case LDAP_FILTER_APPROX:
677       if (con != ASN1_CON)
678         return ASN1_ERR_WRONG_TYPE;
679       ret = parse_filter_strings(a, filter, filter_length, "~=");
680       if (ret != ASN1_ERR_NOERROR)
681         return ret;
682       break;
683      case LDAP_FILTER_PRESENT:
684       {
685         guchar *string;
686         char *filterp;
687     
688         if (con != ASN1_PRI)
689           return ASN1_ERR_WRONG_TYPE;
690         ret = asn1_string_value_decode(a, length, &string);
691         if (ret != ASN1_ERR_NOERROR)
692           return ret;
693         *filter_length += 4 + length;
694         *filter = g_realloc(*filter, *filter_length);
695         filterp = *filter + strlen(*filter);
696         *filterp++ = '(';
697         if (length != 0) {
698           memcpy(filterp, string, length);
699           filterp += length;
700         }
701         *filterp++ = '=';
702         *filterp++ = '*';
703         *filterp++ = ')';
704         *filterp = '\0';
705         g_free(string);
706       }
707       break;
708      case LDAP_FILTER_SUBSTRINGS:
709       if (con != ASN1_CON)
710         return ASN1_ERR_WRONG_TYPE;
711       /* Richard Dawe: Handle substrings */
712       ret = parse_filter_substrings(a, filter, filter_length);
713       if (ret != ASN1_ERR_NOERROR)
714         return ret;
715       break;
716      default:
717       return ASN1_ERR_WRONG_TYPE;
718     }
719   }
720   
721   if (a->offset == *end)
722     return -1;
723   else
724     return ret;
725 }
726
727 static gboolean read_filter(ASN1_SCK *a, proto_tree *tree, int hf_id)
728 {
729   int start = a->offset;
730   char *filter = 0;
731   guint filter_length = 0;
732   int end = 0;
733   int ret;
734      
735   while ((ret = parse_filter(a, &filter, &filter_length, &end))
736         == ASN1_ERR_NOERROR)
737     continue;
738
739   if (tree) {
740     if (ret != -1) {
741       proto_tree_add_text(tree, a->tvb, start, 0,
742         "%s: ERROR: Can't parse filter: %s",
743         proto_registrar_get_name(hf_id), asn1_err_to_str(ret));
744     } else
745       proto_tree_add_string(tree, hf_id, a->tvb, start, a->offset-start, filter);
746   }
747
748   g_free(filter);
749
750   return (ret == -1) ? TRUE : FALSE;
751 }
752
753 /********************************************************************************************/
754
755 static void dissect_ldap_result(ASN1_SCK *a, proto_tree *tree)
756 {
757   guint resultCode = 0;
758   int ret;
759   
760   if (read_integer(a, tree, hf_ldap_message_result, 0, &resultCode, ASN1_ENUM) != ASN1_ERR_NOERROR)
761     return;
762   if (read_string(a, tree, hf_ldap_message_result_matcheddn, 0, 0, ASN1_UNI, ASN1_OTS) != ASN1_ERR_NOERROR)
763     return;
764   if (read_string(a, tree, hf_ldap_message_result_errormsg, 0, 0, ASN1_UNI, ASN1_OTS) != ASN1_ERR_NOERROR)
765     return;
766
767   if (resultCode == 10)         /* Referral */
768   {
769     int start = a->offset;
770     int end;
771     guint length;
772     proto_item *ti;
773     proto_tree *referralTree;
774     
775     ret = read_sequence(a, &length);
776     if (ret != ASN1_ERR_NOERROR) {
777       if (tree) {
778         proto_tree_add_text(tree, a->tvb, start, 0,
779             "ERROR: Couldn't parse referral URL sequence header: %s",
780             asn1_err_to_str(ret));
781       }
782       return;
783     }
784     ti = proto_tree_add_text(tree, a->tvb, start, length, "Referral URLs");
785     referralTree = proto_item_add_subtree(ti, ett_ldap_referrals);
786
787     end = a->offset + length;
788     while (a->offset < end) {
789       if (read_string(a, referralTree, hf_ldap_message_result_referral, 0, 0, ASN1_UNI, ASN1_OTS) != ASN1_ERR_NOERROR)
790         return;
791     }
792   }
793 }
794
795 static void dissect_ldap_request_bind(ASN1_SCK *a, proto_tree *tree,
796     tvbuff_t *tvb, packet_info *pinfo)
797 {
798   guint cls, con, tag;
799   gboolean def;
800   guint length;
801   int start;
802   int end;
803   int ret;
804   char *mechanism;
805   int token_offset;
806   gint available_length, reported_length;
807   tvbuff_t *new_tvb;
808   proto_item *gitem;
809   proto_tree *gtree = NULL;
810
811   if (read_integer(a, tree, hf_ldap_message_bind_version, 0, 0, ASN1_INT) != ASN1_ERR_NOERROR)
812     return;
813   if (read_string(a, tree, hf_ldap_message_bind_dn, 0, 0, ASN1_UNI, ASN1_OTS) != ASN1_ERR_NOERROR)
814     return;
815
816   start = a->offset;
817   ret = asn1_header_decode(a, &cls, &con, &tag, &def, &length);
818   if (ret == ASN1_ERR_NOERROR) {
819     if (cls != ASN1_CTX) {
820       /* RFCs 1777 and 2251 say these are context-specific types */
821       ret = ASN1_ERR_WRONG_TYPE;
822     }
823   }
824   if (ret != ASN1_ERR_NOERROR) {
825     proto_tree_add_text(tree, a->tvb, start, 0,
826       "%s: ERROR: Couldn't parse header: %s",
827       proto_registrar_get_name(hf_ldap_message_bind_auth),
828       asn1_err_to_str(ret));
829     return;
830   }
831   proto_tree_add_uint(tree, hf_ldap_message_bind_auth, a->tvb, start,
832                         a->offset - start, tag);
833   end = a->offset + length;
834   switch (tag)
835   {
836    case LDAP_AUTH_SIMPLE:
837     if (read_string_value(a, tree, hf_ldap_message_bind_auth_password, NULL,
838                           NULL, start, length) != ASN1_ERR_NOERROR)
839       return;
840     break;
841
842     /* For Kerberos V4, dissect it as a ticket. */
843
844    case LDAP_AUTH_SASL:
845     if (read_string(a, tree, hf_ldap_message_bind_auth_mechanism, NULL,
846                     &mechanism, ASN1_UNI, ASN1_OTS) != ASN1_ERR_NOERROR)
847       return;
848     if (a->offset < end) {
849       if (strcmp(mechanism, "GSS-SPNEGO") == 0) {
850         /*
851          * This is a GSS-API token.
852          * Find out how big it is by parsing the ASN.1 header for the
853          * OCTET STREAM that contains it.
854          */
855         token_offset = a->offset;
856         ret = asn1_header_decode(a, &cls, &con, &tag, &def, &length);
857         if (ret != ASN1_ERR_NOERROR) {
858           proto_tree_add_text(tree, a->tvb, token_offset, 0,
859             "%s: ERROR: Couldn't parse header: %s",
860             proto_registrar_get_name(hf_ldap_message_bind_auth_credentials),
861             asn1_err_to_str(ret));
862           return;
863         }
864         if (tree) {
865           gitem = proto_tree_add_text(tree, tvb, token_offset,
866             (a->offset + length) - token_offset, "GSS-API Token");
867           gtree = proto_item_add_subtree(gitem, ett_ldap_gssapi_token);
868         }
869         available_length = tvb_length_remaining(tvb, token_offset);
870         reported_length = tvb_reported_length_remaining(tvb, token_offset);
871         g_assert(available_length >= 0);
872         g_assert(reported_length >= 0);
873         if (available_length > reported_length)
874           available_length = reported_length;
875         if ((guint)available_length > length)
876           available_length = length;
877         if ((guint)reported_length > length)
878           reported_length = length;
879         new_tvb = tvb_new_subset(tvb, a->offset, available_length, reported_length);
880         call_dissector(gssapi_handle, new_tvb, pinfo, gtree);
881         a->offset += length;
882       } else {
883         if (read_bytestring(a, tree, hf_ldap_message_bind_auth_credentials,
884                             NULL, NULL, ASN1_UNI, ASN1_OTS) != ASN1_ERR_NOERROR)
885           return;
886       }
887     }
888     break;
889   }
890 }
891
892 static void dissect_ldap_response_bind(ASN1_SCK *a, proto_tree *tree,
893                 int start, guint length)
894 {
895   int end;
896
897   end = start + length;
898   dissect_ldap_result(a, tree);
899   if (a->offset < end) {
900     if (read_bytestring(a, tree, hf_ldap_message_bind_server_credentials,
901                         NULL, NULL, ASN1_CTX, 7) != ASN1_ERR_NOERROR)
902       return;
903   }
904 }
905
906 static void dissect_ldap_request_search(ASN1_SCK *a, proto_tree *tree)
907 {
908   guint seq_length;
909   int end;
910   int ret;
911   
912   if (read_string(a, tree, hf_ldap_message_search_base, 0, 0, ASN1_UNI, ASN1_OTS) != ASN1_ERR_NOERROR)
913     return;
914   if (read_integer(a, tree, hf_ldap_message_search_scope, 0, 0, ASN1_ENUM) != ASN1_ERR_NOERROR)
915     return;
916   if (read_integer(a, tree, hf_ldap_message_search_deref, 0, 0, ASN1_ENUM) != ASN1_ERR_NOERROR)
917     return;
918   if (read_integer(a, tree, hf_ldap_message_search_sizeLimit, 0, 0, ASN1_INT) != ASN1_ERR_NOERROR)
919     return;
920   if (read_integer(a, tree, hf_ldap_message_search_timeLimit, 0, 0, ASN1_INT) != ASN1_ERR_NOERROR)
921     return;
922   if (read_boolean(a, tree, hf_ldap_message_search_typesOnly, 0, 0) != ASN1_ERR_NOERROR)
923     return;
924   if (!read_filter(a, tree, hf_ldap_message_search_filter))
925     return;
926   ret = read_sequence(a, &seq_length);
927   if (ret != ASN1_ERR_NOERROR) {
928     if (tree) {
929       proto_tree_add_text(tree, a->tvb, a->offset, 0,
930           "ERROR: Couldn't parse LDAP attribute sequence header: %s",
931           asn1_err_to_str(ret));
932     }
933     return;
934   }
935   end = a->offset + seq_length;
936   while (a->offset < end) {
937     if (read_string(a, tree, hf_ldap_message_attribute, 0, 0, ASN1_UNI,
938                     ASN1_OTS) != ASN1_ERR_NOERROR)
939       return;
940   }
941 }
942
943 static void dissect_ldap_response_search_entry(ASN1_SCK *a, proto_tree *tree)
944 {
945   guint seq_length;
946   int end_of_sequence;
947   int ret;
948  
949   if (read_string(a, tree, hf_ldap_message_dn, 0, 0, ASN1_UNI, ASN1_OTS) != ASN1_ERR_NOERROR)
950     return;
951   ret = read_sequence(a, &seq_length);
952   if (ret != ASN1_ERR_NOERROR) {
953     if (tree) {
954       proto_tree_add_text(tree, a->tvb, a->offset, 0,
955           "ERROR: Couldn't parse search entry response sequence header: %s",
956           asn1_err_to_str(ret));
957     }
958     return;
959   }
960
961   end_of_sequence = a->offset + seq_length;
962   while (a->offset < end_of_sequence)
963   {
964     proto_item *ti;
965     proto_tree *attr_tree;
966     guint set_length;
967     int end_of_set;
968
969     ret = read_sequence(a, 0);
970     if (ret != ASN1_ERR_NOERROR) {
971       if (tree) {
972         proto_tree_add_text(tree, a->tvb, a->offset, 0,
973             "ERROR: Couldn't parse LDAP attribute sequence header: %s",
974             asn1_err_to_str(ret));
975       }
976       return;
977     }
978     if (read_string(a, tree, hf_ldap_message_attribute, &ti, 0, ASN1_UNI, ASN1_OTS) != ASN1_ERR_NOERROR)
979       return;
980     attr_tree = proto_item_add_subtree(ti, ett_ldap_attribute);
981
982     ret = read_set(a, &set_length);
983     if (ret != ASN1_ERR_NOERROR) {
984       if (tree) {
985         proto_tree_add_text(attr_tree, a->tvb, a->offset, 0,
986             "ERROR: Couldn't parse LDAP value set header: %s",
987             asn1_err_to_str(ret));
988       }
989       return;
990     }
991     end_of_set = a->offset + set_length;
992     while (a->offset < end_of_set) {
993       if (read_string(a, attr_tree, hf_ldap_message_value, 0, 0, ASN1_UNI,
994                       ASN1_OTS) != ASN1_ERR_NOERROR)
995         return;
996     }
997   }
998 }
999
1000 static void dissect_ldap_request_add(ASN1_SCK *a, proto_tree *tree)
1001 {
1002   guint seq_length;
1003   int end_of_sequence;
1004   int ret;
1005   
1006   if (read_string(a, tree, hf_ldap_message_dn, 0, 0, ASN1_UNI, ASN1_OTS) != ASN1_ERR_NOERROR)
1007     return;
1008
1009   ret = read_sequence(a, &seq_length);
1010   if (ret != ASN1_ERR_NOERROR) {
1011     if (tree) {
1012       proto_tree_add_text(tree, a->tvb, a->offset, 0,
1013           "ERROR: Couldn't parse add request sequence header: %s",
1014           asn1_err_to_str(ret));
1015     }
1016     return;
1017   }
1018
1019   end_of_sequence = a->offset + seq_length;
1020   while (a->offset < end_of_sequence)
1021   {
1022     proto_item *ti;
1023     proto_tree *attr_tree;
1024     guint set_length;
1025     int end_of_set;
1026
1027     ret = read_sequence(a, 0);
1028     if (ret != ASN1_ERR_NOERROR) {
1029       if (tree) {
1030         proto_tree_add_text(tree, a->tvb, a->offset, 0,
1031             "ERROR: Couldn't parse LDAP attribute sequence header: %s",
1032             asn1_err_to_str(ret));
1033       }
1034       return;
1035     }
1036     if (read_string(a, tree, hf_ldap_message_attribute, &ti, 0, ASN1_UNI,
1037                     ASN1_OTS) != ASN1_ERR_NOERROR)
1038       return;
1039     attr_tree = proto_item_add_subtree(ti, ett_ldap_attribute);
1040
1041     ret = read_set(a, &set_length);
1042     if (ret != ASN1_ERR_NOERROR) {
1043       if (tree) {
1044         proto_tree_add_text(attr_tree, a->tvb, a->offset, 0,
1045             "ERROR: Couldn't parse LDAP value set header: %s",
1046             asn1_err_to_str(ret));
1047       }
1048       return;
1049     }
1050     end_of_set = a->offset + set_length;
1051     while (a->offset < end_of_set) {
1052       if (read_string(a, attr_tree, hf_ldap_message_value, 0, 0, ASN1_UNI, ASN1_OTS) != ASN1_ERR_NOERROR)
1053         return;
1054     }
1055   }
1056 }
1057
1058 static void dissect_ldap_request_delete(ASN1_SCK *a, proto_tree *tree,
1059                 int start, guint length)
1060 {
1061   read_string_value(a, tree, hf_ldap_message_dn, NULL, NULL, start, length);
1062 }
1063
1064 static void dissect_ldap_request_modifyrdn(ASN1_SCK *a, proto_tree *tree,
1065                 guint length)
1066 {
1067   int start = a->offset;
1068
1069   if (read_string(a, tree, hf_ldap_message_dn, 0, 0, ASN1_UNI, ASN1_OTS) != ASN1_ERR_NOERROR)
1070     return;
1071   if (read_string(a, tree, hf_ldap_message_modrdn_name, 0, 0, ASN1_UNI, ASN1_OTS) != ASN1_ERR_NOERROR)
1072     return;
1073   if (read_boolean(a, tree, hf_ldap_message_modrdn_delete, 0, 0) != ASN1_ERR_NOERROR)
1074     return;
1075   
1076   if (a->offset < (int) (start + length)) {
1077     /* LDAP V3 Modify DN operation, with newSuperior */
1078     if (read_string(a, tree, hf_ldap_message_modrdn_superior, 0, 0, ASN1_UNI, ASN1_OTS) != ASN1_ERR_NOERROR)
1079       return;
1080   }
1081 }
1082
1083 static void dissect_ldap_request_compare(ASN1_SCK *a, proto_tree *tree)
1084 {
1085   int start;
1086   int length;
1087   char *string1 = 0;
1088   char *string2 = 0;
1089   char *compare;
1090   int ret;
1091   
1092   if (read_string(a, tree, hf_ldap_message_dn, 0, 0, ASN1_UNI, ASN1_OTS) != ASN1_ERR_NOERROR)
1093     return;
1094   ret = read_sequence(a, 0);
1095   if (ret != ASN1_ERR_NOERROR) {
1096     if (tree) {
1097       proto_tree_add_text(tree, a->tvb, a->offset, 0,
1098           "ERROR: Couldn't parse compare request sequence header: %s",
1099           asn1_err_to_str(ret));
1100     }
1101     return;
1102   }
1103
1104   start = a->offset;
1105   ret = read_string(a, 0, -1, 0, &string1, ASN1_UNI, ASN1_OTS);
1106   if (ret != ASN1_ERR_NOERROR) {
1107     if (tree) {
1108       proto_tree_add_text(tree, a->tvb, start, 0,
1109         "ERROR: Couldn't parse compare type: %s", asn1_err_to_str(ret));
1110     }
1111     return;
1112   }
1113   ret = read_string(a, 0, -1, 0, &string2, ASN1_UNI, ASN1_OTS);
1114   if (ret != ASN1_ERR_NOERROR) {
1115     if (tree) {
1116       proto_tree_add_text(tree, a->tvb, start, 0,
1117         "ERROR: Couldn't parse compare value: %s", asn1_err_to_str(ret));
1118     }
1119     return;
1120   }
1121
1122   length = 2 + strlen(string1) + strlen(string2);
1123   compare = g_malloc0(length);
1124   snprintf(compare, length, "%s=%s", string1, string2);
1125   proto_tree_add_string(tree, hf_ldap_message_compare, a->tvb, start,
1126       a->offset-start, compare);
1127   
1128   g_free(string1);
1129   g_free(string2);
1130   g_free(compare);
1131   
1132   return;
1133 }
1134
1135 static void dissect_ldap_request_modify(ASN1_SCK *a, proto_tree *tree)
1136 {
1137   guint seq_length;
1138   int end_of_sequence;
1139   int ret;
1140   
1141   if (read_string(a, tree, hf_ldap_message_dn, 0, 0, ASN1_UNI, ASN1_OTS) != ASN1_ERR_NOERROR)
1142     return;
1143   ret = read_sequence(a, &seq_length);
1144   if (ret != ASN1_ERR_NOERROR) {
1145     if (tree) {
1146       proto_tree_add_text(tree, a->tvb, a->offset, 0,
1147           "ERROR: Couldn't parse modify request sequence header: %s",
1148           asn1_err_to_str(ret));
1149     }
1150     return;
1151   }
1152   end_of_sequence = a->offset + seq_length;
1153   while (a->offset < end_of_sequence)
1154   {
1155     proto_item *ti;
1156     proto_tree *attr_tree;
1157     guint set_length;
1158     int end_of_set;
1159     guint operation;
1160
1161     ret = read_sequence(a, 0);
1162     if (ret != ASN1_ERR_NOERROR) {
1163       if (tree) {
1164         proto_tree_add_text(tree, a->tvb, a->offset, 0,
1165             "ERROR: Couldn't parse modify request item sequence header: %s",
1166             asn1_err_to_str(ret));
1167       }
1168       return;
1169     }
1170     ret = read_integer(a, 0, -1, 0, &operation, ASN1_ENUM);
1171     if (ret != ASN1_ERR_NOERROR) {
1172       if (tree) {
1173         proto_tree_add_text(tree, a->tvb, a->offset, 0,
1174           "ERROR: Couldn't parse modify operation: %s",
1175           asn1_err_to_str(ret));
1176         return;
1177       }
1178     }
1179     ret = read_sequence(a, 0);
1180     if (ret != ASN1_ERR_NOERROR) {
1181       if (tree) {
1182         proto_tree_add_text(tree, a->tvb, a->offset, 0,
1183             "ERROR: Couldn't parse modify request operation sequence header: %s",
1184             asn1_err_to_str(ret));
1185       }
1186       return;
1187     }
1188
1189     switch (operation)
1190     {
1191      case LDAP_MOD_ADD:
1192       if (read_string(a, tree, hf_ldap_message_modify_add, &ti, 0, ASN1_UNI,
1193                       ASN1_OTS) != ASN1_ERR_NOERROR)
1194         return;
1195       break;
1196
1197      case LDAP_MOD_REPLACE:
1198       if (read_string(a, tree, hf_ldap_message_modify_replace, &ti, 0,
1199                       ASN1_UNI, ASN1_OTS) != ASN1_ERR_NOERROR)
1200         return;
1201       break;
1202
1203      case LDAP_MOD_DELETE:
1204       if (read_string(a, tree, hf_ldap_message_modify_delete, &ti, 0,
1205                       ASN1_UNI, ASN1_OTS) != ASN1_ERR_NOERROR)
1206         return;
1207       break;
1208
1209      default:
1210        proto_tree_add_text(tree, a->tvb, a->offset, 0,
1211             "Unknown LDAP modify operation (%u)", operation);
1212        return;
1213     }
1214     attr_tree = proto_item_add_subtree(ti, ett_ldap_attribute);
1215
1216     ret = read_set(a, &set_length);
1217     if (ret != ASN1_ERR_NOERROR) {
1218       if (tree) {
1219         proto_tree_add_text(attr_tree, a->tvb, a->offset, 0,
1220             "ERROR: Couldn't parse LDAP value set header: %s",
1221             asn1_err_to_str(ret));
1222       }
1223       return;
1224     }
1225     end_of_set = a->offset + set_length;
1226     while (a->offset < end_of_set) {
1227       if (read_string(a, attr_tree, hf_ldap_message_value, 0, 0, ASN1_UNI,
1228                       ASN1_OTS) != ASN1_ERR_NOERROR)
1229         return;
1230     }
1231   }
1232 }
1233
1234 static void dissect_ldap_request_abandon(ASN1_SCK *a, proto_tree *tree,
1235                 int start, guint length)
1236 {
1237   read_integer_value(a, tree, hf_ldap_message_abandon_msgid, NULL, NULL,
1238                             start, length); 
1239 }
1240
1241 static void
1242 dissect_ldap(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
1243 {
1244   proto_tree *ldap_tree = 0, *ti, *msg_tree;
1245   guint messageLength;
1246   guint messageId;
1247   int next_offset;
1248   guint protocolOpCls, protocolOpCon, protocolOpTag;
1249   gchar *typestr;
1250   guint opLen;
1251   ASN1_SCK a;
1252   int start;
1253   gboolean first_time = TRUE;
1254   int ret;
1255
1256   asn1_open(&a, tvb, 0);
1257
1258   while (tvb_reported_length_remaining(tvb, a.offset) > 0)
1259   {
1260     int message_id_start;
1261     int message_id_length;
1262     int message_start;
1263     
1264     /*
1265      * XXX - should handle the initial sequence specifier split across
1266      * segment boundaries.
1267      */
1268     message_start = a.offset;
1269     ret = read_sequence(&a, &messageLength);
1270     if (ret != ASN1_ERR_NOERROR)
1271     {
1272       if (first_time)
1273       {
1274         if (check_col(pinfo->cinfo, COL_PROTOCOL))
1275           col_set_str(pinfo->cinfo, COL_PROTOCOL, "LDAP");
1276         if (check_col(pinfo->cinfo, COL_INFO))
1277         {
1278           col_add_fstr(pinfo->cinfo, COL_INFO,
1279                       "Invalid LDAP message (Can't parse sequence header: %s)",
1280                       asn1_err_to_str(ret));
1281         }
1282       }
1283       if (tree)
1284       {
1285         ti = proto_tree_add_item(tree, proto_ldap, tvb, message_start, -1,
1286                                  FALSE);
1287         ldap_tree = proto_item_add_subtree(ti, ett_ldap);
1288         proto_tree_add_text(ldap_tree, tvb, message_start, -1,
1289                             "Invalid LDAP message (Can't parse sequence header: %s)",
1290                             asn1_err_to_str(ret));
1291       }
1292       break;
1293     }
1294
1295     /*
1296      * Desegmentation check.
1297      */
1298     if (ldap_desegment) {
1299         if (pinfo->can_desegment
1300             && messageLength > (guint)tvb_length_remaining(tvb, a.offset)) {
1301             /*
1302              * This frame doesn't have all of the data for this message,
1303              * but we can do reassembly on it.
1304              *
1305              * Tell the TCP dissector where the data for this message
1306              * starts in the data it handed us, and how many more bytes
1307              * we need, and return.
1308              */
1309             pinfo->desegment_offset = message_start;
1310             pinfo->desegment_len = messageLength -
1311                 tvb_length_remaining(tvb, a.offset);
1312             return;
1313         }
1314     }
1315     next_offset = a.offset + messageLength;
1316
1317     if (first_time)
1318     {
1319       if (check_col(pinfo->cinfo, COL_PROTOCOL))
1320         col_set_str(pinfo->cinfo, COL_PROTOCOL, "LDAP");
1321       if (check_col(pinfo->cinfo, COL_INFO))
1322         col_clear(pinfo->cinfo, COL_INFO);
1323     }
1324
1325     if (tree) 
1326     {
1327       ti = proto_tree_add_item(tree, proto_ldap, tvb, message_start,
1328                                next_offset - message_start, FALSE);
1329       ldap_tree = proto_item_add_subtree(ti, ett_ldap);
1330     }
1331
1332     message_id_start = a.offset;
1333     ret = read_integer(&a, 0, hf_ldap_message_id, 0, &messageId, ASN1_INT);
1334     if (ret != ASN1_ERR_NOERROR)
1335     {
1336       if (first_time && check_col(pinfo->cinfo, COL_INFO))
1337         col_add_fstr(pinfo->cinfo, COL_INFO, "Invalid LDAP packet (Can't parse Message ID: %s)",
1338                     asn1_err_to_str(ret));
1339       if (ldap_tree)
1340         proto_tree_add_text(ldap_tree, tvb, message_id_start, 1,
1341                             "Invalid LDAP packet (Can't parse Message ID: %s)",
1342                             asn1_err_to_str(ret));
1343       break;
1344     }
1345     message_id_length = a.offset - message_id_start;
1346
1347     start = a.offset;
1348     asn1_id_decode(&a, &protocolOpCls, &protocolOpCon, &protocolOpTag);
1349     if (protocolOpCls != ASN1_APL)
1350       typestr = "Bad message type (not Application)";
1351     else
1352       typestr = val_to_str(protocolOpTag, msgTypes, "Unknown message type (%u)");
1353
1354     if (first_time)
1355     {
1356       if (check_col(pinfo->cinfo, COL_INFO))
1357         col_add_fstr(pinfo->cinfo, COL_INFO, "MsgId=%u MsgType=%s",
1358                      messageId, typestr);
1359       first_time = FALSE;
1360     }
1361
1362     if (ldap_tree) 
1363     {
1364       proto_tree_add_uint_hidden(ldap_tree, hf_ldap_message_id, tvb, message_id_start, message_id_length, messageId);
1365       proto_tree_add_uint_hidden(ldap_tree, hf_ldap_message_type, tvb,
1366                                  start, a.offset - start, protocolOpTag);
1367       ti = proto_tree_add_text(ldap_tree, tvb, message_id_start, messageLength, "Message: Id=%u  %s", messageId, typestr);
1368       msg_tree = proto_item_add_subtree(ti, ett_ldap_message);
1369       start = a.offset;
1370       if (read_length(&a, msg_tree, hf_ldap_message_length, &opLen) != ASN1_ERR_NOERROR)
1371         return;
1372
1373       if (protocolOpCls != ASN1_APL)
1374       {
1375         proto_tree_add_text(msg_tree, a.tvb, a.offset, opLen,
1376                             "%s", typestr);
1377       }
1378       else
1379       {
1380         switch (protocolOpTag)
1381         {
1382          case LDAP_REQ_BIND:
1383           dissect_ldap_request_bind(&a, msg_tree, tvb, pinfo);
1384           break;
1385          case LDAP_REQ_UNBIND:
1386           /* Nothing to dissect */
1387           break;
1388          case LDAP_REQ_SEARCH:
1389           dissect_ldap_request_search(&a, msg_tree);
1390           break;
1391          case LDAP_REQ_MODIFY:
1392           dissect_ldap_request_modify(&a, msg_tree);
1393           break;
1394          case LDAP_REQ_ADD:
1395           dissect_ldap_request_add(&a, msg_tree);
1396           break;
1397          case LDAP_REQ_DELETE:
1398           dissect_ldap_request_delete(&a, msg_tree, start, opLen);
1399           break;
1400          case LDAP_REQ_MODRDN:
1401           dissect_ldap_request_modifyrdn(&a, msg_tree, opLen);
1402           break;
1403          case LDAP_REQ_COMPARE:
1404           dissect_ldap_request_compare(&a, msg_tree);
1405           break;
1406          case LDAP_REQ_ABANDON:
1407           dissect_ldap_request_abandon(&a, msg_tree, start, opLen);
1408           break;
1409          case LDAP_RES_BIND:
1410           dissect_ldap_response_bind(&a, msg_tree, start, opLen);
1411           break;
1412          case LDAP_RES_SEARCH_ENTRY:
1413           dissect_ldap_response_search_entry(&a, msg_tree);
1414           break;
1415          case LDAP_RES_SEARCH_RESULT:
1416          case LDAP_RES_MODIFY:
1417          case LDAP_RES_ADD:
1418          case LDAP_RES_DELETE:
1419          case LDAP_RES_MODRDN:
1420          case LDAP_RES_COMPARE:
1421           dissect_ldap_result(&a, msg_tree);
1422           break;
1423          default:
1424           proto_tree_add_text(msg_tree, a.tvb, a.offset, opLen,
1425                               "Unknown LDAP operation (%u)", protocolOpTag);
1426           break;
1427         }
1428       }
1429     }
1430
1431     /*
1432      * XXX - what if "a.offset" is past the offset of the next top-level
1433      * sequence?  Show that as an error?
1434      */
1435     a.offset = next_offset;
1436   }
1437 }
1438
1439 void
1440 proto_register_ldap(void)
1441 {
1442   static value_string result_codes[] = {
1443     {0, "Success"},
1444     {1, "Operations error"},
1445     {2, "Protocol error"},
1446     {3, "Time limit exceeded"},
1447     {4, "Size limit exceeded"},
1448     {5, "Compare false"},
1449     {6, "Compare true"},
1450     {7, "Authentication method not supported"},
1451     {8, "Strong authentication required"},
1452     {10, "Referral"},
1453     {11, "Administrative limit exceeded"},
1454     {12, "Unavailable critical extension"},
1455     {13, "Confidentiality required"},
1456     {14, "SASL bind in progress"},
1457     {16, "No such attribute"},
1458     {17, "Undefined attribute type"},
1459     {18, "Inappropriate matching"},
1460     {19, "Constraint violation"},
1461     {20, "Attribute or value exists"},
1462     {21, "Invalid attribute syntax"},
1463     {32, "No such object"},
1464     {33, "Alias problem"},
1465     {34, "Invalid DN syntax"},
1466     {36, "Alias derefetencing problem"},
1467     {48, "Inappropriate authentication"},
1468     {49, "Invalid credentials"},
1469     {50, "Insufficient access rights"},
1470     {51, "Busy"},
1471     {52, "Unavailable"},
1472     {53, "Unwilling to perform"},
1473     {54, "Loop detected"},
1474     {64, "Naming violation"},
1475     {65, "Objectclass violation"},
1476     {66, "Not allowed on non-leaf"},
1477     {67, "Not allowed on RDN"},
1478     {68, "Entry already exists"},
1479     {69, "Objectclass modification prohibited"},
1480     {71, "Affects multiple DSAs"},
1481     {80, "Other"},
1482     {0,  NULL},
1483   };
1484
1485   static value_string auth_types[] = {
1486     {LDAP_AUTH_SIMPLE,    "Simple"},
1487     {LDAP_AUTH_KRBV4LDAP, "Kerberos V4 to the LDAP server"},
1488     {LDAP_AUTH_KRBV4DSA,  "Kerberos V4 to the DSA"},
1489     {LDAP_AUTH_SASL,      "SASL"},
1490     {0, NULL},
1491   };
1492   
1493   static value_string search_scope[] = {
1494     {0x00, "Base"},
1495     {0x01, "Single"},
1496     {0x02, "Subtree"},
1497     {0x00, NULL},
1498   };
1499     
1500   static value_string search_dereference[] = {
1501     {0x00, "Never"},
1502     {0x01, "Searching"},
1503     {0x02, "Base Object"},
1504     {0x03, "Always"},
1505     {0x00, NULL},
1506   };
1507   
1508   static hf_register_info hf[] = {
1509     { &hf_ldap_length,
1510       { "Length",               "ldap.length",
1511         FT_UINT32, BASE_DEC, NULL, 0x0,
1512         "LDAP Length", HFILL }},
1513           
1514     { &hf_ldap_message_id,
1515       { "Message Id",           "ldap.message_id",
1516         FT_UINT32, BASE_DEC, NULL, 0x0,
1517         "LDAP Message Id", HFILL }},
1518     { &hf_ldap_message_type,
1519       { "Message Type",         "ldap.message_type",
1520         FT_UINT8, BASE_HEX, &msgTypes, 0x0,
1521         "LDAP Message Type", HFILL }},
1522     { &hf_ldap_message_length,
1523       { "Message Length",               "ldap.message_length",
1524         FT_UINT32, BASE_DEC, NULL, 0x0,
1525         "LDAP Message Length", HFILL }},
1526
1527     { &hf_ldap_message_result,
1528       { "Result Code",          "ldap.result.code",
1529         FT_UINT8, BASE_HEX, result_codes, 0x0,
1530         "LDAP Result Code", HFILL }},
1531     { &hf_ldap_message_result_matcheddn,
1532       { "Matched DN",           "ldap.result.matcheddn",
1533         FT_STRING, BASE_NONE, NULL, 0x0,
1534         "LDAP Result Matched DN", HFILL }},
1535     { &hf_ldap_message_result_errormsg,
1536       { "Error Message",                "ldap.result.errormsg",
1537         FT_STRING, BASE_NONE, NULL, 0x0,
1538         "LDAP Result Error Message", HFILL }},
1539     { &hf_ldap_message_result_referral,
1540       { "Referral",             "ldap.result.referral",
1541         FT_STRING, BASE_NONE, NULL, 0x0,
1542         "LDAP Result Referral URL", HFILL }},
1543
1544     { &hf_ldap_message_bind_version,
1545       { "Version",              "ldap.bind.version",
1546         FT_UINT32, BASE_DEC, NULL, 0x0,
1547         "LDAP Bind Version", HFILL }},
1548     { &hf_ldap_message_bind_dn,
1549       { "DN",                   "ldap.bind.dn",
1550         FT_STRING, BASE_NONE, NULL, 0x0,
1551         "LDAP Bind Distinguished Name", HFILL }},
1552     { &hf_ldap_message_bind_auth,
1553       { "Auth Type",            "ldap.bind.auth_type",
1554         FT_UINT8, BASE_HEX, auth_types, 0x0,
1555         "LDAP Bind Auth Type", HFILL }},
1556     { &hf_ldap_message_bind_auth_password,
1557       { "Password",             "ldap.bind.password",
1558         FT_STRING, BASE_NONE, NULL, 0x0,
1559         "LDAP Bind Password", HFILL }},
1560     { &hf_ldap_message_bind_auth_mechanism,
1561       { "Mechanism",            "ldap.bind.mechanism",
1562         FT_STRING, BASE_NONE, NULL, 0x0,
1563         "LDAP Bind Mechanism", HFILL }},
1564     { &hf_ldap_message_bind_auth_credentials,
1565       { "Credentials",          "ldap.bind.credentials",
1566         FT_BYTES, BASE_NONE, NULL, 0x0,
1567         "LDAP Bind Credentials", HFILL }},
1568     { &hf_ldap_message_bind_server_credentials,
1569       { "Server Credentials",   "ldap.bind.server_credentials",
1570         FT_BYTES, BASE_NONE, NULL, 0x0,
1571         "LDAP Bind Server Credentials", HFILL }},
1572
1573     { &hf_ldap_message_search_base,
1574       { "Base DN",              "ldap.search.basedn",
1575         FT_STRING, BASE_NONE, NULL, 0x0,
1576         "LDAP Search Base Distinguished Name", HFILL }},
1577     { &hf_ldap_message_search_scope,
1578       { "Scope",                        "ldap.search.scope",
1579         FT_UINT8, BASE_HEX, search_scope, 0x0,
1580         "LDAP Search Scope", HFILL }},
1581     { &hf_ldap_message_search_deref,
1582       { "Dereference",          "ldap.search.dereference",
1583         FT_UINT8, BASE_HEX, search_dereference, 0x0,
1584         "LDAP Search Dereference", HFILL }},
1585     { &hf_ldap_message_search_sizeLimit,
1586       { "Size Limit",           "ldap.search.sizelimit",
1587         FT_UINT32, BASE_DEC, NULL, 0x0,
1588         "LDAP Search Size Limit", HFILL }},
1589     { &hf_ldap_message_search_timeLimit,
1590       { "Time Limit",           "ldap.search.timelimit",
1591         FT_UINT32, BASE_DEC, NULL, 0x0,
1592         "LDAP Search Time Limit", HFILL }},
1593     { &hf_ldap_message_search_typesOnly,
1594       { "Attributes Only",      "ldap.search.typesonly",
1595         FT_BOOLEAN, BASE_NONE, NULL, 0x0,
1596         "LDAP Search Attributes Only", HFILL }},
1597     { &hf_ldap_message_search_filter,
1598       { "Filter",               "ldap.search.filter",
1599         FT_STRING, BASE_NONE, NULL, 0x0,
1600         "LDAP Search Filter", HFILL }},
1601     { &hf_ldap_message_dn,
1602       { "Distinguished Name",   "ldap.dn",
1603         FT_STRING, BASE_NONE, NULL, 0x0,
1604         "LDAP Distinguished Name", HFILL }},
1605     { &hf_ldap_message_attribute,
1606       { "Attribute",            "ldap.attribute",
1607         FT_STRING, BASE_NONE, NULL, 0x0,
1608         "LDAP Attribute", HFILL }},
1609     /*
1610      * XXX - not all LDAP values are text strings; we'd need a file
1611      * describing which values (by name) are text strings and which are
1612      * binary.
1613      *
1614      * Some values that are, at least in Microsoft's schema, binary
1615      * are:
1616      *
1617      *  invocationId
1618      *  nTSecurityDescriptor
1619      *  objectGUID
1620      */
1621     { &hf_ldap_message_value,
1622       { "Value",                "ldap.value",
1623         FT_STRING, BASE_NONE, NULL, 0x0,
1624         "LDAP Value", HFILL }},
1625
1626     { &hf_ldap_message_modrdn_name,
1627       { "New Name",             "ldap.modrdn.name",
1628         FT_STRING, BASE_NONE, NULL, 0x0,
1629         "LDAP New Name", HFILL }},
1630     { &hf_ldap_message_modrdn_delete,
1631       { "Delete Values",        "ldap.modrdn.delete",
1632         FT_BOOLEAN, BASE_NONE, NULL, 0x0,
1633         "LDAP Modify RDN - Delete original values", HFILL }},
1634     { &hf_ldap_message_modrdn_superior,
1635       { "New Location",         "ldap.modrdn.superior",
1636         FT_STRING, BASE_NONE, NULL, 0x0,
1637         "LDAP Modify RDN - New Location", HFILL }},
1638
1639     { &hf_ldap_message_compare,
1640       { "Test",         "ldap.compare.test",
1641         FT_STRING, BASE_NONE, NULL, 0x0,
1642         "LDAP Compare Test", HFILL }},
1643
1644     { &hf_ldap_message_modify_add,
1645       { "Add",                  "ldap.modify.add",
1646         FT_STRING, BASE_NONE, NULL, 0x0,
1647         "LDAP Add", HFILL }},
1648     { &hf_ldap_message_modify_replace,
1649       { "Replace",              "ldap.modify.replace",
1650         FT_STRING, BASE_NONE, NULL, 0x0,
1651         "LDAP Replace", HFILL }},
1652     { &hf_ldap_message_modify_delete,
1653       { "Delete",               "ldap.modify.delete",
1654         FT_STRING, BASE_NONE, NULL, 0x0,
1655         "LDAP Delete", HFILL }},
1656
1657     { &hf_ldap_message_abandon_msgid,
1658       { "Abandon Msg Id",       "ldap.abandon.msgid",
1659         FT_UINT32, BASE_DEC, NULL, 0x0,
1660         "LDAP Abandon Msg Id", HFILL }},
1661   };
1662
1663   static gint *ett[] = {
1664     &ett_ldap,
1665     &ett_ldap_message,
1666     &ett_ldap_gssapi_token,
1667     &ett_ldap_referrals,
1668     &ett_ldap_attribute
1669   };
1670   module_t *ldap_module;
1671
1672   proto_ldap = proto_register_protocol("Lightweight Directory Access Protocol",
1673                                        "LDAP", "ldap");
1674   proto_register_field_array(proto_ldap, hf, array_length(hf));
1675   proto_register_subtree_array(ett, array_length(ett));
1676
1677   ldap_module = prefs_register_protocol(proto_ldap, NULL);
1678   prefs_register_bool_preference(ldap_module, "desegment_ldap_messages",
1679     "Desegment all LDAP messages spanning multiple TCP segments",
1680     "Whether the LDAP dissector should desegment all messages spanning multiple TCP segments",
1681     &ldap_desegment);
1682 }
1683
1684 void
1685 proto_reg_handoff_ldap(void)
1686 {
1687   dissector_handle_t ldap_handle;
1688
1689   ldap_handle = create_dissector_handle(dissect_ldap, proto_ldap);
1690   dissector_add("tcp.port", TCP_PORT_LDAP, ldap_handle);
1691   dissector_add("udp.port", UDP_PORT_CLDAP, ldap_handle);
1692
1693   gssapi_handle = find_dissector("gssapi");
1694 }