Check whether the array of procedure hf values has an element for the
[obnox/wireshark/wip.git] / packet-dcerpc-nt.c
1 /* packet-dcerpc-nt.c
2  * Routines for DCERPC over SMB packet disassembly
3  * Copyright 2001, Tim Potter <tpot@samba.org>
4  *
5  * $Id: packet-dcerpc-nt.c,v 1.46 2002/08/28 21:00:10 jmayer Exp $
6  *
7  * Ethereal - Network traffic analyzer
8  * By Gerald Combs <gerald@ethereal.com>
9  * Copyright 1998 Gerald Combs
10  *
11  * This program is free software; you can redistribute it and/or
12  * modify it under the terms of the GNU General Public License
13  * as published by the Free Software Foundation; either version 2
14  * of the License, or (at your option) any later version.
15  *
16  * This program is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19  * GNU General Public License for more details.
20  *
21  * You should have received a copy of the GNU General Public License
22  * along with this program; if not, write to the Free Software
23  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
24  */
25
26 #ifdef HAVE_CONFIG_H
27 #include "config.h"
28 #endif
29
30 #include <glib.h>
31 #include <epan/packet.h>
32 #include "packet-dcerpc.h"
33 #include "packet-dcerpc-nt.h"
34 #include "smb.h"
35 #include "packet-smb-common.h" /* for dissect_smb_64bit_time() */
36
37 /*
38  * This file contains helper routines that are used by the DCERPC over SMB
39  * dissectors for ethereal.
40  */
41
42 /* Align offset to a n-byte boundary */
43
44 int prs_align(int offset, int n)
45 {
46         if (offset % n)
47                 offset += n - (offset % n);
48
49         return offset;
50 }
51
52 /* Parse a 8-bit integer */
53
54 int prs_uint8(tvbuff_t *tvb, int offset, packet_info *pinfo _U_,
55               proto_tree *tree, guint8 *data, char *name)
56 {
57         guint8 i;
58
59         /* No alignment required */
60
61         i = tvb_get_guint8(tvb, offset);
62         offset++;
63
64         if (name && tree)
65                 proto_tree_add_text(tree, tvb, offset - 1, 1,
66                                     "%s: %u", name, i);
67
68         if (data)
69                 *data = i;
70
71         return offset;
72 }
73
74 int prs_uint8s(tvbuff_t *tvb, int offset, packet_info *pinfo _U_,
75                proto_tree *tree, int count, int *data_offset, char *name)
76 {
77         /* No alignment required */
78
79         if (name && tree)
80                 proto_tree_add_text(tree, tvb, offset, count, "%s", name);
81
82         if (data_offset)
83                 *data_offset = offset;
84
85         offset += count;
86
87         return offset;
88 }
89
90 /* Parse a 16-bit integer */
91
92 int prs_uint16(tvbuff_t *tvb, int offset, packet_info *pinfo _U_,
93                proto_tree *tree, guint16 *data, char *name)
94 {
95         guint16 i;
96
97         offset = prs_align(offset, 2);
98
99         i = tvb_get_letohs(tvb, offset);
100         offset += 2;
101
102         if (name && tree)
103                 proto_tree_add_text(tree, tvb, offset - 2, 2,
104                                     "%s: %u", name, i);
105         if (data)
106                 *data = i;
107
108         return offset;
109 }
110
111 /* Parse a number of uint16's */
112
113 int prs_uint16s(tvbuff_t *tvb, int offset, packet_info *pinfo _U_,
114                 proto_tree *tree, int count, int *data_offset, char *name)
115 {
116         offset = prs_align(offset, 2);
117
118         if (name && tree)
119                 proto_tree_add_text(tree, tvb, offset, count * 2,
120                                     "%s", name);
121         if (data_offset)
122                 *data_offset = offset;
123
124         offset += count * 2;
125
126         return offset;
127 }
128
129 /* Parse a 32-bit integer */
130
131 int prs_uint32(tvbuff_t *tvb, int offset, packet_info *pinfo _U_,
132                proto_tree *tree, guint32 *data, char *name)
133 {
134         guint32 i;
135
136         offset = prs_align(offset, 4);
137
138         i = tvb_get_letohl(tvb, offset);
139         offset += 4;
140
141         if (name && tree)
142                 proto_tree_add_text(tree, tvb, offset - 4, 4,
143                                     "%s: %u", name, i);
144
145         if (data)
146                 *data = i;
147
148         return offset;
149 }
150
151 /* Parse a number of 32-bit integers */
152
153 int prs_uint32s(tvbuff_t *tvb, int offset, packet_info *pinfo _U_,
154                 proto_tree *tree, int count, int *data_offset, char *name)
155 {
156         offset = prs_align(offset, 4);
157
158         if (name && tree)
159                 proto_tree_add_text(tree, tvb, offset - 4, 4,
160                                     "%s", name);
161         if (data_offset)
162                 *data_offset = offset;
163
164         offset += count * 4;
165
166         return offset;
167 }
168
169 /* Parse a NT status code */
170
171 int prs_ntstatus(tvbuff_t *tvb, int offset, packet_info *pinfo,
172                  proto_tree *tree)
173 {
174         guint32 status;
175
176         offset = prs_uint32(tvb, offset, pinfo, tree, &status, NULL);
177
178         if (tree)
179                 proto_tree_add_text(tree, tvb, offset - 4, 4, "Status: %s",
180                                     val_to_str(status, NT_errors, "???"));
181
182         return offset;
183 }
184
185 /*
186  * We need to keep track of deferred referrents as they appear in the
187  * packet after all the non-pointer objects.
188  * to keep track of pointers as they are parsed as scalars and need to be
189  * remembered for the next call to the prs function.
190  *
191  * Pointers are stored in a linked list and pushed in the PARSE_SCALARS
192  * section of the prs function and popped in the PARSE_BUFFERS section.  If
193  * we try to pop off a referrent that has a different name then we are
194  * expecting then something has gone wrong.
195  */
196
197 #undef DEBUG_PTRS
198
199 struct ptr {
200         char *name;
201         guint32 value;
202 };
203
204 /* Create a new pointer */
205
206 static struct ptr *new_ptr(char *name, guint32 value)
207 {
208         struct ptr *p;
209
210         p = g_malloc(sizeof(struct ptr));
211
212         p->name = g_strdup(name);
213         p->value = value;
214
215         return p;
216 }
217
218 /* Free a pointer */
219
220 static void free_ptr(struct ptr *p)
221 {
222         if (p) {
223                 g_free(p->name);
224                 g_free(p);
225         }
226 }
227
228 /* Parse a pointer and store it's value in a linked list */
229
230 int prs_push_ptr(tvbuff_t *tvb, int offset, packet_info *pinfo,
231                  proto_tree *tree, GList **ptr_list, char *name)
232 {
233         struct ptr *p;
234         guint32 value;
235
236         offset = prs_uint32(tvb, offset, pinfo, tree, &value, NULL);
237
238         if (name && tree)
239                 proto_tree_add_text(tree, tvb, offset - 4, 4,
240                                     "%s pointer: 0x%08x", name, value);
241
242         p = new_ptr(name, value);
243
244         *ptr_list = g_list_append(*ptr_list, p);
245
246 #ifdef DEBUG_PTRS
247         fprintf(stderr, "DEBUG_PTRS: pushing %s ptr = 0x%08x, %d ptrs in "
248                 "list\n", name, value, g_list_length(*ptr_list));
249 #endif
250
251         return offset;
252 }
253
254 /* Pop a pointer of a given name.  Return it's value. */
255
256 guint32 prs_pop_ptr(GList **ptr_list, char *name _U_)
257 {
258         GList *elt;
259         struct ptr *p;
260         guint32 result;
261
262         g_assert(g_list_length(*ptr_list) != 0);        /* List too short */
263
264         /* Get pointer at head of list */
265
266         elt = g_list_first(*ptr_list);
267         p = (struct ptr *)elt->data;
268         result = p->value;
269
270 #ifdef DEBUG_PTRS
271         if (strcmp(p->name, name) != 0) {
272                 fprintf(stderr, "DEBUG_PTRS: wrong pointer (%s != %s)\n",
273                         p->name, name);
274         }
275 #endif
276
277         /* Free pointer record */
278
279         *ptr_list = g_list_remove_link(*ptr_list, elt);
280
281 #ifdef DEBUG_PTRS
282         fprintf(stderr, "DEBUG_PTRS: popping %s ptr = 0x%08x, %d ptrs in "
283                 "list\n", p->name, p->value, g_list_length(*ptr_list));
284 #endif
285
286         free_ptr(p);
287
288         return result;
289 }
290
291 /* Convert a string from little-endian unicode to ascii.  At the moment we
292    fake it by taking every odd byte.  )-:  The caller must free the
293    result returned. */
294
295 char *fake_unicode(tvbuff_t *tvb, int offset, int len)
296 {
297         char *buffer;
298         int i;
299         guint16 character;
300
301         /* Make sure we have enough data before allocating the buffer,
302            so we don't blow up if the length is huge.
303            We do so by attempting to fetch the last character; it'll
304            throw an exception if it's past the end. */
305         tvb_get_letohs(tvb, offset + 2*(len - 1));
306
307         /* We know we won't throw an exception, so we don't have to worry
308            about leaking this buffer. */
309         buffer = g_malloc(len + 1);
310
311         for (i = 0; i < len; i++) {
312                 character = tvb_get_letohs(tvb, offset);
313                 buffer[i] = character & 0xff;
314                 offset += 2;
315         }
316
317         buffer[len] = 0;
318
319         return buffer;
320 }
321
322 /* Parse a UNISTR2 structure */
323
324 int prs_UNISTR2(tvbuff_t *tvb, int offset, packet_info *pinfo,
325                 proto_tree *tree, int flags, char **data, char *name _U_)
326 {
327         guint32 len = 0, unknown = 0, max_len = 0;
328
329         if (flags & PARSE_SCALARS) {
330                 offset = prs_uint32(tvb, offset, pinfo, tree, &len, "Length");
331                 offset = prs_uint32(tvb, offset, pinfo, tree, &unknown,
332                                     "Offset");
333                 offset = prs_uint32(tvb, offset, pinfo, tree, &max_len,
334                                     "Max length");
335         }
336
337         if (flags & PARSE_BUFFERS) {
338                 int data16_offset;
339
340                 offset = prs_uint16s(tvb, offset, pinfo, tree, max_len,
341                                      &data16_offset, "Buffer");
342
343                 if (data)
344                         *data = fake_unicode(tvb, data16_offset, max_len);
345         }
346
347         return offset;
348 }
349
350 /* following are a few functions for dissecting common structures used by NT
351    services. These might need to be cleaned up at a later time but at least we get
352    them out of the real service dissectors.
353 */
354
355
356 /* UNICODE_STRING  BEGIN */
357 /* functions to dissect a UNICODE_STRING structure, common to many
358    NT services
359    struct {
360      short len;
361      short size;
362      [size_is(size/2), length_is(len/2), ptr] unsigned short *string;
363    } UNICODE_STRING;
364
365    these variables can be found in packet-dcerpc-samr.c
366 */
367 extern int hf_nt_str_len;
368 extern int hf_nt_str_off;
369 extern int hf_nt_str_max_len;
370 extern int hf_nt_string_length;
371 extern int hf_nt_string_size;
372
373 gint ett_nt_unicode_string = -1;
374 static gint ett_nt_policy_hnd = -1;
375
376 /* this function will dissect the
377      [size_is(size/2), length_is(len/2), ptr] unsigned short *string;
378   part of the unicode string
379
380    struct {
381      short len;
382      short size;
383      [size_is(size/2), length_is(len/2), ptr] unsigned short *string;
384    } UNICODE_STRING;
385   structure used by NT to transmit unicode string values.
386
387   This function also looks at di->levels to see if whoever called us wanted us to append
388   the name: string to any higher levels in the tree .
389 */
390 int
391 dissect_ndr_nt_UNICODE_STRING_str(tvbuff_t *tvb, int offset,
392                         packet_info *pinfo, proto_tree *tree,
393                         char *drep)
394 {
395         guint32 len, off, max_len;
396         int data16_offset;
397         char *text;
398         int old_offset;
399         dcerpc_info *di;
400
401         di=pinfo->private_data;
402         if(di->conformant_run){
403                 /*just a run to handle conformant arrays, nothing to dissect */
404                 return offset;
405         }
406
407         offset = dissect_ndr_uint32 (tvb, offset, pinfo, tree, drep,
408                         hf_nt_str_max_len, &max_len);
409         offset = dissect_ndr_uint32 (tvb, offset, pinfo, tree, drep,
410                         hf_nt_str_off, &off);
411         offset = dissect_ndr_uint32 (tvb, offset, pinfo, tree, drep,
412                         hf_nt_str_len, &len);
413
414         old_offset=offset;
415         offset = prs_uint16s(tvb, offset, pinfo, tree, len, &data16_offset,
416                         NULL);
417         text = fake_unicode(tvb, data16_offset, len);
418
419         proto_tree_add_string(tree, di->hf_index, tvb, old_offset,
420                 offset-old_offset, text);
421
422         /* need to test di->levels before doing the proto_item_append_text()
423            since netlogon has these objects as top level objects in its representation
424            and trying to append to the tree object in that case will dump core */
425         if(tree && (di->levels>-1)){
426                 proto_item_append_text(tree, ": %s", text);
427                 di->levels--;
428                 if(di->levels>-1){
429                         tree=tree->parent;
430                         proto_item_append_text(tree, ": %s", text);
431                         di->levels--;
432                         while(di->levels>-1){
433                                 tree=tree->parent;
434                                 proto_item_append_text(tree, " %s", text);
435                                 di->levels--;
436                         }
437                 }
438         }
439         g_free(text);
440         return offset;
441 }
442
443 /* this function will dissect the
444    struct {
445      short len;
446      short size;
447      [size_is(size/2), length_is(len/2), ptr] unsigned short *string;
448    } UNICODE_STRING;
449   structure used by NT to transmit unicode string values.
450
451   the function takes one additional parameter, level
452   which specifies how many additional levels up in the tree where we should
453   append the string.  If unsure, specify levels as 0.
454 */
455 int
456 dissect_ndr_nt_UNICODE_STRING(tvbuff_t *tvb, int offset,
457                         packet_info *pinfo, proto_tree *parent_tree,
458                         char *drep, int hf_index, int levels)
459 {
460         proto_item *item=NULL;
461         proto_tree *tree=NULL;
462         int old_offset=offset;
463         dcerpc_info *di;
464         char *name;
465
466         ALIGN_TO_4_BYTES;  /* strcture starts with short, but is aligned for longs */
467
468         di=pinfo->private_data;
469         if(di->conformant_run){
470                 /*just a run to handle conformant arrays, nothing to dissect */
471                 return offset;
472         }
473
474         name = proto_registrar_get_name(hf_index);
475         if(parent_tree){
476                 item = proto_tree_add_text(parent_tree, tvb, offset, -1,
477                         "%s", name);
478                 tree = proto_item_add_subtree(item, ett_nt_unicode_string);
479         }
480
481         offset = dissect_ndr_uint16 (tvb, offset, pinfo, tree, drep,
482                         hf_nt_string_length, NULL);
483         offset = dissect_ndr_uint16 (tvb, offset, pinfo, tree, drep,
484                         hf_nt_string_size, NULL);
485         di->levels=1;   /* XXX - is this necessary? */
486         /* Add 1 level, for the extra level we added */
487         offset = dissect_ndr_pointer(tvb, offset, pinfo, tree, drep,
488                         dissect_ndr_nt_UNICODE_STRING_str, NDR_POINTER_UNIQUE,
489                         name, hf_index, levels + 1);
490
491         proto_item_set_len(item, offset-old_offset);
492         return offset;
493 }
494 /* UNICODE_STRING  END */
495
496 /* functions to dissect a STRING structure, common to many
497    NT services
498    struct {
499      short len;
500      short size;
501      [size_is(size), length_is(len), ptr] char *string;
502    } STRING;
503 */
504 int
505 dissect_ndr_nt_STRING_string (tvbuff_t *tvb, int offset,
506                              packet_info *pinfo, proto_tree *tree,
507                              char *drep)
508 {
509         guint32 len, off, max_len;
510         int text_offset;
511         const guint8 *text;
512         int old_offset;
513         header_field_info *hfi;
514         dcerpc_info *di;
515
516         di=pinfo->private_data;
517         if(di->conformant_run){
518                 /*just a run to handle conformant arrays, nothing to dissect */
519                 return offset;
520         }
521
522         offset = dissect_ndr_uint32 (tvb, offset, pinfo, tree, drep,
523                                      hf_nt_str_max_len, &max_len);
524         offset = dissect_ndr_uint32 (tvb, offset, pinfo, tree, drep,
525                                      hf_nt_str_off, &off);
526         offset = dissect_ndr_uint32 (tvb, offset, pinfo, tree, drep,
527                                      hf_nt_str_len, &len);
528
529         old_offset=offset;
530         hfi = proto_registrar_get_nth(di->hf_index);
531
532         switch(hfi->type){
533         case FT_STRING:
534                 offset = prs_uint8s(tvb, offset, pinfo, tree, len,
535                         &text_offset, NULL);
536                 text = tvb_get_ptr(tvb, text_offset, len);
537                 proto_tree_add_string_format(tree, di->hf_index,
538                         tvb, old_offset, offset-old_offset,
539                         text, "%s: %s", hfi->name, text);
540                 break;
541         case FT_BYTES:
542                 text = NULL;
543                 proto_tree_add_item(tree, di->hf_index, tvb, offset, len, FALSE);
544                 offset += len;
545                 break;
546         default:
547                 text = NULL;
548                 g_assert_not_reached();
549         }
550
551         if(tree && text && (di->levels>-1)){
552                 proto_item_append_text(tree, ": %s", text);
553                 if(di->levels>-1){
554                         tree=tree->parent;
555                         proto_item_append_text(tree, ": %s", text);
556                         while(di->levels>0){
557                                 tree=tree->parent;
558                                 proto_item_append_text(tree, " %s", text);
559                                 di->levels--;
560                         }
561                 }
562         }
563         return offset;
564 }
565
566 int
567 dissect_ndr_nt_STRING (tvbuff_t *tvb, int offset,
568                              packet_info *pinfo, proto_tree *parent_tree,
569                              char *drep, int hf_index, int levels)
570 {
571         proto_item *item=NULL;
572         proto_tree *tree=NULL;
573         int old_offset=offset;
574         dcerpc_info *di;
575         char *name;
576
577         ALIGN_TO_4_BYTES;  /* strcture starts with short, but is aligned for longs */
578
579         di=pinfo->private_data;
580         if(di->conformant_run){
581                 /*just a run to handle conformant arrays, nothing to dissect */
582                 return offset;
583         }
584
585         name = proto_registrar_get_name(hf_index);
586         if(parent_tree){
587                 item = proto_tree_add_text(parent_tree, tvb, offset, -1,
588                         "%s", name);
589                 tree = proto_item_add_subtree(item, ett_nt_unicode_string);
590         }
591
592         offset = dissect_ndr_uint16 (tvb, offset, pinfo, tree, drep,
593                                      hf_nt_string_length, NULL);
594         offset = dissect_ndr_uint16 (tvb, offset, pinfo, tree, drep,
595                                      hf_nt_string_size, NULL);
596         offset = dissect_ndr_pointer(tvb, offset, pinfo, tree, drep,
597                         dissect_ndr_nt_STRING_string, NDR_POINTER_UNIQUE,
598                         name, hf_index, levels);
599
600         proto_item_set_len(item, offset-old_offset);
601         return offset;
602 }
603
604
605 /* This function is used to dissect a DCERPC encoded 64 bit time value.
606    XXX it should be fixed both here and in dissect_smb_64bit_time so
607    it can handle both BIG and LITTLE endian encodings
608  */
609 int
610 dissect_ndr_nt_NTTIME (tvbuff_t *tvb, int offset,
611                         packet_info *pinfo, proto_tree *tree,
612                         char *drep _U_, int hf_index)
613 {
614         dcerpc_info *di;
615
616         di=pinfo->private_data;
617         if(di->conformant_run){
618                 /*just a run to handle conformant arrays, nothing to dissect */
619                 return offset;
620         }
621
622         ALIGN_TO_4_BYTES;
623
624         offset = dissect_smb_64bit_time(tvb, tree, offset, hf_index);
625         return offset;
626 }
627
628 /* Define this symbol to display warnings about request/response and
629    policy handle hash table collisions.  This happens when a packet with
630    the same conversation, smb fid and dcerpc call id occurs.  I think this
631    is due to a bug in the dcerpc/smb fragment reassembly code. */
632
633 #undef DEBUG_HASH_COLL
634
635 /*
636  * Policy handle hashing
637  */
638
639 typedef struct {
640         guint8 policy_hnd[20];
641 } pol_hash_key;
642
643 typedef struct {
644         guint32 open_frame, close_frame; /* Frame numbers for open/close */
645         char *name;                      /* Name of policy handle */
646 } pol_hash_value;
647
648 #define POL_HASH_INIT_COUNT 100
649
650 static GHashTable *pol_hash;
651 static GMemChunk *pol_hash_key_chunk;
652 static GMemChunk *pol_hash_value_chunk;
653
654 /* Hash function */
655
656 static guint pol_hash_fn(gconstpointer k)
657 {
658         pol_hash_key *key = (pol_hash_key *)k;
659
660         /* Bytes 4-7 of the policy handle are a timestamp so should make a
661            reasonable hash value */
662
663         return key->policy_hnd[4] + (key->policy_hnd[5] << 8) +
664                 (key->policy_hnd[6] << 16) + (key->policy_hnd[7] << 24);
665 }
666
667 /* Return true if a policy handle is all zeros */
668
669 static gboolean is_null_pol(e_ctx_hnd *policy_hnd)
670 {
671         static guint8 null_policy_hnd[20];
672
673         return memcmp(policy_hnd, null_policy_hnd, 20) == 0;
674 }
675
676 /* Hash compare function */
677
678 static gint pol_hash_compare(gconstpointer k1, gconstpointer k2)
679 {
680         pol_hash_key *key1 = (pol_hash_key *)k1;
681         pol_hash_key *key2 = (pol_hash_key *)k2;
682
683         return memcmp(key1->policy_hnd, key2->policy_hnd,
684                       sizeof(key1->policy_hnd)) == 0;
685 }
686
687 /* Store the open and close frame numbers of a policy handle */
688
689 void dcerpc_smb_store_pol_pkts(e_ctx_hnd *policy_hnd, guint32 open_frame,
690                                guint32 close_frame)
691 {
692         pol_hash_key *key;
693         pol_hash_value *value;
694
695         if (is_null_pol(policy_hnd) || (open_frame == 0 && close_frame == 0))
696                 return;
697
698         /* Look up existing value */
699
700         key = g_mem_chunk_alloc(pol_hash_key_chunk);
701
702         memcpy(&key->policy_hnd, policy_hnd, sizeof(key->policy_hnd));
703
704         if ((value = g_hash_table_lookup(pol_hash, key))) {
705
706                 /* Update existing value */
707
708                 if (open_frame) {
709 #ifdef DEBUG_HASH_COLL
710                         if (value->open_frame != open_frame)
711                                 g_warning("dcerpc_smb: pol_hash open frame collision %d/%d\n", value->open_frame, open_frame);
712 #endif
713                         value->open_frame = open_frame;
714                 }
715
716                 if (close_frame) {
717 #ifdef DEBUG_HASH_COLL
718                         if (value->close_frame != close_frame)
719                                 g_warning("dcerpc_smb: pol_hash close frame collision %d/%d\n", value->close_frame, close_frame);
720 #endif
721                         value->close_frame = close_frame;
722                 }
723
724                 return;
725         }
726
727         /* Create a new value */
728
729         value = g_mem_chunk_alloc(pol_hash_value_chunk);
730
731         value->open_frame = open_frame;
732         value->close_frame = close_frame;
733
734         value->name = NULL;
735
736         g_hash_table_insert(pol_hash, key, value);
737 }
738
739 /* Store a text string with a policy handle */
740
741 void dcerpc_smb_store_pol_name(e_ctx_hnd *policy_hnd, char *name)
742 {
743         pol_hash_key *key;
744         pol_hash_value *value;
745
746         if (is_null_pol(policy_hnd))
747                 return;
748
749         /* Look up existing value */
750
751         key = g_mem_chunk_alloc(pol_hash_key_chunk);
752
753         memcpy(&key->policy_hnd, policy_hnd, sizeof(key->policy_hnd));
754
755         if ((value = g_hash_table_lookup(pol_hash, key))) {
756
757                 /* Update existing value */
758
759                 if (value->name && name) {
760 #ifdef DEBUG_HASH_COLL
761                         if (strcmp(value->name, name) != 0)
762                                 g_warning("dcerpc_smb: pol_hash name collision %s/%s\n", value->name, name);
763 #endif
764                         free(value->name);
765                 }
766
767                 value->name = strdup(name);
768
769                 return;
770         }
771
772         /* Create a new value */
773
774         value = g_mem_chunk_alloc(pol_hash_value_chunk);
775
776         value->open_frame = 0;
777         value->close_frame = 0;
778
779         if (name)
780                 value->name = strdup(name);
781         else
782                 value->name = strdup("UNKNOWN");
783
784         g_hash_table_insert(pol_hash, key, value);
785 }
786
787 /* Retrieve a policy handle */
788
789 gboolean dcerpc_smb_fetch_pol(e_ctx_hnd *policy_hnd, char **name,
790                               guint32 *open_frame, guint32 *close_frame)
791 {
792         pol_hash_key key;
793         pol_hash_value *value;
794
795         /* Prevent uninitialised return vars */
796
797         if (name)
798                 *name = NULL;
799
800         if (open_frame)
801                 *open_frame = 0;
802
803         if (close_frame)
804                 *close_frame = 0;
805
806         /* Look up existing value */
807
808         memcpy(&key.policy_hnd, policy_hnd, sizeof(key.policy_hnd));
809
810         value = g_hash_table_lookup(pol_hash, &key);
811
812         /* Return name and frame numbers */
813
814         if (value) {
815                 if (name)
816                         *name = value->name;
817
818                 if (open_frame)
819                         *open_frame = value->open_frame;
820
821                 if (close_frame)
822                         *close_frame = value->close_frame;
823         }
824
825         return value != NULL;
826 }
827
828 /* Iterator to free a policy handle key/value pair */
829
830 static void free_pol_keyvalue(gpointer key _U_, gpointer value,
831     gpointer user_data _U_)
832 {
833         pol_hash_value *pol_value = (pol_hash_value *)value;
834
835         /* Free user data */
836
837         if (pol_value->name) {
838                 free(pol_value->name);
839                 pol_value->name = NULL;
840         }
841 }
842
843 /* Initialise policy handle hash */
844
845 static void init_pol_hash(void)
846 {
847         /* Initialise memory chunks */
848
849         if (pol_hash_key_chunk)
850                 g_mem_chunk_destroy(pol_hash_key_chunk);
851
852         pol_hash_key_chunk = g_mem_chunk_new(
853                 "Policy handle hash keys", sizeof(pol_hash_key),
854                 POL_HASH_INIT_COUNT * sizeof(pol_hash_key), G_ALLOC_ONLY);
855
856         if (pol_hash_value_chunk)
857                 g_mem_chunk_destroy(pol_hash_value_chunk);
858
859         pol_hash_value_chunk = g_mem_chunk_new(
860                 "Policy handle hash values", sizeof(pol_hash_value),
861                 POL_HASH_INIT_COUNT * sizeof(pol_hash_value), G_ALLOC_ONLY);
862
863         /* Initialise hash table */
864
865         if (pol_hash) {
866                 g_hash_table_foreach(pol_hash, free_pol_keyvalue, NULL);
867                 g_hash_table_destroy(pol_hash);
868         }
869
870         pol_hash = g_hash_table_new(pol_hash_fn, pol_hash_compare);
871 }
872
873 /* Dissect an access mask.  All this stuff is kind of explained at MSDN:
874
875 http://msdn.microsoft.com/library/default.asp?url=/library/en-us/security/security/windows_2000_windows_nt_access_mask_format.asp
876
877 */
878
879 static gint ett_nt_access_mask = -1;
880 static gint ett_nt_access_mask_generic = -1;
881 static gint ett_nt_access_mask_standard = -1;
882 static gint ett_nt_access_mask_specific = -1;
883
884 static int hf_access_sacl = -1;
885 static int hf_access_maximum_allowed = -1;
886 static int hf_access_generic_read = -1;
887 static int hf_access_generic_write = -1;
888 static int hf_access_generic_execute = -1;
889 static int hf_access_generic_all = -1;
890 static int hf_access_standard_delete = -1;
891 static int hf_access_standard_read_control = -1;
892 static int hf_access_standard_synchronise = -1;
893 static int hf_access_standard_write_dac = -1;
894 static int hf_access_standard_write_owner = -1;
895 static int hf_access_specific_15 = -1;
896 static int hf_access_specific_14 = -1;
897 static int hf_access_specific_13 = -1;
898 static int hf_access_specific_12 = -1;
899 static int hf_access_specific_11 = -1;
900 static int hf_access_specific_10 = -1;
901 static int hf_access_specific_9 = -1;
902 static int hf_access_specific_8 = -1;
903 static int hf_access_specific_7 = -1;
904 static int hf_access_specific_6 = -1;
905 static int hf_access_specific_5 = -1;
906 static int hf_access_specific_4 = -1;
907 static int hf_access_specific_3 = -1;
908 static int hf_access_specific_2 = -1;
909 static int hf_access_specific_1 = -1;
910 static int hf_access_specific_0 = -1;
911
912 int
913 dissect_nt_access_mask(tvbuff_t *tvb, gint offset, packet_info *pinfo,
914                        proto_tree *tree, char *drep, int hfindex,
915                        nt_access_mask_fn_t *specific_rights_fn)
916 {
917         proto_item *item;
918         proto_tree *subtree, *generic, *standard, *specific;
919         guint32 access;
920
921         offset = dissect_ndr_uint32(tvb, offset, pinfo, NULL, drep,
922                                     hfindex, &access);
923
924         item = proto_tree_add_uint(tree, hfindex, tvb, offset - 4, 4, access);
925
926         subtree = proto_item_add_subtree(item, ett_nt_access_mask);
927
928         /* Generic access rights */
929
930         item = proto_tree_add_text(subtree, tvb, offset - 4, 4,
931                                    "Generic rights: 0x%08x",
932                                    access & GENERIC_RIGHTS_MASK);
933
934         generic = proto_item_add_subtree(item, ett_nt_access_mask_generic);
935
936         proto_tree_add_boolean(
937                 generic, hf_access_generic_read, tvb, offset - 4, 4,
938                 access);
939
940         proto_tree_add_boolean(
941                 generic, hf_access_generic_write, tvb, offset - 4, 4,
942                 access);
943
944         proto_tree_add_boolean(
945                 generic, hf_access_generic_execute, tvb, offset - 4, 4,
946                 access);
947
948         proto_tree_add_boolean(
949                 generic, hf_access_generic_all, tvb, offset - 4, 4,
950                 access);
951
952         /* Reserved (??) */
953
954         proto_tree_add_boolean(
955                 subtree, hf_access_maximum_allowed, tvb, offset - 4, 4,
956                 access);
957
958         /* Access system security */
959
960         proto_tree_add_boolean(
961                 subtree, hf_access_sacl, tvb, offset - 4, 4,
962                 access);
963
964         /* Standard access rights */
965
966         item = proto_tree_add_text(subtree, tvb, offset - 4, 4,
967                                    "Standard rights: 0x%08x",
968                                    access & STANDARD_RIGHTS_MASK);
969
970         standard = proto_item_add_subtree(item, ett_nt_access_mask_standard);
971
972         proto_tree_add_boolean(
973                 standard, hf_access_standard_synchronise, tvb, offset - 4, 4,
974                 access);
975
976         proto_tree_add_boolean(
977                 standard, hf_access_standard_write_owner, tvb, offset - 4, 4,
978                 access);
979
980         proto_tree_add_boolean(
981                 standard, hf_access_standard_write_dac, tvb, offset - 4, 4,
982                 access);
983
984         proto_tree_add_boolean(
985                 standard, hf_access_standard_read_control, tvb, offset - 4, 4,
986                 access);
987
988         proto_tree_add_boolean(
989                 standard, hf_access_standard_delete, tvb, offset - 4, 4,
990                 access);
991
992         /* Specific access rights.  Call the specific_rights_fn
993            pointer if we have one, otherwise just display bits 0-15 in
994            boring fashion. */
995
996         item = proto_tree_add_text(subtree, tvb, offset - 4, 4,
997                                    "Specific rights: 0x%08x",
998                                    access & SPECIFIC_RIGHTS_MASK);
999
1000         specific = proto_item_add_subtree(item, ett_nt_access_mask_specific);
1001
1002         if (specific_rights_fn) {
1003                 specific_rights_fn(tvb, offset - 4, specific, access);
1004                 return offset;
1005         }
1006
1007         proto_tree_add_boolean(
1008                 specific, hf_access_specific_15, tvb, offset - 4, 4,
1009                 access);
1010
1011         proto_tree_add_boolean(
1012                 specific, hf_access_specific_14, tvb, offset - 4, 4,
1013                 access);
1014
1015         proto_tree_add_boolean(
1016                 specific, hf_access_specific_13, tvb, offset - 4, 4,
1017                 access);
1018
1019         proto_tree_add_boolean(
1020                 specific, hf_access_specific_12, tvb, offset - 4, 4,
1021                 access);
1022
1023         proto_tree_add_boolean(
1024                 specific, hf_access_specific_11, tvb, offset - 4, 4,
1025                 access);
1026
1027         proto_tree_add_boolean(
1028                 specific, hf_access_specific_10, tvb, offset - 4, 4,
1029                 access);
1030
1031         proto_tree_add_boolean(
1032                 specific, hf_access_specific_9, tvb, offset - 4, 4,
1033                 access);
1034
1035         proto_tree_add_boolean(
1036                 specific, hf_access_specific_8, tvb, offset - 4, 4,
1037                 access);
1038
1039         proto_tree_add_boolean(
1040                 specific, hf_access_specific_7, tvb, offset - 4, 4,
1041                 access);
1042
1043         proto_tree_add_boolean(
1044                 specific, hf_access_specific_6, tvb, offset - 4, 4,
1045                 access);
1046
1047         proto_tree_add_boolean(
1048                 specific, hf_access_specific_5, tvb, offset - 4, 4,
1049                 access);
1050
1051         proto_tree_add_boolean(
1052                 specific, hf_access_specific_4, tvb, offset - 4, 4,
1053                 access);
1054
1055         proto_tree_add_boolean(
1056                 specific, hf_access_specific_3, tvb, offset - 4, 4,
1057                 access);
1058
1059         proto_tree_add_boolean(
1060                 specific, hf_access_specific_2, tvb, offset - 4, 4,
1061                 access);
1062
1063         proto_tree_add_boolean(
1064                 specific, hf_access_specific_1, tvb, offset - 4, 4,
1065                 access);
1066
1067         proto_tree_add_boolean(
1068                 specific, hf_access_specific_0, tvb, offset - 4, 4,
1069                 access);
1070
1071         return offset;
1072 }
1073
1074 /*
1075  * Initialise global DCERPC/SMB data structures
1076  */
1077
1078 static void dcerpc_smb_init(void)
1079 {
1080         /* Initialise policy handle hash */
1081
1082         init_pol_hash();
1083 }
1084
1085 /*
1086  * Register ett_ values, and register "dcerpc_smb_init()" as an
1087  * initialisation routine.
1088  */
1089 void proto_register_dcerpc_smb(void)
1090 {
1091         static hf_register_info hf[] = {
1092
1093                 /* Access mask */
1094
1095                 { &hf_access_generic_read,
1096                   { "Generic read", "nt.access_mask.generic_read",
1097                     FT_BOOLEAN, 32, TFS(&flags_set_truth),
1098                     GENERIC_READ_ACCESS, "Generic read", HFILL }},
1099
1100                 { &hf_access_generic_write,
1101                   { "Generic write", "nt.access_mask.generic_write",
1102                     FT_BOOLEAN, 32, TFS(&flags_set_truth),
1103                     GENERIC_WRITE_ACCESS, "Generic write", HFILL }},
1104
1105                 { &hf_access_generic_execute,
1106                   { "Generic execute", "nt.access_mask.generic_execute",
1107                     FT_BOOLEAN, 32, TFS(&flags_set_truth),
1108                     GENERIC_EXECUTE_ACCESS, "Generic execute", HFILL }},
1109
1110                 { &hf_access_generic_all,
1111                   { "Generic all", "nt.access_mask.generic_all",
1112                     FT_BOOLEAN, 32, TFS(&flags_set_truth),
1113                     GENERIC_ALL_ACCESS, "Generic all", HFILL }},
1114
1115                 { &hf_access_maximum_allowed,
1116                   { "Maximum allowed", "nt.access_mask.maximum_allowed",
1117                     FT_BOOLEAN, 32, TFS(&flags_set_truth),
1118                     MAXIMUM_ALLOWED_ACCESS, "Maximum allowed", HFILL }},
1119
1120                 { &hf_access_sacl,
1121                   { "Access SACL", "nt.access_mask.access_sacl",
1122                     FT_BOOLEAN, 32, TFS(&flags_set_truth),
1123                     ACCESS_SACL_ACCESS, "Access SACL", HFILL }},
1124
1125                 { &hf_access_standard_read_control,
1126                   { "Read control", "nt.access_mask.read_control",
1127                     FT_BOOLEAN, 32, TFS(&flags_set_truth),
1128                     READ_CONTROL_ACCESS, "Read control", HFILL }},
1129
1130                 { &hf_access_standard_delete,
1131                   { "Delete", "nt.access_mask.delete",
1132                     FT_BOOLEAN, 32, TFS(&flags_set_truth),
1133                     DELETE_ACCESS, "Delete", HFILL }},
1134
1135                 { &hf_access_standard_synchronise,
1136                   { "Synchronise", "nt.access_mask.synchronise",
1137                     FT_BOOLEAN, 32, TFS(&flags_set_truth),
1138                     SYNCHRONIZE_ACCESS, "Synchronise", HFILL }},
1139
1140                 { &hf_access_standard_write_dac,
1141                   { "Write DAC", "nt.access_mask.write_dac",
1142                     FT_BOOLEAN, 32, TFS(&flags_set_truth),
1143                     WRITE_DAC_ACCESS, "Write DAC", HFILL }},
1144
1145                 { &hf_access_standard_write_owner,
1146                   { "Write owner", "nt.access_mask.write_owner",
1147                     FT_BOOLEAN, 32, TFS(&flags_set_truth),
1148                     WRITE_OWNER_ACCESS, "Write owner", HFILL }},
1149
1150                 { &hf_access_specific_15,
1151                   { "Specific access, bit 15", "nt.access_mask.specific_15",
1152                     FT_BOOLEAN, 32, TFS(&flags_set_truth),
1153                     0x8000, "Specific access, bit 15", HFILL }},
1154
1155                 { &hf_access_specific_14,
1156                   { "Specific access, bit 14", "nt.access_mask.specific_14",
1157                     FT_BOOLEAN, 32, TFS(&flags_set_truth),
1158                     0x4000, "Specific access, bit 14", HFILL }},
1159
1160                 { &hf_access_specific_13,
1161                   { "Specific access, bit 13", "nt.access_mask.specific_13",
1162                     FT_BOOLEAN, 32, TFS(&flags_set_truth),
1163                     0x2000, "Specific access, bit 13", HFILL }},
1164
1165                 { &hf_access_specific_12,
1166                   { "Specific access, bit 12", "nt.access_mask.specific_12",
1167                     FT_BOOLEAN, 32, TFS(&flags_set_truth),
1168                     0x1000, "Specific access, bit 12", HFILL }},
1169
1170                 { &hf_access_specific_11,
1171                   { "Specific access, bit 11", "nt.access_mask.specific_11",
1172                     FT_BOOLEAN, 32, TFS(&flags_set_truth),
1173                     0x0800, "Specific access, bit 11", HFILL }},
1174
1175                 { &hf_access_specific_10,
1176                   { "Specific access, bit 10", "nt.access_mask.specific_10",
1177                     FT_BOOLEAN, 32, TFS(&flags_set_truth),
1178                     0x0400, "Specific access, bit 10", HFILL }},
1179
1180                 { &hf_access_specific_9,
1181                   { "Specific access, bit 9", "nt.access_mask.specific_9",
1182                     FT_BOOLEAN, 32, TFS(&flags_set_truth),
1183                     0x0200, "Specific access, bit 9", HFILL }},
1184
1185                 { &hf_access_specific_8,
1186                   { "Specific access, bit 8", "nt.access_mask.specific_8",
1187                     FT_BOOLEAN, 32, TFS(&flags_set_truth),
1188                     0x0100, "Specific access, bit 8", HFILL }},
1189
1190                 { &hf_access_specific_7,
1191                   { "Specific access, bit 7", "nt.access_mask.specific_7",
1192                     FT_BOOLEAN, 32, TFS(&flags_set_truth),
1193                     0x0080, "Specific access, bit 7", HFILL }},
1194
1195                 { &hf_access_specific_6,
1196                   { "Specific access, bit 6", "nt.access_mask.specific_6",
1197                     FT_BOOLEAN, 32, TFS(&flags_set_truth),
1198                     0x0040, "Specific access, bit 6", HFILL }},
1199
1200                 { &hf_access_specific_5,
1201                   { "Specific access, bit 5", "nt.access_mask.specific_5",
1202                     FT_BOOLEAN, 32, TFS(&flags_set_truth),
1203                     0x0020, "Specific access, bit 5", HFILL }},
1204
1205                 { &hf_access_specific_4,
1206                   { "Specific access, bit 4", "nt.access_mask.specific_4",
1207                     FT_BOOLEAN, 32, TFS(&flags_set_truth),
1208                     0x0010, "Specific access, bit 4", HFILL }},
1209
1210                 { &hf_access_specific_3,
1211                   { "Specific access, bit 3", "nt.access_mask.specific_3",
1212                     FT_BOOLEAN, 32, TFS(&flags_set_truth),
1213                     0x0008, "Specific access, bit 3", HFILL }},
1214
1215                 { &hf_access_specific_2,
1216                   { "Specific access, bit 2", "nt.access_mask.specific_2",
1217                     FT_BOOLEAN, 32, TFS(&flags_set_truth),
1218                     0x0004, "Specific access, bit 2", HFILL }},
1219
1220                 { &hf_access_specific_1,
1221                   { "Specific access, bit 1", "nt.access_mask.specific_1",
1222                     FT_BOOLEAN, 32, TFS(&flags_set_truth),
1223                     0x0002, "Specific access, bit 1", HFILL }},
1224
1225                 { &hf_access_specific_0,
1226                   { "Specific access, bit 0", "nt.access_mask.specific_0",
1227                     FT_BOOLEAN, 32, TFS(&flags_set_truth),
1228                     0x0001, "Specific access, bit 0", HFILL }},
1229         };
1230
1231         static gint *ett[] = {
1232                 &ett_nt_unicode_string,
1233                 &ett_nt_policy_hnd,
1234                 &ett_nt_access_mask,
1235                 &ett_nt_access_mask_generic,
1236                 &ett_nt_access_mask_standard,
1237                 &ett_nt_access_mask_specific,
1238         };
1239
1240         static int proto_dcerpc_nt = -1;
1241
1242         /* Register ett's */
1243
1244         proto_register_subtree_array(ett, array_length(ett));
1245
1246         /* Register hf's */
1247
1248         proto_dcerpc_nt = proto_register_protocol(
1249                 "Dummy Protocol", "DCERPC_NT", "DCERPC_NT");
1250
1251         proto_register_field_array(proto_dcerpc_nt, hf, array_length(hf));
1252
1253         /* Register a routine to be called whenever initialisation
1254            is done. */
1255
1256         register_init_routine(dcerpc_smb_init);
1257 }
1258
1259 /* Check if there is unparsed data remaining in a frame and display an
1260    error.  I guess this could be made into an exception like the malformed
1261    frame exception.  For the DCERPC over SMB dissectors a long frame
1262    indicates a bug in a dissector. */
1263
1264 void dcerpc_smb_check_long_frame(tvbuff_t *tvb, int offset,
1265                                  packet_info *pinfo, proto_tree *tree)
1266 {
1267         if (tvb_length_remaining(tvb, offset) != 0) {
1268
1269                 proto_tree_add_text(
1270                         tree, tvb, offset, tvb_length_remaining(tvb, offset),
1271                         "[Long frame (%d bytes): SPOOLSS]",
1272                         tvb_length_remaining(tvb, offset));
1273
1274                 if (check_col(pinfo->cinfo, COL_INFO))
1275                         col_append_fstr(pinfo->cinfo, COL_INFO,
1276                                         "[Long frame (%d bytes): SPOOLSS]",
1277                                         tvb_length_remaining(tvb, offset));
1278         }
1279 }
1280
1281 /* Dissect a NT status code */
1282
1283 int
1284 dissect_ntstatus(tvbuff_t *tvb, gint offset, packet_info *pinfo,
1285                  proto_tree *tree, char *drep,
1286                  int hfindex, guint32 *pdata)
1287 {
1288         guint32 status;
1289
1290         offset = dissect_ndr_uint32(tvb, offset, pinfo, tree, drep,
1291                                     hfindex, &status);
1292
1293         if (tree && status != 0 && check_col(pinfo->cinfo, COL_INFO))
1294                 col_append_fstr(pinfo->cinfo, COL_INFO, ", %s",
1295                                 val_to_str(status, NT_errors,
1296                                            "Unknown error 0x%08x"));
1297         if (pdata)
1298                 *pdata = status;
1299
1300         return offset;
1301 }
1302
1303 /* Dissect a DOS status code */
1304
1305 int
1306 dissect_doserror(tvbuff_t *tvb, gint offset, packet_info *pinfo,
1307                proto_tree *tree, char *drep,
1308                int hfindex, guint32 *pdata)
1309 {
1310         guint32 status;
1311
1312         offset = dissect_ndr_uint32(tvb, offset, pinfo, tree, drep,
1313                                     hfindex, &status);
1314
1315         if (tree && status != 0 && check_col(pinfo->cinfo, COL_INFO))
1316                 col_append_fstr(pinfo->cinfo, COL_INFO, ", %s",
1317                                 val_to_str(status, DOS_errors,
1318                                            "Unknown error 0x%08x"));
1319         if (pdata)
1320                 *pdata = status;
1321
1322         return offset;
1323 }
1324
1325 /* Dissect a NT policy handle */
1326
1327 int
1328 dissect_nt_policy_hnd(tvbuff_t *tvb, gint offset, packet_info *pinfo,
1329                       proto_tree *tree, char *drep, int hfindex,
1330                       e_ctx_hnd *pdata, gboolean is_open, gboolean is_close)
1331 {
1332         proto_item *item;
1333         proto_tree *subtree;
1334         e_ctx_hnd hnd;
1335         guint32 open_frame = 0, close_frame = 0;
1336         char *name;
1337         int old_offset = offset;
1338
1339         /* Add to proto tree */
1340
1341         item = proto_tree_add_text(tree, tvb, offset, sizeof(e_ctx_hnd),
1342                                    "Policy Handle");
1343
1344         subtree = proto_item_add_subtree(item, ett_nt_policy_hnd);
1345
1346         offset = dissect_ndr_ctx_hnd(tvb, offset, pinfo, subtree, drep,
1347                                      hfindex, &hnd);
1348
1349         /* Store request/reply information */
1350
1351         dcerpc_smb_store_pol_pkts(&hnd, 0, is_close ? pinfo->fd->num : 0);
1352         dcerpc_smb_store_pol_pkts(&hnd, is_open ? pinfo->fd->num: 0, 0);
1353
1354         /* Insert request/reply information if known */
1355
1356         if (dcerpc_smb_fetch_pol(&hnd, &name, &open_frame, &close_frame)) {
1357
1358                 if (open_frame)
1359                         proto_tree_add_text(subtree, tvb, old_offset,
1360                                             sizeof(e_ctx_hnd),
1361                                             "Opened in frame %u", open_frame);
1362
1363                 if (close_frame)
1364                         proto_tree_add_text(subtree, tvb, old_offset,
1365                                             sizeof(e_ctx_hnd),
1366                                             "Closed in frame %u", close_frame);
1367                 if (name != NULL)
1368                         proto_item_append_text(item, ": %s", name);
1369         }
1370
1371         if (pdata)
1372                 *pdata = hnd;
1373
1374         return offset;
1375 }
1376
1377 /* Some helper routines to dissect a range of uint8 characters.  I don't
1378    think these are "official" NDR representations and are probably specific
1379    to NT so for the moment they're put here instead of in packet-dcerpc.c
1380    and packet-dcerpc-ndr.c. */
1381
1382 int
1383 dissect_dcerpc_uint8s(tvbuff_t *tvb, gint offset, packet_info *pinfo _U_,
1384                       proto_tree *tree, char *drep, int hfindex,
1385                       int length, guint8 **pdata)
1386 {
1387     guint8 *data;
1388
1389     data = (guint8 *)tvb_get_ptr(tvb, offset, length);
1390
1391     if (tree) {
1392         proto_tree_add_item (tree, hfindex, tvb, offset, length, (drep[0] & 0x10));
1393     }
1394
1395     if (pdata)
1396         *pdata = data;
1397
1398     return offset + length;
1399 }
1400
1401 int
1402 dissect_ndr_uint8s(tvbuff_t *tvb, gint offset, packet_info *pinfo,
1403                    proto_tree *tree, char *drep,
1404                    int hfindex, int length, guint8 **pdata)
1405 {
1406     dcerpc_info *di;
1407
1408     di=pinfo->private_data;
1409     if(di->conformant_run){
1410       /* just a run to handle conformant arrays, no scalars to dissect */
1411       return offset;
1412     }
1413
1414     /* no alignment needed */
1415     return dissect_dcerpc_uint8s(tvb, offset, pinfo,
1416                                  tree, drep, hfindex, length, pdata);
1417 }
1418
1419 int
1420 dissect_dcerpc_uint16s(tvbuff_t *tvb, gint offset, packet_info *pinfo _U_,
1421                       proto_tree *tree, char *drep, int hfindex,
1422                       int length, guint16 **pdata)
1423 {
1424     guint16 *data;
1425
1426     data = (guint16 *)tvb_get_ptr(tvb, offset, length * 2);
1427
1428     if (tree) {
1429         proto_tree_add_item (tree, hfindex, tvb, offset, length * 2, (drep[0] & 0x10));
1430     }
1431
1432     if (pdata)
1433         *pdata = data;
1434
1435     return offset + length * 2;
1436 }
1437
1438 int
1439 dissect_ndr_uint16s(tvbuff_t *tvb, gint offset, packet_info *pinfo,
1440                    proto_tree *tree, char *drep,
1441                    int hfindex, int length, guint16 **pdata)
1442 {
1443     dcerpc_info *di;
1444
1445     di=pinfo->private_data;
1446     if(di->conformant_run){
1447       /* just a run to handle conformant arrays, no scalars to dissect */
1448       return offset;
1449     }
1450
1451     if (offset % 2)
1452         offset++;
1453
1454     return dissect_dcerpc_uint16s(tvb, offset, pinfo,
1455                                  tree, drep, hfindex, length, pdata);
1456 }