Update manuf to current IEEE entries.
[obnox/wireshark/wip.git] / packet-dcerpc-nt.c
1 /* packet-dcerpc-nt.c
2  * Routines for DCERPC over SMB packet disassembly
3  * Copyright 2001-2003, Tim Potter <tpot@samba.org>
4  *
5  * $Id: packet-dcerpc-nt.c,v 1.69 2003/02/25 02:04:56 tpot 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 /* Parse some common RPC structures */
43
44 gint ett_nt_unicode_string = -1; /* FIXME: make static */
45
46 /* Dissect a counted string as a callback to dissect_ndr_pointer_cb() */
47
48 static int hf_nt_cs_len = -1;
49 static int hf_nt_cs_size = -1;
50
51 int
52 dissect_ndr_counted_string_cb(tvbuff_t *tvb, int offset,
53                               packet_info *pinfo, proto_tree *tree,
54                               char *drep, int hf_index,
55                               dcerpc_callback_fnct_t *callback,
56                               void *callback_args)
57 {
58         dcerpc_info *di = pinfo->private_data;
59         guint16 len, size;
60
61         /* Structure starts with short, but is aligned for longs */
62
63         ALIGN_TO_4_BYTES;
64
65         if (di->conformant_run)
66                 return offset;
67         
68         /* 
69            struct {
70                short len;
71                short size;
72                [size_is(size/2), length_is(len/2), ptr] unsigned short *string;
73            } UNICODE_STRING;
74
75          */
76
77         offset = dissect_ndr_uint16(tvb, offset, pinfo, tree, drep,
78                         hf_nt_cs_len, &len);
79
80         offset = dissect_ndr_uint16(tvb, offset, pinfo, tree, drep,
81                         hf_nt_cs_size, &size);  
82
83         offset = dissect_ndr_pointer_cb(tvb, offset, pinfo, tree, drep,
84                         dissect_ndr_wchar_cvstring, NDR_POINTER_UNIQUE,
85                         "Character Array", hf_index, callback, callback_args);
86
87         return offset;
88 }
89
90 static gint ett_nt_counted_string = -1;
91
92 static int
93 dissect_ndr_counted_string_helper(tvbuff_t *tvb, int offset,
94                                   packet_info *pinfo, proto_tree *tree,
95                                   char *drep, int hf_index, int levels,
96                                   gboolean add_subtree)
97 {
98         proto_item *item;
99         proto_tree *subtree = tree;
100
101         if (add_subtree) {
102
103                 item = proto_tree_add_text(
104                         tree, tvb, offset, 0, 
105                         proto_registrar_get_name(hf_index));
106
107                 subtree = proto_item_add_subtree(item, ett_nt_counted_string);
108         }
109
110         /*
111          * Add 2 levels, so that the string gets attached to the
112          * "Character Array" top-level item and to the top-level item
113          * added above.
114          */
115         return dissect_ndr_counted_string_cb(
116                 tvb, offset, pinfo, subtree, drep, hf_index,
117                 cb_str_postprocess, GINT_TO_POINTER(2 + levels));
118 }
119
120 /* Dissect a counted string in-line. */
121
122 int
123 dissect_ndr_counted_string(tvbuff_t *tvb, int offset,
124                            packet_info *pinfo, proto_tree *tree,
125                            char *drep, int hf_index, int levels)
126 {
127         return dissect_ndr_counted_string_helper(
128                 tvb, offset, pinfo, tree, drep, hf_index, levels, TRUE);
129 }
130
131 /* Dissect a counted string as a callback to dissect_ndr_pointer().
132    This doesn't add a adds a proto item and subtreee for the string as
133    the pointer dissection already creates one. */
134
135 int
136 dissect_ndr_counted_string_ptr(tvbuff_t *tvb, int offset,
137                                packet_info *pinfo, proto_tree *tree,
138                                char *drep)
139 {
140         dcerpc_info *di = pinfo->private_data;
141
142         return dissect_ndr_counted_string_helper(
143                 tvb, offset, pinfo, tree, drep, di->hf_index, 0, FALSE);
144 }
145
146 /* Dissect a counted byte_array as a callback to dissect_ndr_pointer_cb() */
147
148 static gint ett_nt_counted_byte_array = -1;
149
150 /* Dissect a counted byte array in-line. */
151
152 int
153 dissect_ndr_counted_byte_array(tvbuff_t *tvb, int offset,
154                                packet_info *pinfo, proto_tree *tree,
155                                char *drep, int hf_index)
156 {
157         dcerpc_info *di = pinfo->private_data;
158         proto_item *item;
159         proto_tree *subtree;
160         guint16 len, size;
161
162         /* Structure starts with short, but is aligned for longs */
163
164         ALIGN_TO_4_BYTES;
165
166         if (di->conformant_run)
167                 return offset;
168
169         item = proto_tree_add_text(tree, tvb, offset, 0, 
170                 proto_registrar_get_name(hf_index));
171
172         subtree = proto_item_add_subtree(item, ett_nt_counted_byte_array);
173         
174         /* 
175            struct {
176                short len;
177                short size;
178                [size_is(size), length_is(len), ptr] unsigned char *string;
179            } WHATEVER_THIS_IS_CALLED;
180
181          */
182
183         offset = dissect_ndr_uint16(tvb, offset, pinfo, subtree, drep,
184                         hf_nt_cs_len, &len);
185
186         offset = dissect_ndr_uint16(tvb, offset, pinfo, subtree, drep,
187                         hf_nt_cs_size, &size);  
188
189         offset = dissect_ndr_pointer(tvb, offset, pinfo, subtree, drep,
190                         dissect_ndr_char_cvstring, NDR_POINTER_UNIQUE,
191                         "Byte Array", hf_index);
192
193         return offset;
194 }
195
196 /* This function is used to dissect a DCERPC encoded 64 bit time value.
197    XXX it should be fixed both here and in dissect_smb_64bit_time so
198    it can handle both BIG and LITTLE endian encodings
199  */
200 int
201 dissect_ndr_nt_NTTIME (tvbuff_t *tvb, int offset,
202                         packet_info *pinfo, proto_tree *tree,
203                         char *drep _U_, int hf_index)
204 {
205         dcerpc_info *di;
206
207         di=pinfo->private_data;
208         if(di->conformant_run){
209                 /*just a run to handle conformant arrays, nothing to dissect */
210                 return offset;
211         }
212
213         ALIGN_TO_4_BYTES;
214
215         offset = dissect_smb_64bit_time(tvb, tree, offset, hf_index);
216         return offset;
217 }
218
219 /* Define this symbol to display warnings about request/response and
220    policy handle hash table collisions.  This happens when a packet with
221    the same conversation, smb fid and dcerpc call id occurs.  I think this
222    is due to a bug in the dcerpc/smb fragment reassembly code. */
223
224 #undef DEBUG_HASH_COLL
225
226 /*
227  * Policy handle hashing
228  */
229
230 typedef struct {
231         guint8 policy_hnd[20];
232 } pol_hash_key;
233
234 typedef struct {
235         guint32 open_frame, close_frame; /* Frame numbers for open/close */
236         char *name;                      /* Name of policy handle */
237 } pol_hash_value;
238
239 #define POL_HASH_INIT_COUNT 100
240
241 static GHashTable *pol_hash;
242 static GMemChunk *pol_hash_key_chunk;
243 static GMemChunk *pol_hash_value_chunk;
244
245 /* Hash function */
246
247 static guint pol_hash_fn(gconstpointer k)
248 {
249         const pol_hash_key *key = (const pol_hash_key *)k;
250
251         /* Bytes 4-7 of the policy handle are a timestamp so should make a
252            reasonable hash value */
253
254         return key->policy_hnd[4] + (key->policy_hnd[5] << 8) +
255                 (key->policy_hnd[6] << 16) + (key->policy_hnd[7] << 24);
256 }
257
258 /* Return true if a policy handle is all zeros */
259
260 static gboolean is_null_pol(e_ctx_hnd *policy_hnd)
261 {
262         static guint8 null_policy_hnd[20];
263
264         return memcmp(policy_hnd, null_policy_hnd, 20) == 0;
265 }
266
267 /* Hash compare function */
268
269 static gint pol_hash_compare(gconstpointer k1, gconstpointer k2)
270 {
271         const pol_hash_key *key1 = (const pol_hash_key *)k1;
272         const pol_hash_key *key2 = (const pol_hash_key *)k2;
273
274         return memcmp(key1->policy_hnd, key2->policy_hnd,
275                       sizeof(key1->policy_hnd)) == 0;
276 }
277
278 /* Store the open and close frame numbers of a policy handle */
279
280 void dcerpc_smb_store_pol_pkts(e_ctx_hnd *policy_hnd, guint32 open_frame,
281                                guint32 close_frame)
282 {
283         pol_hash_key *key;
284         pol_hash_value *value;
285
286         if (is_null_pol(policy_hnd) || (open_frame == 0 && close_frame == 0))
287                 return;
288
289         /* Look up existing value */
290
291         key = g_mem_chunk_alloc(pol_hash_key_chunk);
292
293         memcpy(&key->policy_hnd, policy_hnd, sizeof(key->policy_hnd));
294
295         if ((value = g_hash_table_lookup(pol_hash, key))) {
296
297                 /* Update existing value */
298
299                 if (open_frame) {
300 #ifdef DEBUG_HASH_COLL
301                         if (value->open_frame != open_frame)
302                                 g_warning("dcerpc_smb: pol_hash open frame collision %d/%d\n", value->open_frame, open_frame);
303 #endif
304                         value->open_frame = open_frame;
305                 }
306
307                 if (close_frame) {
308 #ifdef DEBUG_HASH_COLL
309                         if (value->close_frame != close_frame)
310                                 g_warning("dcerpc_smb: pol_hash close frame collision %d/%d\n", value->close_frame, close_frame);
311 #endif
312                         value->close_frame = close_frame;
313                 }
314
315                 return;
316         }
317
318         /* Create a new value */
319
320         value = g_mem_chunk_alloc(pol_hash_value_chunk);
321
322         value->open_frame = open_frame;
323         value->close_frame = close_frame;
324
325         value->name = NULL;
326
327         g_hash_table_insert(pol_hash, key, value);
328 }
329
330 /* Store a text string with a policy handle */
331
332 void dcerpc_smb_store_pol_name(e_ctx_hnd *policy_hnd, char *name)
333 {
334         pol_hash_key *key;
335         pol_hash_value *value;
336
337         if (is_null_pol(policy_hnd))
338                 return;
339
340         /* Look up existing value */
341
342         key = g_mem_chunk_alloc(pol_hash_key_chunk);
343
344         memcpy(&key->policy_hnd, policy_hnd, sizeof(key->policy_hnd));
345
346         if ((value = g_hash_table_lookup(pol_hash, key))) {
347
348                 /* Update existing value */
349
350                 if (value->name && name) {
351 #ifdef DEBUG_HASH_COLL
352                         if (strcmp(value->name, name) != 0)
353                                 g_warning("dcerpc_smb: pol_hash name collision %s/%s\n", value->name, name);
354 #endif
355                         free(value->name);
356                 }
357
358                 value->name = strdup(name);
359
360                 return;
361         }
362
363         /* Create a new value */
364
365         value = g_mem_chunk_alloc(pol_hash_value_chunk);
366
367         value->open_frame = 0;
368         value->close_frame = 0;
369
370         if (name)
371                 value->name = strdup(name);
372         else
373                 value->name = strdup("<UNKNOWN>");
374
375         g_hash_table_insert(pol_hash, key, value);
376 }
377
378 /* Retrieve a policy handle */
379
380 gboolean dcerpc_smb_fetch_pol(e_ctx_hnd *policy_hnd, char **name,
381                               guint32 *open_frame, guint32 *close_frame)
382 {
383         pol_hash_key key;
384         pol_hash_value *value;
385
386         /* Prevent uninitialised return vars */
387
388         if (name)
389                 *name = NULL;
390
391         if (open_frame)
392                 *open_frame = 0;
393
394         if (close_frame)
395                 *close_frame = 0;
396
397         /* Look up existing value */
398
399         memcpy(&key.policy_hnd, policy_hnd, sizeof(key.policy_hnd));
400
401         value = g_hash_table_lookup(pol_hash, &key);
402
403         /* Return name and frame numbers */
404
405         if (value) {
406                 if (name)
407                         *name = value->name;
408
409                 if (open_frame)
410                         *open_frame = value->open_frame;
411
412                 if (close_frame)
413                         *close_frame = value->close_frame;
414         }
415
416         return value != NULL;
417 }
418
419 /* Iterator to free a policy handle key/value pair */
420
421 static void free_pol_keyvalue(gpointer key _U_, gpointer value,
422     gpointer user_data _U_)
423 {
424         pol_hash_value *pol_value = (pol_hash_value *)value;
425
426         /* Free user data */
427
428         if (pol_value->name) {
429                 free(pol_value->name);
430                 pol_value->name = NULL;
431         }
432 }
433
434 /* Initialise policy handle hash */
435
436 static void init_pol_hash(void)
437 {
438         /* Initialise memory chunks */
439
440         if (pol_hash_key_chunk)
441                 g_mem_chunk_destroy(pol_hash_key_chunk);
442
443         pol_hash_key_chunk = g_mem_chunk_new(
444                 "Policy handle hash keys", sizeof(pol_hash_key),
445                 POL_HASH_INIT_COUNT * sizeof(pol_hash_key), G_ALLOC_ONLY);
446
447         if (pol_hash_value_chunk)
448                 g_mem_chunk_destroy(pol_hash_value_chunk);
449
450         pol_hash_value_chunk = g_mem_chunk_new(
451                 "Policy handle hash values", sizeof(pol_hash_value),
452                 POL_HASH_INIT_COUNT * sizeof(pol_hash_value), G_ALLOC_ONLY);
453
454         /* Initialise hash table */
455
456         if (pol_hash) {
457                 g_hash_table_foreach(pol_hash, free_pol_keyvalue, NULL);
458                 g_hash_table_destroy(pol_hash);
459         }
460
461         pol_hash = g_hash_table_new(pol_hash_fn, pol_hash_compare);
462 }
463
464 /* Check if there is unparsed data remaining in a frame and display an
465    error.  I guess this could be made into an exception like the malformed
466    frame exception.  For the DCERPC over SMB dissectors a long frame
467    indicates a bug in a dissector. */
468
469 void dcerpc_smb_check_long_frame(tvbuff_t *tvb, int offset,
470                                  packet_info *pinfo, proto_tree *tree)
471 {
472         if (tvb_length_remaining(tvb, offset) != 0) {
473
474                 proto_tree_add_text(
475                         tree, tvb, offset, tvb_length_remaining(tvb, offset),
476                         "[Long frame (%d bytes): SPOOLSS]",
477                         tvb_length_remaining(tvb, offset));
478
479                 if (check_col(pinfo->cinfo, COL_INFO))
480                         col_append_fstr(pinfo->cinfo, COL_INFO,
481                                         "[Long frame (%d bytes): SPOOLSS]",
482                                         tvb_length_remaining(tvb, offset));
483         }
484 }
485
486 /* Dissect a NT status code */
487
488 int
489 dissect_ntstatus(tvbuff_t *tvb, gint offset, packet_info *pinfo,
490                  proto_tree *tree, char *drep,
491                  int hfindex, guint32 *pdata)
492 {
493         guint32 status;
494
495         offset = dissect_ndr_uint32(tvb, offset, pinfo, tree, drep,
496                                     hfindex, &status);
497
498         if (status != 0 && check_col(pinfo->cinfo, COL_INFO))
499                 col_append_fstr(pinfo->cinfo, COL_INFO, ", %s",
500                                 val_to_str(status, NT_errors,
501                                            "Unknown error 0x%08x"));
502         if (pdata)
503                 *pdata = status;
504
505         return offset;
506 }
507
508 /* Dissect a DOS status code */
509
510 int
511 dissect_doserror(tvbuff_t *tvb, gint offset, packet_info *pinfo,
512                proto_tree *tree, char *drep,
513                int hfindex, guint32 *pdata)
514 {
515         guint32 status;
516
517         offset = dissect_ndr_uint32(tvb, offset, pinfo, tree, drep,
518                                     hfindex, &status);
519
520         if (status != 0 && check_col(pinfo->cinfo, COL_INFO))
521                 col_append_fstr(pinfo->cinfo, COL_INFO, ", %s",
522                                 val_to_str(status, DOS_errors,
523                                            "Unknown error 0x%08x"));
524         if (pdata)
525                 *pdata = status;
526
527         return offset;
528 }
529
530 /* Dissect a NT policy handle */
531
532 static int hf_nt_policy_open_frame = -1;
533 static int hf_nt_policy_close_frame = -1;
534
535 static gint ett_nt_policy_hnd = -1;
536
537 int
538 dissect_nt_policy_hnd(tvbuff_t *tvb, gint offset, packet_info *pinfo,
539                       proto_tree *tree, char *drep, int hfindex,
540                       e_ctx_hnd *pdata, gboolean is_open, gboolean is_close)
541 {
542         proto_item *item;
543         proto_tree *subtree;
544         e_ctx_hnd hnd;
545         guint32 open_frame = 0, close_frame = 0;
546         char *name;
547         int old_offset = offset;
548
549         /* Add to proto tree */
550
551         item = proto_tree_add_text(tree, tvb, offset, sizeof(e_ctx_hnd),
552                                    "Policy Handle");
553
554         subtree = proto_item_add_subtree(item, ett_nt_policy_hnd);
555
556         offset = dissect_ndr_ctx_hnd(tvb, offset, pinfo, subtree, drep,
557                                      hfindex, &hnd);
558
559         /* Store request/reply information */
560
561         dcerpc_smb_store_pol_pkts(&hnd, 0, is_close ? pinfo->fd->num : 0);
562         dcerpc_smb_store_pol_pkts(&hnd, is_open ? pinfo->fd->num: 0, 0);
563
564         /* Insert request/reply information if known */
565
566         if (dcerpc_smb_fetch_pol(&hnd, &name, &open_frame, &close_frame)) {
567
568                 if (open_frame)
569                         proto_tree_add_uint(
570                                 subtree, hf_nt_policy_open_frame, tvb,
571                                 old_offset, sizeof(e_ctx_hnd), open_frame);
572
573                 if (close_frame)
574                         proto_tree_add_uint(
575                                 subtree, hf_nt_policy_close_frame, tvb,
576                                 old_offset, sizeof(e_ctx_hnd), close_frame);
577
578                 if (name != NULL)
579                         proto_item_append_text(item, ": %s", name);
580         }
581
582         if (pdata)
583                 *pdata = hnd;
584
585         return offset;
586 }
587
588 /* Some helper routines to dissect a range of uint8 characters.  I don't
589    think these are "official" NDR representations and are probably specific
590    to NT so for the moment they're put here instead of in packet-dcerpc.c
591    and packet-dcerpc-ndr.c. */
592
593 int
594 dissect_dcerpc_uint8s(tvbuff_t *tvb, gint offset, packet_info *pinfo _U_,
595                       proto_tree *tree, char *drep, int hfindex,
596                       int length, const guint8 **pdata)
597 {
598     const guint8 *data;
599
600     data = (const guint8 *)tvb_get_ptr(tvb, offset, length);
601
602     if (tree) {
603         proto_tree_add_item (tree, hfindex, tvb, offset, length, (drep[0] & 0x10));
604     }
605
606     if (pdata)
607         *pdata = data;
608
609     return offset + length;
610 }
611
612 int
613 dissect_ndr_uint8s(tvbuff_t *tvb, gint offset, packet_info *pinfo,
614                    proto_tree *tree, char *drep,
615                    int hfindex, int length, const guint8 **pdata)
616 {
617     dcerpc_info *di;
618
619     di=pinfo->private_data;
620     if(di->conformant_run){
621       /* just a run to handle conformant arrays, no scalars to dissect */
622       return offset;
623     }
624
625     /* no alignment needed */
626     return dissect_dcerpc_uint8s(tvb, offset, pinfo,
627                                  tree, drep, hfindex, length, pdata);
628 }
629
630 int
631 dissect_dcerpc_uint16s(tvbuff_t *tvb, gint offset, packet_info *pinfo _U_,
632                       proto_tree *tree, char *drep, int hfindex,
633                       int length)
634 {
635     if (tree) {
636         proto_tree_add_item (tree, hfindex, tvb, offset, length * 2, (drep[0] & 0x10));
637     }
638
639     return offset + length * 2;
640 }
641
642 int
643 dissect_ndr_uint16s(tvbuff_t *tvb, gint offset, packet_info *pinfo,
644                    proto_tree *tree, char *drep,
645                    int hfindex, int length)
646 {
647     dcerpc_info *di;
648
649     di=pinfo->private_data;
650     if(di->conformant_run){
651       /* just a run to handle conformant arrays, no scalars to dissect */
652       return offset;
653     }
654
655     if (offset % 2)
656         offset++;
657
658     return dissect_dcerpc_uint16s(tvb, offset, pinfo,
659                                  tree, drep, hfindex, length);
660 }
661
662 /*
663  * Helper routines for dissecting NDR strings
664  */
665
666 void cb_str_postprocess(packet_info *pinfo, proto_tree *tree _U_,
667                         proto_item *item, tvbuff_t *tvb, 
668                         int start_offset, int end_offset,
669                         void *callback_args)
670 {
671         gint options = GPOINTER_TO_INT(callback_args);
672         gint levels = CB_STR_ITEM_LEVELS(options);
673         char *s;
674
675         /* Align start_offset on 4-byte boundary. */
676
677         if (start_offset % 4)
678                 start_offset += 4 - (start_offset % 4);
679
680         /* Get string value */
681
682         if ((end_offset - start_offset) <= 12)
683                 return;         /* XXX: Use unistr2 dissector instead? */
684
685         s = tvb_fake_unicode(
686                 tvb, start_offset + 12, (end_offset - start_offset - 12) / 2,
687                 TRUE);
688
689         /* Append string to COL_INFO */
690
691         if (options & CB_STR_COL_INFO) {
692                 if (check_col(pinfo->cinfo, COL_INFO))
693                         col_append_fstr(pinfo->cinfo, COL_INFO, ", %s", s);
694         }
695
696         /* Append string to upper-level proto_items */
697
698         if (levels > 0 && item && s && s[0]) {
699                 proto_item_append_text(item, ": %s", s);
700                 item = item->parent;
701                 levels--;
702                 if (levels > 0) {
703                         proto_item_append_text(item, ": %s", s);
704                         item = item->parent;
705                         levels--;
706                         while (levels > 0) {
707                                 proto_item_append_text(item, " %s", s);
708                                 item = item->parent;
709                                 levels--;
710                         }
711                 }
712         }
713
714         /* Save string to dcv->private_data */
715
716         if (options & CB_STR_SAVE) {
717                 dcerpc_info *di = (dcerpc_info *)pinfo->private_data;
718                 dcerpc_call_value *dcv = (dcerpc_call_value *)di->call_data;
719                 
720                 dcv->private_data = g_strdup(s);
721         }
722
723         g_free(s);
724 }
725
726 /* Dissect a pointer to a NDR string and append the string value to the
727    proto_item. */
728
729 int dissect_ndr_str_pointer_item(tvbuff_t *tvb, gint offset, 
730                                  packet_info *pinfo, proto_tree *tree, 
731                                  char *drep, int type, char *text, 
732                                  int hf_index, int levels)
733 {
734         return dissect_ndr_pointer_cb(
735                 tvb, offset, pinfo, tree, drep, 
736                 dissect_ndr_wchar_cvstring, type, text, hf_index, 
737                 cb_str_postprocess, GINT_TO_POINTER(levels + 1));
738 }
739
740 /*
741  * Register ett/hf values and perform DCERPC over SMB specific
742  * initialisation.
743  */
744 void dcerpc_smb_init(int proto_dcerpc)
745 {
746         static hf_register_info hf[] = {
747
748                 /* String handling */
749
750                 { &hf_nt_cs_size,
751                   { "Size", "nt.str.size", FT_UINT16, BASE_DEC,
752                     NULL, 0x0, "Size of string in short integers", 
753                     HFILL }},
754                 
755                 { &hf_nt_cs_len,
756                   { "Length", "nt.str.len", FT_UINT16, BASE_DEC,
757                     NULL, 0x0, "Length of string in short integers", 
758                     HFILL }},
759                 
760                 /* Policy handles */
761
762                 { &hf_nt_policy_open_frame,
763                   { "Frame handle opened", "dcerpc.nt.open_frame",
764                     FT_FRAMENUM, BASE_NONE, NULL, 0x0,
765                     "Frame handle opened", HFILL }},
766
767                 { &hf_nt_policy_close_frame,
768                   { "Frame handle close", "dcerpc.nt.close_frame",
769                     FT_FRAMENUM, BASE_NONE, NULL, 0x0,
770                     "Frame handle closed", HFILL }},
771         };
772
773         static gint *ett[] = {
774                 &ett_nt_unicode_string,
775                 &ett_nt_counted_string,
776                 &ett_nt_counted_byte_array,
777                 &ett_nt_policy_hnd,
778         };
779
780         /* Register ett's and hf's */
781
782         proto_register_subtree_array(ett, array_length(ett));
783         proto_register_field_array(proto_dcerpc, hf, array_length(hf));
784
785         /* Initialise policy handle hash */
786
787         init_pol_hash();
788 }