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