From Todd Sabin: allocate the buffer for the decrypted payload, rather
[obnox/wireshark/wip.git] / packet-smb.c
index 200760e5187810eae40fc677a0e975c7bdeb93ad..66a0da54b0bbd52e7d24d6378a69e1dbcfbcbbc8 100644 (file)
@@ -3,7 +3,7 @@
  * Copyright 1999, Richard Sharpe <rsharpe@ns.aus.com>
  * 2001  Rewrite by Ronnie Sahlberg and Guy Harris
  *
- * $Id: packet-smb.c,v 1.301 2002/12/19 11:22:37 sahlberg Exp $
+ * $Id: packet-smb.c,v 1.310 2003/02/25 02:00:32 tpot Exp $
  *
  * Ethereal - Network traffic analyzer
  * By Gerald Combs <gerald@ethereal.com>
 #include <epan/strutil.h>
 #include "prefs.h"
 #include "reassemble.h"
+#include "tap.h"
 
 #include "packet-smb-common.h"
 #include "packet-smb-mailslot.h"
 #include "packet-smb-pipe.h"
+#include "packet-dcerpc.h"
 
 /*
  * Various specifications and documents about SMB can be found in
@@ -663,6 +665,9 @@ static gint ett_smb_sec_desc_type = -1;
 static gint ett_smb_quotaflags = -1;
 static gint ett_smb_secblob = -1;
 
+
+static int smb_tap = -1;
+
 static dissector_handle_t gssapi_handle = NULL;
 static dissector_handle_t ntlmssp_handle = NULL;
 
@@ -912,27 +917,9 @@ smb_saved_info_hash_matched(gconstpointer k)
        return key->frame + key->pid_mid;
 }
 
-/*
- * The information we need to save about an NT Transaction request in order
- * to dissect the reply.
- */
-typedef struct {
-       int subcmd;
-} smb_nt_transact_info_t;
-
 static GMemChunk *smb_nt_transact_info_chunk = NULL;
 static int smb_nt_transact_info_init_count = 200;
 
-/*
- * The information we need to save about a Transaction2 request in order
- * to dissect the reply.
- */
-typedef struct {
-       int subcmd;
-       int info_level;
-       gboolean resume_keys;   /* if "return resume" keys set in T2 FIND_FIRST request */
-} smb_transact2_info_t;
-
 static GMemChunk *smb_transact2_info_chunk = NULL;
 static int smb_transact2_info_init_count = 200;
 
@@ -6311,7 +6298,7 @@ dissect_tree_connect_andx_response(tvbuff_t *tvb, packet_info *pinfo, proto_tree
 #define NT_TRANS_QSD           6
 #define NT_TRANS_GET_USER_QUOTA        7
 #define NT_TRANS_SET_USER_QUOTA 8
-static const value_string nt_cmd_vals[] = {
+const value_string nt_cmd_vals[] = {
        {NT_TRANS_CREATE,               "NT CREATE"},
        {NT_TRANS_IOCTL,                "NT IOCTL"},
        {NT_TRANS_SSD,                  "NT SET SECURITY DESC"},
@@ -6677,9 +6664,10 @@ dissect_nt_share_access(tvbuff_t *tvb, proto_tree *parent_tree, int offset)
        return offset;
 }
 
+/* FIXME: need to call dissect_nt_access_mask() instead */
 
 static int
-dissect_nt_access_mask(tvbuff_t *tvb, proto_tree *parent_tree, int offset)
+dissect_smb_access_mask(tvbuff_t *tvb, proto_tree *parent_tree, int offset)
 {
        guint32 mask;
        proto_item *item = NULL;
@@ -7014,8 +7002,12 @@ free_g_string(void *arg)
        g_string_free(arg, TRUE);
 }
 
+/* Dissect a NT SID.  Label it with 'name' and return a string version of
+   the SID in the 'sid_str' parameter which must be freed by the caller. */
+
 int
-dissect_nt_sid(tvbuff_t *tvb, int offset, proto_tree *parent_tree, char *name)
+dissect_nt_sid(tvbuff_t *tvb, int offset, proto_tree *parent_tree, char *name,
+              char **sid_str)
 {
        proto_item *item = NULL;
        proto_tree *tree = NULL;
@@ -7087,13 +7079,17 @@ dissect_nt_sid(tvbuff_t *tvb, int offset, proto_tree *parent_tree, char *name)
            proto_tree_add_text(tree, tvb, offset, 4, "RID: %u", rid);
            proto_item_append_text(item, ": S-1-%u-%s-%u", auth, gstr->str, rid);
            offset+=4;
+           if (sid_str)
+                   *sid_str = g_strdup_printf(
+                           "S-1-%u-%s-%u", auth, gstr->str, rid);
          }
          else {
            proto_item_append_text(item, ": S-1-%u-%s", auth, gstr->str);
+           if (sid_str)
+                   *sid_str = g_strdup_printf("S-1-%u-%s", auth, gstr->str);
          }
 
          CLEANUP_CALL_AND_POP;
-
        }
 
        proto_item_set_len(item, offset-old_offset);
@@ -7145,7 +7141,8 @@ static const true_false_string tfs_ace_flags_failed_access = {
        }
 
 static int
-dissect_nt_v2_ace_flags(tvbuff_t *tvb, int offset, proto_tree *parent_tree)
+dissect_nt_v2_ace_flags(tvbuff_t *tvb, int offset, proto_tree *parent_tree,
+                       guint8 *data)
 {
        proto_item *item = NULL;
        proto_tree *tree = NULL;
@@ -7153,6 +7150,11 @@ dissect_nt_v2_ace_flags(tvbuff_t *tvb, int offset, proto_tree *parent_tree)
        char *sep = " ";
 
        mask = tvb_get_guint8(tvb, offset);
+
+       if (data)
+               *data = mask;
+
+
        if(parent_tree){
                item = proto_tree_add_text(parent_tree, tvb, offset, 1,
                                           "NT ACE Flags: 0x%02x", mask);
@@ -7192,13 +7194,238 @@ dissect_nt_v2_ace_flags(tvbuff_t *tvb, int offset, proto_tree *parent_tree)
        return offset;
 }
 
+/* Dissect an access mask.  All this stuff is kind of explained at MSDN:
+
+http://msdn.microsoft.com/library/default.asp?url=/library/en-us/security/security/windows_2000_windows_nt_access_mask_format.asp
+
+*/
+
+static gint ett_nt_access_mask = -1;
+static gint ett_nt_access_mask_generic = -1;
+static gint ett_nt_access_mask_standard = -1;
+static gint ett_nt_access_mask_specific = -1;
+
+static int hf_access_sacl = -1;
+static int hf_access_maximum_allowed = -1;
+static int hf_access_generic_read = -1;
+static int hf_access_generic_write = -1;
+static int hf_access_generic_execute = -1;
+static int hf_access_generic_all = -1;
+static int hf_access_standard_delete = -1;
+static int hf_access_standard_read_control = -1;
+static int hf_access_standard_synchronise = -1;
+static int hf_access_standard_write_dac = -1;
+static int hf_access_standard_write_owner = -1;
+static int hf_access_specific_15 = -1;
+static int hf_access_specific_14 = -1;
+static int hf_access_specific_13 = -1;
+static int hf_access_specific_12 = -1;
+static int hf_access_specific_11 = -1;
+static int hf_access_specific_10 = -1;
+static int hf_access_specific_9 = -1;
+static int hf_access_specific_8 = -1;
+static int hf_access_specific_7 = -1;
+static int hf_access_specific_6 = -1;
+static int hf_access_specific_5 = -1;
+static int hf_access_specific_4 = -1;
+static int hf_access_specific_3 = -1;
+static int hf_access_specific_2 = -1;
+static int hf_access_specific_1 = -1;
+static int hf_access_specific_0 = -1;
+
+int
+dissect_nt_access_mask(tvbuff_t *tvb, gint offset, packet_info *pinfo,
+                      proto_tree *tree, char *drep, int hfindex,
+                      nt_access_mask_fn_t *specific_rights_fn)
+{
+       proto_item *item;
+       proto_tree *subtree, *generic, *standard, *specific;
+       guint32 access;
+
+       if (drep != NULL) {
+               /*
+                * Called from a DCE RPC protocol dissector, for a
+                * protocol where a 32-bit NDR integer contains
+                * an NT access mask; extract the access mask
+                * with an NDR call.
+                */
+               offset = dissect_ndr_uint32(tvb, offset, pinfo, NULL, drep,
+                                           hfindex, &access);
+       } else {
+               /*
+                * Called from SMB, where the access mask is just a
+                * 4-byte little-endian quantity with no special
+                * NDR alignment requirement; extract it with
+                * "tvb_get_letohl()".
+                */
+               access = tvb_get_letohl(tvb, offset);
+               offset += 4;
+       }
+
+       item = proto_tree_add_uint(tree, hfindex, tvb, offset - 4, 4, access);
+
+       subtree = proto_item_add_subtree(item, ett_nt_access_mask);
+
+       /* Generic access rights */
+
+       item = proto_tree_add_text(subtree, tvb, offset - 4, 4,
+                                  "Generic rights: 0x%08x",
+                                  access & GENERIC_RIGHTS_MASK);
+
+       generic = proto_item_add_subtree(item, ett_nt_access_mask_generic);
+
+       proto_tree_add_boolean(
+               generic, hf_access_generic_read, tvb, offset - 4, 4,
+               access);
+
+       proto_tree_add_boolean(
+               generic, hf_access_generic_write, tvb, offset - 4, 4,
+               access);
+
+       proto_tree_add_boolean(
+               generic, hf_access_generic_execute, tvb, offset - 4, 4,
+               access);
+
+       proto_tree_add_boolean(
+               generic, hf_access_generic_all, tvb, offset - 4, 4,
+               access);
+
+       /* Reserved (??) */
+
+       proto_tree_add_boolean(
+               subtree, hf_access_maximum_allowed, tvb, offset - 4, 4,
+               access);
+
+       /* Access system security */
+
+       proto_tree_add_boolean(
+               subtree, hf_access_sacl, tvb, offset - 4, 4,
+               access);
+
+       /* Standard access rights */
+
+       item = proto_tree_add_text(subtree, tvb, offset - 4, 4,
+                                  "Standard rights: 0x%08x",
+                                  access & STANDARD_RIGHTS_MASK);
+
+       standard = proto_item_add_subtree(item, ett_nt_access_mask_standard);
+
+       proto_tree_add_boolean(
+               standard, hf_access_standard_synchronise, tvb, offset - 4, 4,
+               access);
+
+       proto_tree_add_boolean(
+               standard, hf_access_standard_write_owner, tvb, offset - 4, 4,
+               access);
+
+       proto_tree_add_boolean(
+               standard, hf_access_standard_write_dac, tvb, offset - 4, 4,
+               access);
+
+       proto_tree_add_boolean(
+               standard, hf_access_standard_read_control, tvb, offset - 4, 4,
+               access);
+
+       proto_tree_add_boolean(
+               standard, hf_access_standard_delete, tvb, offset - 4, 4,
+               access);
+
+       /* Specific access rights.  Call the specific_rights_fn
+          pointer if we have one, otherwise just display bits 0-15 in
+          boring fashion. */
+
+       item = proto_tree_add_text(subtree, tvb, offset - 4, 4,
+                                  "Specific rights: 0x%08x",
+                                  access & SPECIFIC_RIGHTS_MASK);
+
+       specific = proto_item_add_subtree(item, ett_nt_access_mask_specific);
+
+       if (specific_rights_fn) {
+               specific_rights_fn(tvb, offset - 4, specific, access);
+               return offset;
+       }
+
+       proto_tree_add_boolean(
+               specific, hf_access_specific_15, tvb, offset - 4, 4,
+               access);
+
+       proto_tree_add_boolean(
+               specific, hf_access_specific_14, tvb, offset - 4, 4,
+               access);
+
+       proto_tree_add_boolean(
+               specific, hf_access_specific_13, tvb, offset - 4, 4,
+               access);
+
+       proto_tree_add_boolean(
+               specific, hf_access_specific_12, tvb, offset - 4, 4,
+               access);
+
+       proto_tree_add_boolean(
+               specific, hf_access_specific_11, tvb, offset - 4, 4,
+               access);
+
+       proto_tree_add_boolean(
+               specific, hf_access_specific_10, tvb, offset - 4, 4,
+               access);
+
+       proto_tree_add_boolean(
+               specific, hf_access_specific_9, tvb, offset - 4, 4,
+               access);
+
+       proto_tree_add_boolean(
+               specific, hf_access_specific_8, tvb, offset - 4, 4,
+               access);
+
+       proto_tree_add_boolean(
+               specific, hf_access_specific_7, tvb, offset - 4, 4,
+               access);
+
+       proto_tree_add_boolean(
+               specific, hf_access_specific_6, tvb, offset - 4, 4,
+               access);
+
+       proto_tree_add_boolean(
+               specific, hf_access_specific_5, tvb, offset - 4, 4,
+               access);
+
+       proto_tree_add_boolean(
+               specific, hf_access_specific_4, tvb, offset - 4, 4,
+               access);
+
+       proto_tree_add_boolean(
+               specific, hf_access_specific_3, tvb, offset - 4, 4,
+               access);
+
+       proto_tree_add_boolean(
+               specific, hf_access_specific_2, tvb, offset - 4, 4,
+               access);
+
+       proto_tree_add_boolean(
+               specific, hf_access_specific_1, tvb, offset - 4, 4,
+               access);
+
+       proto_tree_add_boolean(
+               specific, hf_access_specific_0, tvb, offset - 4, 4,
+               access);
+
+       return offset;
+}
+
+static int hf_smb_access_mask = -1;
+
 static int
-dissect_nt_v2_ace(tvbuff_t *tvb, int offset, proto_tree *parent_tree)
+dissect_nt_v2_ace(tvbuff_t *tvb, int offset, packet_info *pinfo,
+                 proto_tree *parent_tree, char *drep,
+                 nt_access_mask_fn_t *specific_rights_fn)
 {
        proto_item *item = NULL;
        proto_tree *tree = NULL;
        int old_offset = offset;
        guint16 size;
+       char *sid_str;
+       guint8 type;
+       guint8 flags;
 
        if(parent_tree){
                item = proto_tree_add_text(parent_tree, tvb, offset, -1,
@@ -7207,14 +7434,12 @@ dissect_nt_v2_ace(tvbuff_t *tvb, int offset, proto_tree *parent_tree)
        }
 
        /* type */
-       if(item){
-         proto_item_append_text(item, val_to_str(tvb_get_guint8(tvb, offset), ace_type_vals, "Unknown ACE type (%u)"));
-       }
-       proto_tree_add_item(tree, hf_smb_ace_type, tvb, offset, 1, TRUE);
+       type = tvb_get_guint8(tvb, offset);
+       proto_tree_add_uint(tree, hf_smb_ace_type, tvb, offset, 1, type);
        offset += 1;
 
        /* flags */
-       offset = dissect_nt_v2_ace_flags(tvb, offset, tree);
+       offset = dissect_nt_v2_ace_flags(tvb, offset, tree, &flags);
 
        /* size */
        size = tvb_get_letohs(tvb, offset);
@@ -7222,10 +7447,19 @@ dissect_nt_v2_ace(tvbuff_t *tvb, int offset, proto_tree *parent_tree)
        offset += 2;
 
        /* access mask */
-       offset = dissect_nt_access_mask(tvb, tree, offset);
+       offset = dissect_nt_access_mask(
+               tvb, offset, pinfo, tree, drep, hf_smb_access_mask, 
+               specific_rights_fn);
 
        /* SID */
-       offset = dissect_nt_sid(tvb, offset, tree, "ACE");
+       offset = dissect_nt_sid(tvb, offset, tree, "ACE", &sid_str);
+
+       if (item)
+               proto_item_append_text(
+                       item, "%s, flags 0x%02x, %s", sid_str, flags,
+                       val_to_str(type, ace_type_vals, "Unknown ACE type (0x%02x)"));
+
+       g_free(sid_str);
 
        proto_item_set_len(item, offset-old_offset);
 
@@ -7236,7 +7470,9 @@ dissect_nt_v2_ace(tvbuff_t *tvb, int offset, proto_tree *parent_tree)
 }
 
 static int
-dissect_nt_acl(tvbuff_t *tvb, int offset, proto_tree *parent_tree, char *name)
+dissect_nt_acl(tvbuff_t *tvb, int offset, packet_info *pinfo,
+              proto_tree *parent_tree, char *drep, char *name,
+              nt_access_mask_fn_t *specific_rights_fn)
 {
        proto_item *item = NULL;
        proto_tree *tree = NULL;
@@ -7270,7 +7506,8 @@ dissect_nt_acl(tvbuff_t *tvb, int offset, proto_tree *parent_tree, char *name)
          offset += 4;
 
          while(num_aces--){
-           offset=dissect_nt_v2_ace(tvb, offset, tree);
+           offset=dissect_nt_v2_ace(
+                   tvb, offset, pinfo, tree, drep, specific_rights_fn);
          }
        }
 
@@ -7379,7 +7616,9 @@ dissect_nt_sec_desc_type(tvbuff_t *tvb, int offset, proto_tree *parent_tree)
 }
 
 int
-dissect_nt_sec_desc(tvbuff_t *tvb, int offset, proto_tree *parent_tree, int len)
+dissect_nt_sec_desc(tvbuff_t *tvb, int offset, packet_info *pinfo,
+                   proto_tree *parent_tree, char *drep, int len, 
+                   nt_access_mask_fn_t *specific_rights_fn)
 {
        proto_item *item = NULL;
        proto_tree *tree = NULL;
@@ -7409,45 +7648,49 @@ dissect_nt_sec_desc(tvbuff_t *tvb, int offset, proto_tree *parent_tree, int len)
 
          /* offset to owner sid */
          owner_sid_offset = tvb_get_letohl(tvb, offset);
-         proto_tree_add_text(tree, tvb, offset, 4, "Offset to owner SID: %d", owner_sid_offset);
+         proto_tree_add_text(tree, tvb, offset, 4, "Offset to owner SID: %u", owner_sid_offset);
          offset += 4;
 
          /* offset to group sid */
          group_sid_offset = tvb_get_letohl(tvb, offset);
-         proto_tree_add_text(tree, tvb, offset, 4, "Offset to group SID: %d", group_sid_offset);
+         proto_tree_add_text(tree, tvb, offset, 4, "Offset to group SID: %u", group_sid_offset);
          offset += 4;
 
          /* offset to sacl */
          sacl_offset = tvb_get_letohl(tvb, offset);
-         proto_tree_add_text(tree, tvb, offset, 4, "Offset to SACL: %d", sacl_offset);
+         proto_tree_add_text(tree, tvb, offset, 4, "Offset to SACL: %u", sacl_offset);
          offset += 4;
 
          /* offset to dacl */
          dacl_offset = tvb_get_letohl(tvb, offset);
-         proto_tree_add_text(tree, tvb, offset, 4, "Offset to DACL: %d", dacl_offset);
+         proto_tree_add_text(tree, tvb, offset, 4, "Offset to DACL: %u", dacl_offset);
          offset += 4;
 
          /*owner SID*/
          if(owner_sid_offset){
            if (len == -1)
-             offset = dissect_nt_sid(tvb, offset, tree, "Owner");
+             offset = dissect_nt_sid(tvb, offset, tree, "Owner", NULL);
            else
-             dissect_nt_sid(tvb, old_offset+owner_sid_offset, tree, "Owner");
+             dissect_nt_sid(
+                     tvb, old_offset+owner_sid_offset, tree, "Owner", NULL);
          }
 
          /*group SID*/
          if(group_sid_offset){
-           dissect_nt_sid(tvb, old_offset+group_sid_offset, tree, "Group");
+           dissect_nt_sid(
+                   tvb, old_offset+group_sid_offset, tree, "Group", NULL);
          }
 
          /* sacl */
          if(sacl_offset){
-           dissect_nt_acl(tvb, old_offset+sacl_offset, tree, "System (SACL)");
+           dissect_nt_acl(tvb, old_offset+sacl_offset, pinfo, tree, 
+                          drep, "System (SACL)", specific_rights_fn);
          }
 
          /* dacl */
          if(dacl_offset){
-           dissect_nt_acl(tvb, old_offset+dacl_offset, tree, "User (DACL)");
+           dissect_nt_acl(tvb, old_offset+dacl_offset, pinfo, tree, 
+                          drep, "User (DACL)", specific_rights_fn);
          }
 
        }
@@ -7497,7 +7740,7 @@ dissect_nt_user_quota(tvbuff_t *tvb, proto_tree *tree, int offset, guint16 *bcp)
 
                /* SID of the user */
                old_sid_offset=offset;
-               offset = dissect_nt_sid(tvb, offset, tree, "Quota");
+               offset = dissect_nt_sid(tvb, offset, tree, "Quota", NULL);
                *bcp -= (offset-old_sid_offset);
 
                if(qsize){
@@ -7532,7 +7775,9 @@ dissect_nt_trans_data_request(tvbuff_t *tvb, packet_info *pinfo, int offset, pro
        case NT_TRANS_CREATE:
                /* security descriptor */
                if(ntd->sd_len){
-                       offset = dissect_nt_sec_desc(tvb, offset, tree, ntd->sd_len);
+                       offset = dissect_nt_sec_desc(
+                               tvb, offset, pinfo, tree, NULL, ntd->sd_len, 
+                               NULL);
                }
 
                /* extended attributes */
@@ -7549,7 +7794,8 @@ dissect_nt_trans_data_request(tvbuff_t *tvb, packet_info *pinfo, int offset, pro
 
                break;
        case NT_TRANS_SSD:
-               offset = dissect_nt_sec_desc(tvb, offset, tree, bc);
+               offset = dissect_nt_sec_desc(
+                       tvb, offset, pinfo, tree, NULL, bc, NULL);
                break;
        case NT_TRANS_NOTIFY:
                break;
@@ -7568,7 +7814,7 @@ dissect_nt_trans_data_request(tvbuff_t *tvb, packet_info *pinfo, int offset, pro
                proto_tree_add_text(tree, tvb, offset, 4, "Length of SID: %d", tvb_get_letohl(tvb, offset));
                offset +=4;
 
-               offset = dissect_nt_sid(tvb, offset, tree, "Quota");
+               offset = dissect_nt_sid(tvb, offset, tree, "Quota", NULL);
                break;
        case NT_TRANS_SET_USER_QUOTA:
                offset = dissect_nt_user_quota(tvb, tree, offset, &bcp);
@@ -7614,7 +7860,7 @@ dissect_nt_trans_param_request(tvbuff_t *tvb, packet_info *pinfo, int offset, pr
                COUNT_BYTES(4);
 
                /* nt access mask */
-               offset = dissect_nt_access_mask(tvb, tree, offset);
+               offset = dissect_smb_access_mask(tvb, tree, offset);
                bc -= 4;
 
                /* allocation size */
@@ -7979,7 +8225,8 @@ dissect_nt_transaction_request(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree
        }
        if(dc){
                CHECK_BYTE_COUNT(dc);
-               dissect_nt_trans_data_request(tvb, pinfo, offset, tree, dc, &ntd);
+               dissect_nt_trans_data_request(
+                       tvb, pinfo, offset, tree, dc, &ntd);
                COUNT_BYTES(dc);
        }
 
@@ -8043,14 +8290,16 @@ dissect_nt_trans_data_response(tvbuff_t *tvb, packet_info *pinfo,
        case NT_TRANS_RENAME:
                /* XXX not documented */
                break;
-       case NT_TRANS_QSD:
+       case NT_TRANS_QSD: {
                /*
                 * XXX - this is probably a SECURITY_DESCRIPTOR structure,
                 * which may be documented in the Win32 documentation
                 * somewhere.
                 */
-               offset = dissect_nt_sec_desc(tvb, offset, tree, len);
+               offset = dissect_nt_sec_desc(
+                       tvb, offset, pinfo, tree, NULL, len, NULL);
                break;
+       }
        case NT_TRANS_GET_USER_QUOTA:
                bcp=len;
                offset = dissect_nt_user_quota(tvb, tree, offset, &bcp);
@@ -8979,7 +9228,7 @@ dissect_nt_create_andx_request(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tr
        offset += 4;
 
        /* nt access mask */
-       offset = dissect_nt_access_mask(tvb, tree, offset);
+       offset = dissect_smb_access_mask(tvb, tree, offset);
 
        /* allocation size */
        proto_tree_add_item(tree, hf_smb_alloc_size64, tvb, offset, 8, TRUE);
@@ -9136,7 +9385,7 @@ dissect_nt_cancel_request(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tre
    XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX */
 
 
-static const value_string trans2_cmd_vals[] = {
+const value_string trans2_cmd_vals[] = {
        { 0x00,         "OPEN2" },
        { 0x01,         "FIND_FIRST2" },
        { 0x02,         "FIND_NEXT2" },
@@ -10395,9 +10644,9 @@ dissect_4_2_14_5(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree,
        COUNT_BYTES_SUBR(4);
 
        /* delete pending */
-       CHECK_BYTE_COUNT_SUBR(2);
-       proto_tree_add_item(tree, hf_smb_delete_pending, tvb, offset, 2, TRUE);
-       COUNT_BYTES_SUBR(2);
+       CHECK_BYTE_COUNT_SUBR(1);
+       proto_tree_add_item(tree, hf_smb_delete_pending, tvb, offset, 1, TRUE);
+       COUNT_BYTES_SUBR(1);
 
        /* is directory */
        CHECK_BYTE_COUNT_SUBR(1);
@@ -10481,7 +10730,7 @@ dissect_4_2_14_8(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
 
        /* access flags */
        CHECK_BYTE_COUNT_SUBR(4);
-       offset = dissect_nt_access_mask(tvb, tree, offset);
+       offset = dissect_smb_access_mask(tvb, tree, offset);
        COUNT_BYTES_SUBR(4);
 
        /* index number */
@@ -13625,7 +13874,7 @@ dissect_smb_command(tvbuff_t *tvb, packet_info *pinfo, int offset, proto_tree *s
  * 1, contain all entries 0x00 to 0xff
  * 2, all entries must be in order.
  */
-static const value_string smb_cmd_vals[] = {
+const value_string smb_cmd_vals[] = {
   { 0x00, "Create Directory" },
   { 0x01, "Delete Directory" },
   { 0x02, "Open" },
@@ -14031,6 +14280,7 @@ const value_string DOS_errors[] = {
   {SMBE_invalidsecuritydescriptor, "Invalid security descriptor"},
   {SMBE_invalidowner, "Invalid owner"},
   {SMBE_nomoreitems, "No more items"},
+  {SMBE_serverunavailable, "Server unavailable"},
   {0, NULL}
   };
 
@@ -15266,7 +15516,9 @@ dissect_smb(tvbuff_t *tvb, packet_info *pinfo, proto_tree *parent_tree)
        proto_tree *tree = NULL, *htree = NULL;
        guint8          flags;
        guint16         flags2;
-       smb_info_t      si;
+       static smb_info_t       si_arr[20];
+       static int si_counter=0;
+       smb_info_t              *si;
        smb_saved_info_t *sip = NULL;
        smb_saved_info_key_t key;
        smb_saved_info_key_t *new_key;
@@ -15277,6 +15529,12 @@ dissect_smb(tvbuff_t *tvb, packet_info *pinfo, proto_tree *parent_tree)
        conversation_t *conversation;
        nstime_t ns;
 
+       si_counter++;
+       if(si_counter==20){
+               si_counter=0;
+       }
+       si=&si_arr[si_counter];
+
        top_tree=parent_tree;
 
        /* must check that this really is a smb packet */
@@ -15299,22 +15557,22 @@ dissect_smb(tvbuff_t *tvb, packet_info *pinfo, proto_tree *parent_tree)
 
        /* start off using the local variable, we will allocate a new one if we
           need to*/
-       si.cmd = tvb_get_guint8(tvb, offset+4);
+       si->cmd = tvb_get_guint8(tvb, offset+4);
        flags = tvb_get_guint8(tvb, offset+9);
-       si.request = !(flags&SMB_FLAGS_DIRN);
+       si->request = !(flags&SMB_FLAGS_DIRN);
        flags2 = tvb_get_letohs(tvb, offset+10);
        if(flags2 & 0x8000){
-               si.unicode = TRUE; /* Mark them as Unicode */
+               si->unicode = TRUE; /* Mark them as Unicode */
        } else {
-               si.unicode = FALSE;
+               si->unicode = FALSE;
        }
-       si.tid = tvb_get_letohs(tvb, offset+24);
-       si.pid = tvb_get_letohs(tvb, offset+26);
-       si.uid = tvb_get_letohs(tvb, offset+28);
-       si.mid = tvb_get_letohs(tvb, offset+30);
-       pid_mid = (si.pid << 16) | si.mid;
-       si.info_level = -1;
-       si.info_count = -1;
+       si->tid = tvb_get_letohs(tvb, offset+24);
+       si->pid = tvb_get_letohs(tvb, offset+26);
+       si->uid = tvb_get_letohs(tvb, offset+28);
+       si->mid = tvb_get_letohs(tvb, offset+30);
+       pid_mid = (si->pid << 16) | si->mid;
+       si->info_level = -1;
+       si->info_count = -1;
 
        if (parent_tree) {
                item = proto_tree_add_item(parent_tree, proto_smb, tvb, offset,
@@ -15340,37 +15598,37 @@ dissect_smb(tvbuff_t *tvb, packet_info *pinfo, proto_tree *parent_tree)
                        pinfo->ptype, pinfo->srcport, pinfo->destport, 0);
        }
        /* see if we already have the smb data for this conversation */
-       si.ct=conversation_get_proto_data(conversation, proto_smb);
-       if(!si.ct){
+       si->ct=conversation_get_proto_data(conversation, proto_smb);
+       if(!si->ct){
                /* No, not yet. create it and attach it to the conversation */
-               si.ct = g_mem_chunk_alloc(conv_tables_chunk);
-               conv_tables = g_slist_prepend(conv_tables, si.ct);
-               si.ct->matched= g_hash_table_new(smb_saved_info_hash_matched,
+               si->ct = g_mem_chunk_alloc(conv_tables_chunk);
+               conv_tables = g_slist_prepend(conv_tables, si->ct);
+               si->ct->matched= g_hash_table_new(smb_saved_info_hash_matched,
                        smb_saved_info_equal_matched);
-               si.ct->unmatched= g_hash_table_new(smb_saved_info_hash_unmatched,
+               si->ct->unmatched= g_hash_table_new(smb_saved_info_hash_unmatched,
                        smb_saved_info_equal_unmatched);
-               si.ct->dcerpc_fid_to_frame=g_hash_table_new(
+               si->ct->dcerpc_fid_to_frame=g_hash_table_new(
                        smb_saved_info_hash_unmatched,
                        smb_saved_info_equal_unmatched);
-               si.ct->tid_service=g_hash_table_new(
+               si->ct->tid_service=g_hash_table_new(
                        smb_saved_info_hash_unmatched,
                        smb_saved_info_equal_unmatched);
-               conversation_add_proto_data(conversation, proto_smb, si.ct);
+               conversation_add_proto_data(conversation, proto_smb, si->ct);
        }
 
-       if( (si.request)
-           &&  (si.mid==0)
-           &&  (si.uid==0)
-           &&  (si.pid==0)
-           &&  (si.tid==0) ){
+       if( (si->request)
+           &&  (si->mid==0)
+           &&  (si->uid==0)
+           &&  (si->pid==0)
+           &&  (si->tid==0) ){
                /* this is a broadcast SMB packet, there will not be a reply.
                   We dont need to do anything
                */
-               si.unidir = TRUE;
-       } else if( (si.cmd==SMB_COM_NT_CANCEL)     /* NT Cancel */
-                  ||(si.cmd==SMB_COM_TRANSACTION_SECONDARY)   /* Transaction Secondary */
-                  ||(si.cmd==SMB_COM_TRANSACTION2_SECONDARY)   /* Transaction2 Secondary */
-                  ||(si.cmd==SMB_COM_NT_TRANSACT_SECONDARY)){ /* NT Transaction Secondary */
+               si->unidir = TRUE;
+       } else if( (si->cmd==SMB_COM_NT_CANCEL)     /* NT Cancel */
+                  ||(si->cmd==SMB_COM_TRANSACTION_SECONDARY)   /* Transaction Secondary */
+                  ||(si->cmd==SMB_COM_TRANSACTION2_SECONDARY)   /* Transaction2 Secondary */
+                  ||(si->cmd==SMB_COM_NT_TRANSACT_SECONDARY)){ /* NT Transaction Secondary */
                /* Ok, we got a special request type. This request is either
                   an NT Cancel or a continuation relative to a real request
                   in an earlier packet.  In either case, we don't expect any
@@ -15389,7 +15647,7 @@ dissect_smb(tvbuff_t *tvb, packet_info *pinfo, proto_tree *parent_tree)
                   in it.
                */
 
-               si.unidir = TRUE;  /*we dont expect an answer to this one*/
+               si->unidir = TRUE;  /*we dont expect an answer to this one*/
 
                if(!pinfo->fd->flags.visited){
                        /* try to find which original call we match and if we
@@ -15403,12 +15661,12 @@ dissect_smb(tvbuff_t *tvb, packet_info *pinfo, proto_tree *parent_tree)
                           last seen MID matching ours is the right one.
                           This can fail but is better than nothing
                        */
-                       sip=g_hash_table_lookup(si.ct->unmatched, (void *)pid_mid);
+                       sip=g_hash_table_lookup(si->ct->unmatched, (void *)pid_mid);
                        if(sip!=NULL){
                                new_key = g_mem_chunk_alloc(smb_saved_info_key_chunk);
                                new_key->frame = pinfo->fd->num;
                                new_key->pid_mid = pid_mid;
-                               g_hash_table_insert(si.ct->matched, new_key,
+                               g_hash_table_insert(si->ct->matched, new_key,
                                    sip);
                        }
                } else {
@@ -15417,7 +15675,7 @@ dissect_smb(tvbuff_t *tvb, packet_info *pinfo, proto_tree *parent_tree)
                        */
                        key.frame = pinfo->fd->num;
                        key.pid_mid = pid_mid;
-                       sip=g_hash_table_lookup(si.ct->matched, &key);
+                       sip=g_hash_table_lookup(si->ct->matched, &key);
                        if(sip==NULL){
                        /*
                          We didn't find it.
@@ -15430,7 +15688,7 @@ dissect_smb(tvbuff_t *tvb, packet_info *pinfo, proto_tree *parent_tree)
 
 
                if(sip && sip->frame_req){
-                       switch(si.cmd){
+                       switch(si->cmd){
                        case SMB_COM_NT_CANCEL:
                                proto_tree_add_uint(htree, hf_smb_cancel_to,
                                                    tvb, 0, 0, sip->frame_req);
@@ -15443,7 +15701,7 @@ dissect_smb(tvbuff_t *tvb, packet_info *pinfo, proto_tree *parent_tree)
                                break;
                        }
                } else {
-                       switch(si.cmd){
+                       switch(si->cmd){
                        case SMB_COM_NT_CANCEL:
                                proto_tree_add_text(htree, tvb, 0, 0,
                                                    "Cancellation to: <unknown frame>");
@@ -15457,13 +15715,13 @@ dissect_smb(tvbuff_t *tvb, packet_info *pinfo, proto_tree *parent_tree)
                        }
                }
        } else { /* normal bidirectional request or response */
-               si.unidir = FALSE;
+               si->unidir = FALSE;
 
                if(!pinfo->fd->flags.visited){
                        /* first see if we find an unmatched smb "equal" to
                           the current one
                        */
-                       sip=g_hash_table_lookup(si.ct->unmatched, (void *)pid_mid);
+                       sip=g_hash_table_lookup(si->ct->unmatched, (void *)pid_mid);
                        if(sip!=NULL){
                                gboolean cmd_match=FALSE;
 
@@ -15473,26 +15731,26 @@ dissect_smb(tvbuff_t *tvb, packet_info *pinfo, proto_tree *parent_tree)
                                 * that's another valid type of reply
                                 * to that command.
                                 */
-                               if(si.cmd==sip->cmd){
+                               if(si->cmd==sip->cmd){
                                        cmd_match=TRUE;
                                }
-                               else if(si.cmd==SMB_COM_NT_CANCEL){
+                               else if(si->cmd==SMB_COM_NT_CANCEL){
                                        cmd_match=TRUE;
                                }
-                               else if((si.cmd==SMB_COM_TRANSACTION_SECONDARY)
+                               else if((si->cmd==SMB_COM_TRANSACTION_SECONDARY)
                                     && (sip->cmd==SMB_COM_TRANSACTION)){
                                        cmd_match=TRUE;
                                }
-                               else if((si.cmd==SMB_COM_TRANSACTION2_SECONDARY)
+                               else if((si->cmd==SMB_COM_TRANSACTION2_SECONDARY)
                                     && (sip->cmd==SMB_COM_TRANSACTION2)){
                                        cmd_match=TRUE;
                                }
-                               else if((si.cmd==SMB_COM_NT_TRANSACT_SECONDARY)
+                               else if((si->cmd==SMB_COM_NT_TRANSACT_SECONDARY)
                                     && (sip->cmd==SMB_COM_NT_TRANSACT)){
                                        cmd_match=TRUE;
                                }
 
-                               if( (si.request) || (!cmd_match) ) {
+                               if( (si->request) || (!cmd_match) ) {
                                        /* If we are processing an SMB request but there was already
                                           another "identical" smb resuest we had not matched yet.
                                           This must mean that either we have a retransmission or that the
@@ -15507,7 +15765,7 @@ dissect_smb(tvbuff_t *tvb, packet_info *pinfo, proto_tree *parent_tree)
                                           SMBs of different cmds but with identical MID and PID values and
                                           if ethereal lost the first reply and the second request.
                                        */
-                                       g_hash_table_remove(si.ct->unmatched, (void *)pid_mid);
+                                       g_hash_table_remove(si->ct->unmatched, (void *)pid_mid);
                                        sip=NULL; /* XXX should free it as well */
                                } else {
                                        /* we have found a response to some request we have seen earlier.
@@ -15520,7 +15778,7 @@ dissect_smb(tvbuff_t *tvb, packet_info *pinfo, proto_tree *parent_tree)
                                                new_key = g_mem_chunk_alloc(smb_saved_info_key_chunk);
                                                new_key->frame = sip->frame_res;
                                                new_key->pid_mid = pid_mid;
-                                               g_hash_table_insert(si.ct->matched, new_key, sip);
+                                               g_hash_table_insert(si->ct->matched, new_key, sip);
                                        } else {
                                                /* we have already seen another response to this one, but
                                                   register it anyway so we see which request it matches
@@ -15528,28 +15786,28 @@ dissect_smb(tvbuff_t *tvb, packet_info *pinfo, proto_tree *parent_tree)
                                                new_key = g_mem_chunk_alloc(smb_saved_info_key_chunk);
                                                new_key->frame = pinfo->fd->num;
                                                new_key->pid_mid = pid_mid;
-                                               g_hash_table_insert(si.ct->matched, new_key, sip);
+                                               g_hash_table_insert(si->ct->matched, new_key, sip);
                                        }
                                }
                        }
-                       if(si.request){
+                       if(si->request){
                                sip = g_mem_chunk_alloc(smb_saved_info_chunk);
                                sip->frame_req = pinfo->fd->num;
                                sip->frame_res = 0;
                                sip->req_time.secs=pinfo->fd->abs_secs;
                                sip->req_time.nsecs=pinfo->fd->abs_usecs*1000;
                                sip->flags = 0;
-                               if(g_hash_table_lookup(si.ct->tid_service, (void *)si.tid)
+                               if(g_hash_table_lookup(si->ct->tid_service, (void *)si->tid)
                                    == (void *)TID_IPC) {
                                        sip->flags |= SMB_SIF_TID_IS_IPC;
                                }
-                               sip->cmd = si.cmd;
+                               sip->cmd = si->cmd;
                                sip->extra_info = NULL;
-                               g_hash_table_insert(si.ct->unmatched, (void *)pid_mid, sip);
+                               g_hash_table_insert(si->ct->unmatched, (void *)pid_mid, sip);
                                new_key = g_mem_chunk_alloc(smb_saved_info_key_chunk);
                                new_key->frame = sip->frame_req;
                                new_key->pid_mid = pid_mid;
-                               g_hash_table_insert(si.ct->matched, new_key, sip);
+                               g_hash_table_insert(si->ct->matched, new_key, sip);
                        }
                } else {
                        /* we have seen this packet before; check the
@@ -15562,14 +15820,14 @@ dissect_smb(tvbuff_t *tvb, packet_info *pinfo, proto_tree *parent_tree)
                        */
                        key.frame = pinfo->fd->num;
                        key.pid_mid = pid_mid;
-                       sip=g_hash_table_lookup(si.ct->matched, &key);
+                       sip=g_hash_table_lookup(si->ct->matched, &key);
                }
        }
 
        /*
         * Pass the "sip" on to subdissectors through "si".
         */
-       si.sip = sip;
+       si->sip = sip;
 
        if (sip != NULL) {
                /*
@@ -15577,7 +15835,7 @@ dissect_smb(tvbuff_t *tvb, packet_info *pinfo, proto_tree *parent_tree)
                 * this is a response or the frame with the response to this
                 * frame - if we know the frame number (i.e., it's not 0).
                 */
-               if(si.request){
+               if(si->request){
                        if (sip->frame_res != 0)
                                proto_tree_add_uint(htree, hf_smb_response_in, tvb, 0, 0, sip->frame_res);
                } else {
@@ -15596,7 +15854,7 @@ dissect_smb(tvbuff_t *tvb, packet_info *pinfo, proto_tree *parent_tree)
        }
 
        /* smb command */
-       proto_tree_add_uint_format(htree, hf_smb_cmd, tvb, offset, 1, si.cmd, "SMB Command: %s (0x%02x)", decode_smb_name(si.cmd), si.cmd);
+       proto_tree_add_uint_format(htree, hf_smb_cmd, tvb, offset, 1, si->cmd, "SMB Command: %s (0x%02x)", decode_smb_name(si->cmd), si->cmd);
        offset += 1;
 
        if(flags2 & 0x4000){
@@ -15671,26 +15929,26 @@ dissect_smb(tvbuff_t *tvb, packet_info *pinfo, proto_tree *parent_tree)
        offset += 12;
 
        /* TID */
-       proto_tree_add_uint(htree, hf_smb_tid, tvb, offset, 2, si.tid);
+       proto_tree_add_uint(htree, hf_smb_tid, tvb, offset, 2, si->tid);
        offset += 2;
 
        /* PID */
-       proto_tree_add_uint(htree, hf_smb_pid, tvb, offset, 2, si.pid);
+       proto_tree_add_uint(htree, hf_smb_pid, tvb, offset, 2, si->pid);
        offset += 2;
 
        /* UID */
-       proto_tree_add_uint(htree, hf_smb_uid, tvb, offset, 2, si.uid);
+       proto_tree_add_uint(htree, hf_smb_uid, tvb, offset, 2, si->uid);
        offset += 2;
 
        /* MID */
-       proto_tree_add_uint(htree, hf_smb_mid, tvb, offset, 2, si.mid);
+       proto_tree_add_uint(htree, hf_smb_mid, tvb, offset, 2, si->mid);
        offset += 2;
 
-       pinfo->private_data = &si;
-        dissect_smb_command(tvb, pinfo, offset, tree, si.cmd, TRUE);
+       pinfo->private_data = si;
+        dissect_smb_command(tvb, pinfo, offset, tree, si->cmd, TRUE);
 
        /* Append error info from this packet to info string. */
-       if (!si.request && check_col(pinfo->cinfo, COL_INFO)) {
+       if (!si->request && check_col(pinfo->cinfo, COL_INFO)) {
                if (flags2 & 0x4000) {
                        /*
                         * The status is an NT status code; was there
@@ -15721,6 +15979,7 @@ dissect_smb(tvbuff_t *tvb, packet_info *pinfo, proto_tree *parent_tree)
                }
        }
 
+       tap_queue_packet(smb_tap, pinfo, si);
        return TRUE;
 }
 
@@ -17736,6 +17995,147 @@ proto_register_smb(void)
        { &hf_smb_segments,
                { "SMB Segments", "smb.segment.segments", FT_NONE, BASE_NONE, NULL, 0x0,
                        "SMB Segments", HFILL }},
+
+               /* Access masks */
+
+               { &hf_smb_access_mask,
+                 { "Access required", "smb.access_mask",
+                   FT_UINT32, BASE_HEX, NULL, 0x0, "Access mask",
+                   HFILL }},
+               { &hf_access_generic_read,
+                 { "Generic read", "nt.access_mask.generic_read",
+                   FT_BOOLEAN, 32, TFS(&flags_set_truth),
+                   GENERIC_READ_ACCESS, "Generic read", HFILL }},
+
+               { &hf_access_generic_write,
+                 { "Generic write", "nt.access_mask.generic_write",
+                   FT_BOOLEAN, 32, TFS(&flags_set_truth),
+                   GENERIC_WRITE_ACCESS, "Generic write", HFILL }},
+
+               { &hf_access_generic_execute,
+                 { "Generic execute", "nt.access_mask.generic_execute",
+                   FT_BOOLEAN, 32, TFS(&flags_set_truth),
+                   GENERIC_EXECUTE_ACCESS, "Generic execute", HFILL }},
+
+               { &hf_access_generic_all,
+                 { "Generic all", "nt.access_mask.generic_all",
+                   FT_BOOLEAN, 32, TFS(&flags_set_truth),
+                   GENERIC_ALL_ACCESS, "Generic all", HFILL }},
+
+               { &hf_access_maximum_allowed,
+                 { "Maximum allowed", "nt.access_mask.maximum_allowed",
+                   FT_BOOLEAN, 32, TFS(&flags_set_truth),
+                   MAXIMUM_ALLOWED_ACCESS, "Maximum allowed", HFILL }},
+
+               { &hf_access_sacl,
+                 { "Access SACL", "nt.access_mask.access_sacl",
+                   FT_BOOLEAN, 32, TFS(&flags_set_truth),
+                   ACCESS_SACL_ACCESS, "Access SACL", HFILL }},
+
+               { &hf_access_standard_read_control,
+                 { "Read control", "nt.access_mask.read_control",
+                   FT_BOOLEAN, 32, TFS(&flags_set_truth),
+                   READ_CONTROL_ACCESS, "Read control", HFILL }},
+
+               { &hf_access_standard_delete,
+                 { "Delete", "nt.access_mask.delete",
+                   FT_BOOLEAN, 32, TFS(&flags_set_truth),
+                   DELETE_ACCESS, "Delete", HFILL }},
+
+               { &hf_access_standard_synchronise,
+                 { "Synchronise", "nt.access_mask.synchronise",
+                   FT_BOOLEAN, 32, TFS(&flags_set_truth),
+                   SYNCHRONIZE_ACCESS, "Synchronise", HFILL }},
+
+               { &hf_access_standard_write_dac,
+                 { "Write DAC", "nt.access_mask.write_dac",
+                   FT_BOOLEAN, 32, TFS(&flags_set_truth),
+                   WRITE_DAC_ACCESS, "Write DAC", HFILL }},
+
+               { &hf_access_standard_write_owner,
+                 { "Write owner", "nt.access_mask.write_owner",
+                   FT_BOOLEAN, 32, TFS(&flags_set_truth),
+                   WRITE_OWNER_ACCESS, "Write owner", HFILL }},
+
+               { &hf_access_specific_15,
+                 { "Specific access, bit 15", "nt.access_mask.specific_15",
+                   FT_BOOLEAN, 32, TFS(&flags_set_truth),
+                   0x8000, "Specific access, bit 15", HFILL }},
+
+               { &hf_access_specific_14,
+                 { "Specific access, bit 14", "nt.access_mask.specific_14",
+                   FT_BOOLEAN, 32, TFS(&flags_set_truth),
+                   0x4000, "Specific access, bit 14", HFILL }},
+
+               { &hf_access_specific_13,
+                 { "Specific access, bit 13", "nt.access_mask.specific_13",
+                   FT_BOOLEAN, 32, TFS(&flags_set_truth),
+                   0x2000, "Specific access, bit 13", HFILL }},
+
+               { &hf_access_specific_12,
+                 { "Specific access, bit 12", "nt.access_mask.specific_12",
+                   FT_BOOLEAN, 32, TFS(&flags_set_truth),
+                   0x1000, "Specific access, bit 12", HFILL }},
+
+               { &hf_access_specific_11,
+                 { "Specific access, bit 11", "nt.access_mask.specific_11",
+                   FT_BOOLEAN, 32, TFS(&flags_set_truth),
+                   0x0800, "Specific access, bit 11", HFILL }},
+
+               { &hf_access_specific_10,
+                 { "Specific access, bit 10", "nt.access_mask.specific_10",
+                   FT_BOOLEAN, 32, TFS(&flags_set_truth),
+                   0x0400, "Specific access, bit 10", HFILL }},
+
+               { &hf_access_specific_9,
+                 { "Specific access, bit 9", "nt.access_mask.specific_9",
+                   FT_BOOLEAN, 32, TFS(&flags_set_truth),
+                   0x0200, "Specific access, bit 9", HFILL }},
+
+               { &hf_access_specific_8,
+                 { "Specific access, bit 8", "nt.access_mask.specific_8",
+                   FT_BOOLEAN, 32, TFS(&flags_set_truth),
+                   0x0100, "Specific access, bit 8", HFILL }},
+
+               { &hf_access_specific_7,
+                 { "Specific access, bit 7", "nt.access_mask.specific_7",
+                   FT_BOOLEAN, 32, TFS(&flags_set_truth),
+                   0x0080, "Specific access, bit 7", HFILL }},
+
+               { &hf_access_specific_6,
+                 { "Specific access, bit 6", "nt.access_mask.specific_6",
+                   FT_BOOLEAN, 32, TFS(&flags_set_truth),
+                   0x0040, "Specific access, bit 6", HFILL }},
+
+               { &hf_access_specific_5,
+                 { "Specific access, bit 5", "nt.access_mask.specific_5",
+                   FT_BOOLEAN, 32, TFS(&flags_set_truth),
+                   0x0020, "Specific access, bit 5", HFILL }},
+
+               { &hf_access_specific_4,
+                 { "Specific access, bit 4", "nt.access_mask.specific_4",
+                   FT_BOOLEAN, 32, TFS(&flags_set_truth),
+                   0x0010, "Specific access, bit 4", HFILL }},
+
+               { &hf_access_specific_3,
+                 { "Specific access, bit 3", "nt.access_mask.specific_3",
+                   FT_BOOLEAN, 32, TFS(&flags_set_truth),
+                   0x0008, "Specific access, bit 3", HFILL }},
+
+               { &hf_access_specific_2,
+                 { "Specific access, bit 2", "nt.access_mask.specific_2",
+                   FT_BOOLEAN, 32, TFS(&flags_set_truth),
+                   0x0004, "Specific access, bit 2", HFILL }},
+
+               { &hf_access_specific_1,
+                 { "Specific access, bit 1", "nt.access_mask.specific_1",
+                   FT_BOOLEAN, 32, TFS(&flags_set_truth),
+                   0x0002, "Specific access, bit 1", HFILL }},
+
+               { &hf_access_specific_0,
+                 { "Specific access, bit 0", "nt.access_mask.specific_0",
+                   FT_BOOLEAN, 32, TFS(&flags_set_truth),
+                   0x0001, "Specific access, bit 0", HFILL }},
        };
        static gint *ett[] = {
                &ett_smb,
@@ -17813,6 +18213,10 @@ proto_register_smb(void)
                &ett_smb_quotaflags,
                &ett_smb_secblob,
                &ett_smb_mac_support_flags,
+               &ett_nt_access_mask,
+               &ett_nt_access_mask_generic,
+               &ett_nt_access_mask_standard,
+               &ett_nt_access_mask_specific,
        };
        module_t *smb_module;
 
@@ -17832,6 +18236,7 @@ proto_register_smb(void)
                &smb_dcerpc_reassembly);
        register_init_routine(smb_trans_reassembly_init);
        register_init_routine(smb_dcerpc_reassembly_init);
+       smb_tap = register_tap("smb");
 }
 
 void