Use "tvb_get_ntohieee_float()" to fetch floating-point numbers from the
[obnox/wireshark/wip.git] / packet-smb.c
index c6e082534b23b7f97f1b7033ee59835d6b537222..c2119f0856a2b57c21fa23255faa1e980ffe3cbb 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.209 2002/02/21 18:39:49 tpot Exp $
+ * $Id: packet-smb.c,v 1.249 2002/04/24 07:19:25 tpot Exp $
  *
  * Ethereal - Network traffic analyzer
  * By Gerald Combs <gerald@ethereal.com>
@@ -538,6 +538,16 @@ static int hf_smb_fs_attr_fc = -1;
 static int hf_smb_fs_attr_vq = -1;
 static int hf_smb_fs_attr_dim = -1;
 static int hf_smb_fs_attr_vic = -1;
+static int hf_smb_quota_flags_enabled = -1;
+static int hf_smb_quota_flags_deny_disk = -1;
+static int hf_smb_quota_flags_log_limit = -1;
+static int hf_smb_quota_flags_log_warning = -1;
+static int hf_smb_soft_quota_limit = -1;
+static int hf_smb_hard_quota_limit = -1;
+static int hf_smb_user_quota_used = -1;
+static int hf_smb_user_quota_offset = -1;
+static int hf_smb_nt_rename_level = -1;
+static int hf_smb_cluster_count = -1;
 
 static gint ett_smb = -1;
 static gint ett_smb_hdr = -1;
@@ -582,6 +592,8 @@ static gint ett_smb_nt_create_options = -1;
 static gint ett_smb_nt_share_access = -1;
 static gint ett_smb_nt_security_flags = -1;
 static gint ett_smb_nt_trans_setup = -1;
+static gint ett_smb_nt_trans_data = -1;
+static gint ett_smb_nt_trans_param = -1;
 static gint ett_smb_nt_notify_completion_filter = -1;
 static gint ett_smb_nt_ioctl_flags = -1;
 static gint ett_smb_security_information_mask = -1;
@@ -605,6 +617,7 @@ static gint ett_smb_acl = -1;
 static gint ett_smb_ace = -1;
 static gint ett_smb_ace_flags = -1;
 static gint ett_smb_sec_desc_type = -1;
+static gint ett_smb_quotaflags = -1;
 
 proto_tree *top_tree=NULL;     /* ugly */
 
@@ -1158,6 +1171,10 @@ dissect_smb_64bit_time(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int
        guint32 filetime_high, filetime_low;
        nstime_t ts;
 
+       /* XXX there seems also to be another special time value which is fairly common :
+          0x40000000 00000000  
+          the meaning of this one is yet unknown 
+       */
        if (tree) {
                filetime_low = tvb_get_letohl(tvb, offset);
                filetime_high = tvb_get_letohl(tvb, offset + 4);
@@ -1167,11 +1184,11 @@ dissect_smb_64bit_time(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int
                            proto_registrar_get_name(hf_date));
                } else if(filetime_low==0 && filetime_high==0x80000000){
                        proto_tree_add_text(tree, tvb, offset, 8,
-                           "%s: Infinity (absolute time)",
+                           "%s: Infinity (relative time)",
                            proto_registrar_get_name(hf_date));
                } else if(filetime_low==0xffffffff && filetime_high==0x7fffffff){
                        proto_tree_add_text(tree, tvb, offset, 8,
-                           "%s: Infinity (relative time)",
+                           "%s: Infinity (absolute time)",
                            proto_registrar_get_name(hf_date));
                } else {                        
                        if (nt_time_to_nstime(filetime_high, filetime_low, &ts)) {
@@ -2862,6 +2879,69 @@ dissect_rename_file_request(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
        return offset;
 }
 
+static int
+dissect_nt_rename_file_request(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int offset, proto_tree *smb_tree)
+{
+       int fn_len;
+       const char *fn;
+       guint8 wc;
+       guint16 bc;
+
+       WORD_COUNT;
+
+       /* search attributes */
+       offset = dissect_search_attributes(tvb, pinfo, tree, offset);
+    proto_tree_add_uint(tree, hf_smb_nt_rename_level, tvb, offset, 2, tvb_get_letohs(tvb, offset));
+    offset += 2;
+
+    proto_tree_add_item(tree, hf_smb_cluster_count, tvb, offset, 4, TRUE);
+    offset += 4;
+
+       BYTE_COUNT;
+
+       /* buffer format */
+       CHECK_BYTE_COUNT(1);
+       proto_tree_add_item(tree, hf_smb_buffer_format, tvb, offset, 1, TRUE);
+       COUNT_BYTES(1);
+
+       /* old file name */
+       fn = get_unicode_or_ascii_string(tvb, &offset, pinfo, &fn_len,
+               FALSE, FALSE, &bc);
+       if (fn == NULL)
+               goto endofcommand;
+       proto_tree_add_string(tree, hf_smb_old_file_name, tvb, offset, fn_len,
+               fn);
+       COUNT_BYTES(fn_len);
+
+       if (check_col(pinfo->cinfo, COL_INFO)) {
+               col_append_fstr(pinfo->cinfo, COL_INFO, ", Old Name: %s", fn);
+       }
+
+       /* buffer format */
+       CHECK_BYTE_COUNT(1);
+       proto_tree_add_item(tree, hf_smb_buffer_format, tvb, offset, 1, TRUE);
+       COUNT_BYTES(1);
+
+       /* file name */
+       fn = get_unicode_or_ascii_string(tvb, &offset, pinfo, &fn_len,
+               FALSE, FALSE, &bc);
+       if (fn == NULL)
+               goto endofcommand;
+       proto_tree_add_string(tree, hf_smb_file_name, tvb, offset, fn_len,
+               fn);
+       COUNT_BYTES(fn_len);
+
+       if (check_col(pinfo->cinfo, COL_INFO)) {
+               col_append_fstr(pinfo->cinfo, COL_INFO, ", New Name: %s", fn);
+       }
+
+       END_OF_SMB
+
+       return offset;
+}
+
+
 static int
 dissect_query_information_request(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int offset, proto_tree *smb_tree)
 {
@@ -2975,7 +3055,9 @@ static int
 dissect_read_file_request(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int offset, proto_tree *smb_tree)
 {
        guint8 wc;
-       guint16 bc, fid;
+       guint16 bc;
+       smb_info_t *si;
+       unsigned int fid;
 
        WORD_COUNT;
 
@@ -2983,6 +3065,11 @@ dissect_read_file_request(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, i
        fid = tvb_get_letohs(tvb, offset);
        add_fid(tvb, pinfo, tree, offset, 2, fid);
        offset += 2;
+       if (!pinfo->fd->flags.visited) {
+               /* remember the FID for the processing of the response */
+               si = (smb_info_t *)pinfo->private_data;
+               si->sip->extra_info=(void *)fid;
+       }
 
        /* read count */
        proto_tree_add_item(tree, hf_smb_count, tvb, offset, 2, TRUE);
@@ -3027,11 +3114,38 @@ dissect_file_data(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int offse
        return offset;
 }
 
+static int
+dissect_file_data_dcerpc(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
+    proto_tree *top_tree, int offset, guint16 bc, guint16 datalen, guint16 fid)
+{
+       int tvblen;
+       tvbuff_t *dcerpc_tvb;
+
+       if(bc>datalen){
+               /* We have some initial padding bytes. */
+               /* XXX - use the data offset here instead? */
+               proto_tree_add_item(tree, hf_smb_padding, tvb, offset, bc-datalen,
+                       TRUE);
+               offset += bc-datalen;
+               bc = datalen;
+       }
+       tvblen = tvb_length_remaining(tvb, offset);
+       dcerpc_tvb = tvb_new_subset(tvb, offset, tvblen, bc);
+       dissect_pipe_dcerpc(dcerpc_tvb, pinfo, top_tree, tree, fid);
+       if(bc>tvblen)
+               offset += tvblen;
+       else
+               offset += bc;
+       return offset;
+}
+
 static int
 dissect_read_file_response(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int offset, proto_tree *smb_tree)
 {
        guint16 cnt=0, bc;
        guint8 wc;
+       smb_info_t *si = (smb_info_t *)pinfo->private_data;
+       int fid=0;
 
        WORD_COUNT;
 
@@ -3044,6 +3158,13 @@ dissect_read_file_response(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
        proto_tree_add_item(tree, hf_smb_reserved, tvb, offset, 8, TRUE);
        offset += 8;
 
+       /* If we have seen the request, then print which FID this refers to */
+       /* first check if we have seen the request */
+       if(si->sip != NULL && si->sip->frame_req>0){
+               fid=(int)si->sip->extra_info;
+               add_fid(tvb, pinfo, tree, 0, 0, fid);
+       }
+
        BYTE_COUNT;
 
        /* buffer format */
@@ -3056,9 +3177,19 @@ dissect_read_file_response(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
        proto_tree_add_item(tree, hf_smb_data_len, tvb, offset, 2, TRUE);
        COUNT_BYTES(2);
 
-       if (bc != 0) {
-               /* file data */
-               offset = dissect_file_data(tvb, pinfo, tree, offset, bc, bc);
+       /* another way to transport DCERPC over SMB is to skip Transaction completely and just
+          read write */
+       if(bc){
+               if(si->sip != NULL && si->sip->flags&SMB_SIF_TID_IS_IPC){
+                       /* dcerpc call */
+                       offset = dissect_file_data_dcerpc(tvb, pinfo, tree,
+                           top_tree, offset, bc, bc, fid);
+               } else {
+                       /* ordinary file data, or we didn't see the request,
+                          so we don't know whether this is a DCERPC call
+                          or not */
+                       offset = dissect_file_data(tvb, pinfo, tree, offset, bc, bc);
+               }
                bc = 0;
        }
 
@@ -3106,8 +3237,9 @@ static int
 dissect_write_file_request(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int offset, proto_tree *smb_tree)
 {
        guint32 ofs=0;
-       guint16 cnt=0, bc, fid;
+       guint16 cnt=0, bc, fid=0;
        guint8 wc;
+       smb_info_t *si = (smb_info_t *)pinfo->private_data;
 
        WORD_COUNT;
 
@@ -3147,14 +3279,15 @@ dissect_write_file_request(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
        proto_tree_add_item(tree, hf_smb_data_len, tvb, offset, 2, TRUE);
        COUNT_BYTES(2);
 
-       if (check_col(pinfo->cinfo, COL_INFO))
-               col_append_fstr(pinfo->cinfo, COL_INFO, 
-                               ", %d byte%s at offset %d", cnt, 
-                               (cnt == 1) ? "" : "s", ofs);
-
        if (bc != 0) {
-               /* file data */
-               offset = dissect_file_data(tvb, pinfo, tree, offset, bc, bc);
+               if( (si->sip && si->sip->flags&SMB_SIF_TID_IS_IPC) && (ofs==0) ){
+                       /* dcerpc call */
+                       offset = dissect_file_data_dcerpc(tvb, pinfo, tree,
+                           top_tree, offset, bc, bc, fid);
+               } else {
+                       /* ordinary file data */
+                       offset = dissect_file_data(tvb, pinfo, tree, offset, bc, bc);
+               }
                bc = 0;
        }
 
@@ -4772,6 +4905,7 @@ dissect_read_andx_response(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
        guint8  wc, cmd=0xff;
        guint16 andxoffset=0, bc, datalen=0, dataoffset=0;
        smb_info_t *si = (smb_info_t *)pinfo->private_data;
+       int fid=0;
 
        WORD_COUNT;
 
@@ -4796,7 +4930,8 @@ dissect_read_andx_response(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
        /* If we have seen the request, then print which FID this refers to */
        /* first check if we have seen the request */
        if(si->sip != NULL && si->sip->frame_req>0){
-               add_fid(tvb, pinfo, tree, 0, 0, (int)si->sip->extra_info);
+               fid=(int)si->sip->extra_info;
+               add_fid(tvb, pinfo, tree, 0, 0, fid);
        }
 
        /* remaining */
@@ -4873,9 +5008,21 @@ dissect_read_andx_response(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
                }
        }
 
-       /* file data */
-       offset = dissect_file_data(tvb, pinfo, tree, offset, bc, datalen);
-       bc = 0;
+       /* another way to transport DCERPC over SMB is to skip Transaction completely and just
+          read write */
+       if(bc){
+               if(si->sip != NULL && si->sip->flags&SMB_SIF_TID_IS_IPC){
+                       /* dcerpc call */
+                       offset = dissect_file_data_dcerpc(tvb, pinfo, tree,
+                           top_tree, offset, bc, datalen, fid);
+               } else {
+                       /* ordinary file data, or we didn't see the request,
+                          so we don't know whether this is a DCERPC call
+                          or not */
+                       offset = dissect_file_data(tvb, pinfo, tree, offset, bc, datalen);
+               }
+               bc = 0;
+       }
 
        END_OF_SMB
 
@@ -4888,10 +5035,11 @@ dissect_read_andx_response(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
 static int
 dissect_write_andx_request(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int offset, proto_tree *smb_tree)
 {
+       guint32 ofs=0;
        guint8  wc, cmd=0xff;
        guint16 andxoffset=0, bc, datalen=0, dataoffset=0;
        smb_info_t *si = (smb_info_t *)pinfo->private_data;
-       unsigned int fid;
+       unsigned int fid=0;
 
        WORD_COUNT;
 
@@ -4923,6 +5071,7 @@ dissect_write_andx_request(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
        }
 
        /* offset */
+       ofs = tvb_get_letohl(tvb, offset);
        proto_tree_add_item(tree, hf_smb_offset, tvb, offset, 4, TRUE);
        offset += 4;
 
@@ -5001,8 +5150,18 @@ dissect_write_andx_request(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
        }
 
        /* file data */
-       offset = dissect_file_data(tvb, pinfo, tree, offset, bc, datalen);
-       bc = 0;
+       if (bc != 0) {
+               if( (si->sip && si->sip->flags&SMB_SIF_TID_IS_IPC) && (ofs==0) ){
+                       /* dcerpc call */
+                       offset = dissect_file_data_dcerpc(tvb, pinfo, tree,
+                           top_tree, offset, bc, datalen, fid);
+               } else {
+                       /* ordinary file data */
+                       offset = dissect_file_data(tvb, pinfo, tree, offset,
+                           bc, datalen);
+               }
+               bc = 0;
+       }
 
        END_OF_SMB
 
@@ -5308,8 +5467,14 @@ dissect_session_setup_andx_request(tvbuff_t *tvb, packet_info *pinfo, proto_tree
                COUNT_BYTES(dn_len);
 
                if (check_col(pinfo->cinfo, COL_INFO)) {
-                       col_append_fstr(pinfo->cinfo, COL_INFO, ", User: %s@%s",
-                       an,dn);
+                       col_append_fstr(pinfo->cinfo, COL_INFO, ", User: ");
+
+                       if (!dn[0] && !an[0])
+                               col_append_fstr(pinfo->cinfo, COL_INFO, 
+                                               "anonymous");
+                       else
+                               col_append_fstr(pinfo->cinfo, COL_INFO, 
+                                               "%s\\%s", dn,an);
                }
 
                /* OS */
@@ -5704,6 +5869,22 @@ dissect_tree_connect_andx_response(tvbuff_t *tvb, packet_info *pinfo, proto_tree
                offset, an_len, an);
        COUNT_BYTES(an_len);
 
+       /* Now when we know the service type, store it so that we know it for later commands down
+          this tree */
+       if(!pinfo->fd->flags.visited){
+               smb_info_t *si = (smb_info_t *)pinfo->private_data;
+               /* Remove any previous entry for this TID */
+               if(g_hash_table_lookup(si->ct->tid_service, (void *)si->tid)){
+                       g_hash_table_remove(si->ct->tid_service, (void *)si->tid);
+               }
+               if(strcmp(an,"IPC") == 0){
+                       g_hash_table_insert(si->ct->tid_service, (void *)si->tid, (void *)TID_IPC);
+               } else {
+                       g_hash_table_insert(si->ct->tid_service, (void *)si->tid, (void *)TID_NORMAL);
+               }
+       }
+
+
        if(wc==3){
                if (bc != 0) {
                        /*
@@ -5740,13 +5921,17 @@ dissect_tree_connect_andx_response(tvbuff_t *tvb, packet_info *pinfo, proto_tree
 #define NT_TRANS_NOTIFY                4
 #define NT_TRANS_RENAME                5
 #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[] = {
-       {NT_TRANS_CREATE,       "NT CREATE"},
-       {NT_TRANS_IOCTL,        "NT IOCTL"},
-       {NT_TRANS_SSD,          "NT SET SECURITY DESC"},
-       {NT_TRANS_NOTIFY,       "NT NOTIFY"},
-       {NT_TRANS_RENAME,       "NT RENAME"},
-       {NT_TRANS_QSD,          "NT QUERY SECURITY DESC"},
+       {NT_TRANS_CREATE,               "NT CREATE"},
+       {NT_TRANS_IOCTL,                "NT IOCTL"},
+       {NT_TRANS_SSD,                  "NT SET SECURITY DESC"},
+       {NT_TRANS_NOTIFY,               "NT NOTIFY"},
+       {NT_TRANS_RENAME,               "NT RENAME"},
+       {NT_TRANS_QSD,                  "NT QUERY SECURITY DESC"},
+       {NT_TRANS_GET_USER_QUOTA,       "NT GET USER QUOTA"},
+       {NT_TRANS_SET_USER_QUOTA,       "NT SET USER QUOTA"},
        {0, NULL}
 };
 
@@ -6448,9 +6633,12 @@ dissect_nt_sid(tvbuff_t *tvb, packet_info *pinfo, int offset, proto_tree *parent
 {
        proto_item *item = NULL;
        proto_tree *tree = NULL;
-       int old_offset = offset;
+       int old_offset = offset, sa_offset = offset;
+        guint *s_auths = NULL;
+       guint rid;
        guint8 revision;
        guint8 num_auth;
+        guint auth = 0;   /* FIXME: What if it is larger than 32-bits */
        int i;
        GString *gstr;
 
@@ -6476,37 +6664,57 @@ dissect_nt_sid(tvbuff_t *tvb, packet_info *pinfo, int offset, proto_tree *parent
          /* XXX perhaps we should have these thing searchable?
             a new FT_xxx thingie? SMB is quite common!*/
          /* identifier authorities */
-         gstr = g_string_new(NULL);
 
-         CLEANUP_PUSH(free_g_string, gstr);
-         
-         g_string_sprintf(gstr, "S-1");
-
-         proto_tree_add_text(tree, tvb, offset, 6, "Authorities");
+          /* FIXME: We should dynamically allocate the authorities array,
+             which is only one thing. Then we don't have to allocate two
+             strings below etc ...
+          */
 
          for(i=0;i<6;i++){
-           guint8 auth = tvb_get_guint8(tvb, offset);
+           auth = (auth << 8) + tvb_get_guint8(tvb, offset);
 
-           if (auth > 0)
-             g_string_sprintfa(gstr,"-%u", auth);
            offset++;
          }
 
-         proto_tree_add_text(tree, tvb, offset, num_auth * 4, "Sub-authorities");
+         proto_tree_add_text(tree, tvb, offset - 6, 6, "Authority: %u", auth);
+
+          sa_offset = offset;
+
+         CLEANUP_PUSH(free, s_auths);
+
+          s_auths = g_malloc(sizeof(guint) * num_auth);
 
-         /* sub authorities */
-         for(i=0;i<num_auth;i++){
+         /* sub authorities, leave RID to last */
+         /* FIXME: If we take an exception now, we lose the whole 
+            sub-authorities string thang */
+         for(i=0; i < (num_auth > 4?(num_auth - 1):num_auth); i++){
            /* XXX should not be letohl but native byteorder according to
               samba header files. considering that all non-x86 NT ports
               are dead we can (?) assume that non le byte encodings
               will be "uncommon"?*/
-           g_string_sprintfa(gstr, "-%u",tvb_get_letohl(tvb, offset));
-           offset+=4;
+              s_auths[i] = tvb_get_letohl(tvb, offset);
+              offset+=4;
          }
 
-         proto_item_append_text(item, ": %s", gstr->str);  
-
          CLEANUP_CALL_AND_POP;
+
+          gstr = g_string_new("");
+          
+          for (i = 0; i < (num_auth>4?(num_auth - 1):num_auth); i++)
+              g_string_sprintfa(gstr, (i>0 ? "-%u" : "%u"), s_auths[i]);
+
+          proto_tree_add_text(tree, tvb, sa_offset, num_auth * 4, "Sub-authorities: %s", gstr->str);
+
+         if (num_auth > 4) {
+           rid = tvb_get_letohl(tvb, offset);
+           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;
+         }
+         else {
+           proto_item_append_text(item, ": S-1-%u-%s", auth, gstr->str);  
+         }
+
        }
 
        proto_item_set_len(item, offset-old_offset);
@@ -6551,9 +6759,11 @@ static const true_false_string tfs_ace_flags_failed_access = {
 };
 
 #define APPEND_ACE_TEXT(flag, item, string) \
-        if(item && flag){                                     \
-                  proto_item_append_text(item, string);       \
-        }
+       if(flag){                                                       \
+               if(item)                                                \
+                       proto_item_append_text(item, string, sep);      \
+               sep = ", ";                                             \
+       }
 
 static int
 dissect_nt_v2_ace_flags(tvbuff_t *tvb, packet_info *pinfo, int offset, proto_tree *parent_tree)
@@ -6561,41 +6771,42 @@ dissect_nt_v2_ace_flags(tvbuff_t *tvb, packet_info *pinfo, int offset, proto_tre
        proto_item *item = NULL;
        proto_tree *tree = NULL;
        guint8 mask;
+       char *sep = " ";
 
        mask = tvb_get_guint8(tvb, offset);
        if(parent_tree){
                item = proto_tree_add_text(parent_tree, tvb, offset, 1,
-                                          "NT ACE Flags:0x%02x", mask);
+                                          "NT ACE Flags: 0x%02x", mask);
                tree = proto_item_add_subtree(item, ett_smb_ace_flags);
        }
 
        proto_tree_add_boolean(tree, hf_smb_ace_flags_failed_access,
                       tvb, offset, 1, mask);
-       APPEND_ACE_TEXT(mask&0x80, item, "  Failed Access,");
+       APPEND_ACE_TEXT(mask&0x80, item, "%sFailed Access");
 
        proto_tree_add_boolean(tree, hf_smb_ace_flags_successful_access,
                       tvb, offset, 1, mask);
-       APPEND_ACE_TEXT(mask&0x40, item, "  Successful Access,");
+       APPEND_ACE_TEXT(mask&0x40, item, "%sSuccessful Access");
 
        proto_tree_add_boolean(tree, hf_smb_ace_flags_inherited_ace,
                       tvb, offset, 1, mask);
-       APPEND_ACE_TEXT(mask&0x10, item, "  Inherited ACE,");
+       APPEND_ACE_TEXT(mask&0x10, item, "%sInherited ACE");
 
        proto_tree_add_boolean(tree, hf_smb_ace_flags_inherit_only,
                       tvb, offset, 1, mask);
-       APPEND_ACE_TEXT(mask&0x08, item, "  Inherit Only,");
+       APPEND_ACE_TEXT(mask&0x08, item, "%sInherit Only");
 
        proto_tree_add_boolean(tree, hf_smb_ace_flags_non_propagate_inherit,
                       tvb, offset, 1, mask);
-       APPEND_ACE_TEXT(mask&0x04, item, "  No Propagate Inherit,");
+       APPEND_ACE_TEXT(mask&0x04, item, "%sNo Propagate Inherit");
 
        proto_tree_add_boolean(tree, hf_smb_ace_flags_container_inherit,
                       tvb, offset, 1, mask);
-       APPEND_ACE_TEXT(mask&0x02, item, "  Container Inherit,");
+       APPEND_ACE_TEXT(mask&0x02, item, "%sContainer Inherit");
 
        proto_tree_add_boolean(tree, hf_smb_ace_flags_object_inherit,
                       tvb, offset, 1, mask);
-       APPEND_ACE_TEXT(mask&0x01, item, "  Object Inherit,");
+       APPEND_ACE_TEXT(mask&0x01, item, "%sObject Inherit");
 
 
        offset += 1;
@@ -6608,6 +6819,7 @@ dissect_nt_v2_ace(tvbuff_t *tvb, packet_info *pinfo, int offset, proto_tree *par
        proto_item *item = NULL;
        proto_tree *tree = NULL;
        int old_offset = offset;
+       guint16 size;
        
        if(parent_tree){
                item = proto_tree_add_text(parent_tree, tvb, offset, -1,
@@ -6626,7 +6838,8 @@ dissect_nt_v2_ace(tvbuff_t *tvb, packet_info *pinfo, int offset, proto_tree *par
        offset = dissect_nt_v2_ace_flags(tvb, pinfo, offset, tree);
 
        /* size */
-       proto_tree_add_item(tree, hf_smb_ace_size, tvb, offset, 2, TRUE);
+       size = tvb_get_letohs(tvb, offset);
+       proto_tree_add_uint(tree, hf_smb_ace_size, tvb, offset, 2, size);
        offset += 2;
 
        /* access mask */
@@ -6636,7 +6849,11 @@ dissect_nt_v2_ace(tvbuff_t *tvb, packet_info *pinfo, int offset, proto_tree *par
        offset = dissect_nt_sid(tvb, pinfo, offset, tree, "ACE");
 
        proto_item_set_len(item, offset-old_offset);
-       return offset;
+
+       /* Sometimes there is some spare space at the end of the ACE so use
+          the size field to work out where the end is. */
+
+       return old_offset + size;
 }
 
 static int
@@ -6782,7 +6999,19 @@ dissect_nt_sec_desc_type(tvbuff_t *tvb, packet_info *pinfo, int offset, proto_tr
        return offset;
 }
 
+/* This function is also called from DCREPC services; it may be that, in
+   some cases, the NDR syntax must be followed, but that's not the case,
+   for example, for the security descriptor inside an LSA Security
+   Descriptor structure.
 
+   A "len" of -1 means that the NDR syntax must be followed.
+   In that case, we assume that owner SID, group SID, SACL, and DACL objects
+   are always stored in order (when present) and that all of them are aligned
+   on a 4 byte boundary, and we no longer use the xxx_offset other than to
+   check that they are non-NULL to be compatible with DCERPC NDR Unique.
+
+   Otherwise, we use the offsets to see where the owner SID, group SID,
+   SACL, and DACL are stored. */
 int
 dissect_nt_sec_desc(tvbuff_t *tvb, packet_info *pinfo, int offset, proto_tree *parent_tree, int len)
 {
@@ -6834,43 +7063,116 @@ dissect_nt_sec_desc(tvbuff_t *tvb, packet_info *pinfo, int offset, proto_tree *p
 
          /*owner SID*/
          if(owner_sid_offset){
-           dissect_nt_sid(tvb, pinfo, old_offset+owner_sid_offset, tree, "Owner");
+           if (len == -1)
+             offset = dissect_nt_sid(tvb, pinfo, offset, tree, "Owner");
+           else
+             dissect_nt_sid(tvb, pinfo, old_offset+owner_sid_offset, tree, "Owner");
          }
 
          /*group SID*/
          if(group_sid_offset){
-           dissect_nt_sid(tvb, pinfo, old_offset+group_sid_offset, tree, "Group");
+           if (len == -1)
+             offset = dissect_nt_sid(tvb, pinfo, offset, tree, "Group");
+           else
+             dissect_nt_sid(tvb, pinfo, old_offset+group_sid_offset, tree, "Group");
          }
 
          /* sacl */
          if(sacl_offset){
-           dissect_nt_acl(tvb, pinfo, old_offset+sacl_offset, tree, "System (SACL)");
+           if (len == -1)
+             offset = dissect_nt_acl(tvb, pinfo, offset, tree, "System (SACL)");
+           else
+             dissect_nt_acl(tvb, pinfo, old_offset+sacl_offset, tree, "System (SACL)");
          }
 
          /* dacl */
          if(dacl_offset){
-           dissect_nt_acl(tvb, pinfo, old_offset+dacl_offset, tree, "User (DACL)");
+           if (len == -1)
+             offset = dissect_nt_acl(tvb, pinfo, offset, tree, "User (DACL)");
+           else
+             dissect_nt_acl(tvb, pinfo, old_offset+dacl_offset, tree, "User (DACL)");
          }
 
        }
 
-       return offset+len;
+       if (len == -1) {
+               proto_item_set_len(item, offset-old_offset);
+               return offset;
+       } else
+               return offset+len;
 }
 
 static int
-dissect_nt_trans_data_request(tvbuff_t *tvb, packet_info *pinfo, int offset, proto_tree *parent_tree, int len, nt_trans_data *ntd)
+dissect_nt_user_quota(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int offset, guint16 *bcp)
+{
+       int old_offset, old_sid_offset;
+       guint32 qsize;
+
+       do {
+               old_offset=offset;
+
+               CHECK_BYTE_COUNT_TRANS_SUBR(4);
+               qsize=tvb_get_letohl(tvb, offset);
+               proto_tree_add_uint(tree, hf_smb_user_quota_offset, tvb, offset, 4, qsize);
+               COUNT_BYTES_TRANS_SUBR(4);
+
+               CHECK_BYTE_COUNT_TRANS_SUBR(4);
+               /* length of SID */
+               proto_tree_add_text(tree, tvb, offset, 4, "Length of SID: %d", tvb_get_letohl(tvb, offset));
+               COUNT_BYTES_TRANS_SUBR(4);
+
+               /* 16 unknown bytes */
+               CHECK_BYTE_COUNT_TRANS_SUBR(8);
+               proto_tree_add_item(tree, hf_smb_unknown, tvb,
+                           offset, 8, TRUE);
+               COUNT_BYTES_TRANS_SUBR(8);
+
+               /* number of bytes for used quota */
+               CHECK_BYTE_COUNT_TRANS_SUBR(8);
+               proto_tree_add_item(tree, hf_smb_user_quota_used, tvb, offset, 8, TRUE);
+               COUNT_BYTES_TRANS_SUBR(8);
+
+               /* number of bytes for quota warning */
+               CHECK_BYTE_COUNT_TRANS_SUBR(8);
+               proto_tree_add_item(tree, hf_smb_soft_quota_limit, tvb, offset, 8, TRUE);
+               COUNT_BYTES_TRANS_SUBR(8);
+
+               /* number of bytes for quota limit */
+               CHECK_BYTE_COUNT_TRANS_SUBR(8);
+               proto_tree_add_item(tree, hf_smb_hard_quota_limit, tvb, offset, 8, TRUE);
+               COUNT_BYTES_TRANS_SUBR(8);
+
+               /* SID of the user */
+               old_sid_offset=offset;
+               offset = dissect_nt_sid(tvb, pinfo, offset, tree, "Quota");
+               *bcp -= (offset-old_sid_offset);
+
+               if(qsize){
+                       offset = old_offset+qsize;
+               }
+       }while(qsize);
+
+
+       return offset;
+}
+
+
+static int
+dissect_nt_trans_data_request(tvbuff_t *tvb, packet_info *pinfo, int offset, proto_tree *parent_tree, int bc, nt_trans_data *ntd)
 {
        proto_item *item = NULL;
        proto_tree *tree = NULL;
        smb_info_t *si;
+       int old_offset = offset;
+       guint16 bcp=bc; /* XXX fixme */
 
        si = (smb_info_t *)pinfo->private_data;
 
        if(parent_tree){
-               item = proto_tree_add_text(parent_tree, tvb, offset, len,
+               item = proto_tree_add_text(parent_tree, tvb, offset, bc,
                                "%s Data",
                                val_to_str(ntd->subcmd, nt_cmd_vals, "Unknown NT transaction (%u)"));
-               tree = proto_item_add_subtree(item, ett_smb_nt_trans_setup);
+               tree = proto_item_add_subtree(item, ett_smb_nt_trans_data);
        }
 
        switch(ntd->subcmd){
@@ -6889,12 +7191,12 @@ dissect_nt_trans_data_request(tvbuff_t *tvb, packet_info *pinfo, int offset, pro
                break;
        case NT_TRANS_IOCTL:
                /* ioctl data */
-               proto_tree_add_item(tree, hf_smb_nt_ioctl_data, tvb, offset, len, TRUE);
-               offset += len;
+               proto_tree_add_item(tree, hf_smb_nt_ioctl_data, tvb, offset, bc, TRUE);
+               offset += bc;
 
                break;
        case NT_TRANS_SSD:
-               offset = dissect_nt_sec_desc(tvb, pinfo, offset, tree, len);
+               offset = dissect_nt_sec_desc(tvb, pinfo, offset, tree, bc);
                break;
        case NT_TRANS_NOTIFY:
                break;
@@ -6903,6 +7205,28 @@ dissect_nt_trans_data_request(tvbuff_t *tvb, packet_info *pinfo, int offset, pro
                break;
        case NT_TRANS_QSD:
                break;
+       case NT_TRANS_GET_USER_QUOTA:
+               /* unknown 4 bytes */
+               proto_tree_add_item(tree, hf_smb_unknown, tvb,
+                           offset, 4, TRUE);
+               offset += 4;
+
+               /* length of SID */
+               proto_tree_add_text(tree, tvb, offset, 4, "Length of SID: %d", tvb_get_letohl(tvb, offset));
+               offset +=4;
+
+               offset = dissect_nt_sid(tvb, pinfo, offset, tree, "Quota");
+               break;
+       case NT_TRANS_SET_USER_QUOTA:
+               offset = dissect_nt_user_quota(tvb, pinfo, tree, offset, &bcp);
+               break;
+       }
+
+       /* ooops there were data we didnt know how to process */
+       if((offset-old_offset) < bc){
+               proto_tree_add_item(tree, hf_smb_unknown, tvb, offset,
+                   bc - (offset-old_offset), TRUE);
+               offset += bc - (offset-old_offset);
        }
 
        return offset;
@@ -6923,7 +7247,7 @@ dissect_nt_trans_param_request(tvbuff_t *tvb, packet_info *pinfo, int offset, pr
                item = proto_tree_add_text(parent_tree, tvb, offset, len,
                                "%s Parameters",
                                val_to_str(ntd->subcmd, nt_cmd_vals, "Unknown NT transaction (%u)"));
-               tree = proto_item_add_subtree(item, ett_smb_nt_trans_setup);
+               tree = proto_item_add_subtree(item, ett_smb_nt_trans_param);
        }
 
        switch(ntd->subcmd){
@@ -7031,6 +7355,12 @@ dissect_nt_trans_param_request(tvbuff_t *tvb, packet_info *pinfo, int offset, pr
                offset = dissect_security_information_mask(tvb, pinfo, tree, offset);
                break;
        }
+       case NT_TRANS_GET_USER_QUOTA:
+               /* not decoded yet */
+               break;
+       case NT_TRANS_SET_USER_QUOTA:
+               /* not decoded yet */
+               break;
        }
 
        return offset;
@@ -7105,6 +7435,12 @@ dissect_nt_trans_setup_request(tvbuff_t *tvb, packet_info *pinfo, int offset, pr
                break;
        case NT_TRANS_QSD:
                break;
+       case NT_TRANS_GET_USER_QUOTA:
+               /* not decoded yet */
+               break;
+       case NT_TRANS_SET_USER_QUOTA:
+               /* not decoded yet */
+               break;
        }
  
        return old_offset+len;
@@ -7308,6 +7644,7 @@ dissect_nt_trans_data_response(tvbuff_t *tvb, packet_info *pinfo, int offset, pr
        proto_tree *tree = NULL;
        smb_info_t *si;
        smb_nt_transact_info_t *nti;
+       guint16 bcp;
 
        si = (smb_info_t *)pinfo->private_data;
        if (si->sip != NULL)
@@ -7328,7 +7665,7 @@ dissect_nt_trans_data_response(tvbuff_t *tvb, packet_info *pinfo, int offset, pr
                        item = proto_tree_add_text(parent_tree, tvb, offset, len,
                                "Unknown NT Transaction Data (matching request not seen)");
                }
-               tree = proto_item_add_subtree(item, ett_smb_nt_trans_setup);
+               tree = proto_item_add_subtree(item, ett_smb_nt_trans_data);
        }
 
        if (nti == NULL) {
@@ -7359,6 +7696,13 @@ dissect_nt_trans_data_response(tvbuff_t *tvb, packet_info *pinfo, int offset, pr
                 */
                offset = dissect_nt_sec_desc(tvb, pinfo, offset, tree, len);
                break;
+       case NT_TRANS_GET_USER_QUOTA:
+               bcp=len;
+               offset = dissect_nt_user_quota(tvb, pinfo, tree, offset, &bcp);
+               break;
+       case NT_TRANS_SET_USER_QUOTA:
+               /* not decoded yet */
+               break;
        }
 
        return offset;
@@ -7374,6 +7718,9 @@ dissect_nt_trans_param_response(tvbuff_t *tvb, packet_info *pinfo, int offset, p
        smb_info_t *si;
        smb_nt_transact_info_t *nti;
        guint16 fid;
+       int old_offset;
+       guint32 neo;
+       int padcnt;
 
        si = (smb_info_t *)pinfo->private_data;
        if (si->sip != NULL)
@@ -7394,7 +7741,7 @@ dissect_nt_trans_param_response(tvbuff_t *tvb, packet_info *pinfo, int offset, p
                        item = proto_tree_add_text(parent_tree, tvb, offset, len,
                                "Unknown NT Transaction Parameters (matching request not seen)");
                }
-               tree = proto_item_add_subtree(item, ett_smb_nt_trans_setup);
+               tree = proto_item_add_subtree(item, ett_smb_nt_trans_param);
        }
 
        if (nti == NULL) {
@@ -7468,8 +7815,11 @@ dissect_nt_trans_param_response(tvbuff_t *tvb, packet_info *pinfo, int offset, p
                break;
        case NT_TRANS_NOTIFY:
                while(len){
+                       old_offset = offset;
+
                        /* next entry offset */
-                       proto_tree_add_item(tree, hf_smb_next_entry_offset, tvb, offset, 4, TRUE);
+                       neo = tvb_get_letohl(tvb, offset);
+                       proto_tree_add_uint(tree, hf_smb_next_entry_offset, tvb, offset, 4, neo);
                        COUNT_BYTES(4);
                        len -= 4;
                        /* broken implementations */
@@ -7501,6 +7851,23 @@ dissect_nt_trans_param_response(tvbuff_t *tvb, packet_info *pinfo, int offset, p
                        /* broken implementations */
                        if(len<0)break;
 
+                       if (neo == 0)
+                               break;  /* no more structures */
+
+                       /* skip to next structure */
+                       padcnt = (old_offset + neo) - offset;
+                       if (padcnt < 0) {
+                               /*
+                                * XXX - this is bogus; flag it?
+                                */
+                               padcnt = 0;
+                       }
+                       if (padcnt != 0) {
+                               COUNT_BYTES(padcnt);
+                               len -= padcnt;
+                               /* broken implementations */
+                               if(len<0)break;
+                       }
                }
                break;
        case NT_TRANS_RENAME:
@@ -7519,6 +7886,14 @@ dissect_nt_trans_param_response(tvbuff_t *tvb, packet_info *pinfo, int offset, p
                proto_tree_add_item(tree, hf_smb_sec_desc_len, tvb, offset, 4, TRUE);
                offset += 4;
                break;
+       case NT_TRANS_GET_USER_QUOTA:
+               proto_tree_add_text(tree, tvb, offset, 4, "Size of returned Quota data: %d",
+                       tvb_get_letohl(tvb, offset));
+               offset += 4;
+               break;
+       case NT_TRANS_SET_USER_QUOTA:
+               /* not decoded yet */
+               break;
        }
 
        return offset;
@@ -7572,6 +7947,12 @@ dissect_nt_trans_setup_response(tvbuff_t *tvb, packet_info *pinfo, int offset, p
                break;
        case NT_TRANS_QSD:
                break;
+       case NT_TRANS_GET_USER_QUOTA:
+               /* not decoded yet */
+               break;
+       case NT_TRANS_SET_USER_QUOTA:
+               /* not decoded yet */
+               break;
        }
 
        return offset;
@@ -7705,18 +8086,20 @@ dissect_nt_transaction_response(tvbuff_t *tvb, packet_info *pinfo, proto_tree *t
                proto_item *it;
                fragment_data *fd;
                
-               it = proto_tree_add_text(tree, tvb, 0, 0, "Fragments");
-               tr = proto_item_add_subtree(it, ett_smb_segments);
-               for(fd=r_fd->next;fd;fd=fd->next){
-                       proto_tree_add_text(tr, tvb, 0, 0, "Frame:%u Data:%u-%u",
-                                           fd->frame, fd->offset, fd->offset+fd->len-1);
-               }
-               
                pd_tvb = tvb_new_real_data(r_fd->data, r_fd->datalen,
                                             r_fd->datalen);
                tvb_set_child_real_data_tvbuff(tvb, pd_tvb);
                add_new_data_source(pinfo->fd, pd_tvb, "Reassembled SMB");
                pinfo->fragmented = FALSE;
+
+               it = proto_tree_add_text(tree, pd_tvb, 0, -1, "Fragments");
+               tr = proto_item_add_subtree(it, ett_smb_segments);
+               for(fd=r_fd->next;fd;fd=fd->next){
+                       proto_tree_add_text(tr, pd_tvb, fd->offset, fd->len,
+                                           "Frame:%u Data:%u-%u",
+                                           fd->frame, fd->offset,
+                                           fd->offset+fd->len-1);
+               }
        }
 
 
@@ -8196,6 +8579,7 @@ static const value_string trans2_cmd_vals[] = {
        { 0x01,         "FIND_FIRST2" },
        { 0x02,         "FIND_NEXT2" },
        { 0x03,         "QUERY_FS_INFORMATION" },
+       { 0x04,         "SET_FS_QUOTA" },
        { 0x05,         "QUERY_PATH_INFORMATION" },
        { 0x06,         "SET_PATH_INFORMATION" },
        { 0x07,         "QUERY_FILE_INFORMATION" },
@@ -8287,9 +8671,16 @@ static const value_string qfsi_vals[] = {
        { 0x0103,       "Query FS Size Info"},
        { 0x0104,       "Query FS Device Info"},
        { 0x0105,       "Query FS Attribute Info"},
+       { 1006,         "Query FS Quota Info"},
        {0, NULL}
 };
 
+static const value_string nt_rename_vals[] = {
+       { 0x0103,       "Create Hard Link"},
+       {0, NULL}
+};
+
+
 static const value_string delete_pending_vals[] = {
        {0,     "Normal, no pending delete"},
        {1,     "This object has DELETE PENDING"},
@@ -9591,6 +9982,88 @@ dissect_qpi_loi_vals(tvbuff_t * tvb, packet_info * pinfo, proto_tree * tree,
 }
 
 
+static const true_false_string tfs_quota_flags_deny_disk = {
+       "DENY DISK SPACE for users exceeding quota limit",
+       "Do NOT deny disk space for users exceeding quota limit"
+};
+static const true_false_string tfs_quota_flags_log_limit = {
+       "LOG EVENT when a user exceeds their QUOTA LIMIT",
+       "Do NOT log event when a user exceeds their quota limit"
+};
+static const true_false_string tfs_quota_flags_log_warning = {
+       "LOG EVENT when a user exceeds their WARNING LEVEL",
+       "Do NOT log event when a user exceeds their warning level"
+};
+static const true_false_string tfs_quota_flags_enabled = {
+       "Quotas are ENABLED of this fs",
+       "Quotas are NOT enabled on this fs"
+};
+static void
+dissect_quota_flags(tvbuff_t *tvb, packet_info *pinfo, proto_tree *parent_tree, int offset)
+{
+       guint8 mask;
+       proto_item *item = NULL;
+       proto_tree *tree = NULL;
+
+       mask = tvb_get_guint8(tvb, offset);
+
+       if(parent_tree){
+               item = proto_tree_add_text(parent_tree, tvb, offset, 1,
+                       "Quota Flags: 0x%02x %s", mask,
+                       mask?"Enabled":"Disabled");
+               tree = proto_item_add_subtree(item, ett_smb_quotaflags);
+       }
+
+       proto_tree_add_boolean(tree, hf_smb_quota_flags_log_limit,
+               tvb, offset, 1, mask);
+       proto_tree_add_boolean(tree, hf_smb_quota_flags_log_warning,
+               tvb, offset, 1, mask);
+       proto_tree_add_boolean(tree, hf_smb_quota_flags_deny_disk,
+               tvb, offset, 1, mask);
+
+       if(mask && (!(mask&0x01))){
+               proto_tree_add_boolean_hidden(tree, hf_smb_quota_flags_enabled,
+                       tvb, offset, 1, 0x01);
+       } else {
+               proto_tree_add_boolean(tree, hf_smb_quota_flags_enabled,
+                       tvb, offset, 1, mask);
+       }
+
+}
+
+static int
+dissect_nt_quota(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int offset, guint16 *bcp)
+{
+       /* first 24 bytes are unknown */
+       CHECK_BYTE_COUNT_TRANS_SUBR(24);
+       proto_tree_add_item(tree, hf_smb_unknown, tvb,
+                   offset, 24, TRUE);
+       COUNT_BYTES_TRANS_SUBR(24);
+
+       /* number of bytes for quota warning */
+       CHECK_BYTE_COUNT_TRANS_SUBR(8);
+       proto_tree_add_item(tree, hf_smb_soft_quota_limit, tvb, offset, 8, TRUE);
+       COUNT_BYTES_TRANS_SUBR(8);
+
+       /* number of bytes for quota limit */
+       CHECK_BYTE_COUNT_TRANS_SUBR(8);
+       proto_tree_add_item(tree, hf_smb_hard_quota_limit, tvb, offset, 8, TRUE);
+       COUNT_BYTES_TRANS_SUBR(8);
+
+       /* one byte of quota flags */
+       CHECK_BYTE_COUNT_TRANS_SUBR(1);
+       dissect_quota_flags(tvb, pinfo, tree, offset);
+       COUNT_BYTES_TRANS_SUBR(1);
+
+       /* these 7 bytes are unknown */
+       CHECK_BYTE_COUNT_TRANS_SUBR(7);
+       proto_tree_add_item(tree, hf_smb_unknown, tvb,
+                   offset, 7, TRUE);
+       COUNT_BYTES_TRANS_SUBR(7);
+
+       return offset;
+}
+
 static int
 dissect_transaction2_request_data(tvbuff_t *tvb, packet_info *pinfo,
     proto_tree *parent_tree, int offset, int subcmd, guint16 dc)
@@ -9622,6 +10095,9 @@ dissect_transaction2_request_data(tvbuff_t *tvb, packet_info *pinfo,
        case 0x03:      /*TRANS2_QUERY_FS_INFORMATION*/
                /* no data field in this request */
                break;
+       case 0x04:      /* TRANS2_SET_QUOTA */
+               offset = dissect_nt_quota(tvb, pinfo, tree, offset, &dc);
+               break;
        case 0x05:      /*TRANS2_QUERY_PATH_INFORMATION*/
                /* no data field in this request */
                break;
@@ -10860,7 +11336,6 @@ dissect_device_characteristics(tvbuff_t *tvb, packet_info *pinfo, proto_tree *pa
        return offset;
 }
 
-
 /*dissect the data block for TRANS2_QUERY_FS_INFORMATION*/
 static int
 dissect_qfsi_vals(tvbuff_t * tvb, packet_info * pinfo, proto_tree * tree,
@@ -11014,6 +11489,8 @@ dissect_qfsi_vals(tvbuff_t * tvb, packet_info * pinfo, proto_tree * tree,
                COUNT_BYTES_TRANS_SUBR(fn_len);
 
                break;
+       case 1006:      /* QUERY_FS_QUOTA_INFO */
+               offset = dissect_nt_quota(tvb, pinfo, tree, offset, bcp);
        }
  
        return offset;
@@ -11509,19 +11986,21 @@ dissect_transaction_response(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree
                proto_tree *tr;
                proto_item *it;
                fragment_data *fd;
-               
-               it = proto_tree_add_text(tree, tvb, 0, 0, "Fragments");
-               tr = proto_item_add_subtree(it, ett_smb_segments);
-               for(fd=r_fd->next;fd;fd=fd->next){
-                       proto_tree_add_text(tr, tvb, 0, 0, "Frame:%u Data:%u-%u",
-                                           fd->frame, fd->offset, fd->offset+fd->len-1);
-               }
-               
+
                pd_tvb = tvb_new_real_data(r_fd->data, r_fd->datalen,
                                             r_fd->datalen);
                tvb_set_child_real_data_tvbuff(tvb, pd_tvb);
                add_new_data_source(pinfo->fd, pd_tvb, "Reassembled SMB");
                pinfo->fragmented = FALSE;
+
+               it = proto_tree_add_text(tree, pd_tvb, 0, -1, "Fragments");
+               tr = proto_item_add_subtree(it, ett_smb_segments);
+               for(fd=r_fd->next;fd;fd=fd->next){
+                       proto_tree_add_text(tr, pd_tvb, fd->offset, fd->len,
+                                           "Frame:%u Data:%u-%u",
+                                           fd->frame, fd->offset,
+                                           fd->offset+fd->len-1);
+               }
        }
 
 
@@ -11705,7 +12184,7 @@ typedef struct _smb_function {
        int (*response)(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int offset, proto_tree *smb_tree);
 } smb_function;
 
-smb_function smb_dissector[256] = {
+static smb_function smb_dissector[256] = {
   /* 0x00 Create Dir*/  {dissect_old_dir_request, dissect_empty},
   /* 0x01 Delete Dir*/  {dissect_old_dir_request, dissect_empty},
   /* 0x02 Open File*/  {dissect_open_file_request, dissect_open_file_response},
@@ -11880,7 +12359,7 @@ smb_function smb_dissector[256] = {
   /* 0xa2 NT CreateAndX*/              {dissect_nt_create_andx_request, dissect_nt_create_andx_response},
   /* 0xa3 */  {dissect_unknown, dissect_unknown},
   /* 0xa4 NT Cancel*/          {dissect_nt_cancel_request, dissect_unknown}, /*no response to this one*/
-  /* 0xa5 */  {dissect_unknown, dissect_unknown},
+  /* 0xa5 */  {dissect_nt_rename_file_request, dissect_empty},
   /* 0xa6 */  {dissect_unknown, dissect_unknown},
   /* 0xa7 */  {dissect_unknown, dissect_unknown},
   /* 0xa8 */  {dissect_unknown, dissect_unknown},
@@ -12187,7 +12666,7 @@ static const value_string smb_cmd_vals[] = {
   { 0xA2, "NT Create AndX" },
   { 0xA3, "unknown-0xA3" },
   { 0xA4, "NT Cancel" },
-  { 0xA5, "unknown-0xA5" },
+  { 0xA5, "NT Rename" },
   { 0xA6, "unknown-0xA6" },
   { 0xA7, "unknown-0xA7" },
   { 0xA8, "unknown-0xA8" },
@@ -12304,6 +12783,8 @@ free_hash_tables(gpointer ctarg, gpointer user_data)
                g_hash_table_destroy(ct->matched);
        if (ct->dcerpc_fid_to_frame)
                g_hash_table_destroy(ct->dcerpc_fid_to_frame);
+       if (ct->tid_service)
+               g_hash_table_destroy(ct->tid_service);
 }
 
 static void
@@ -12459,7 +12940,7 @@ get_unicode_or_ascii_string(tvbuff_t *tvb, int *offsetp,
   const gchar *string;
   int string_len;
   smb_info_t *si;
-  int copylen;
+  unsigned int copylen;
 
   if (*bcp == 0) {
     /* Not enough data in buffer */
@@ -12553,7 +13034,8 @@ const value_string DOS_errors[] = {
   {SMBE_nosuchshare, "Requested share does not exist"},
   {SMBE_filexists, "File in operation already exists"},
   {SMBE_cannotopen, "Cannot open the file specified"},
-  {SMBE_unknownlevel, "Unknown level??"},
+  {SMBE_unknownlevel, "Unknown info level"},
+  {SMBE_invalidname, "Invalid name"},
   {SMBE_badpipe, "Named pipe invalid"},
   {SMBE_pipebusy, "All instances of pipe are busy"},
   {SMBE_pipeclosing, "Named pipe close in progress"},
@@ -12573,6 +13055,8 @@ const value_string DOS_errors[] = {
   {SMBE_invalidenvironment, "Invalid environment"},
   {SMBE_printerdriverinuse, "Printer driver in use"},
   {SMBE_invalidparam, "Invalid parameter"},
+  {SMBE_invalidformsize, "Invalid form size"},
+  {SMBE_invalidsecuritydescriptor, "Invalid security descriptor"},
   {0, NULL}
   };
 
@@ -12672,6 +13156,131 @@ static char *decode_smb_error(guint8 errcls, guint16 errcode)
 
 }
 
+
+/* These are the MS country codes from
+
+       http://www.unicode.org/unicode/onlinedat/countries.html
+
+   For countries that share the same number, I choose to use only the
+   name of the largest country. Apologies for this. If this offends you,
+   here is the table to change that.
+
+   This also includes the code of 0 for "Default", which isn't in
+   that list, but is in Microsoft's SDKs and the Cygnus "winnls.h"
+   header file.  Presumably it means "don't override the setting
+   on the user's machine".
+
+   Future versions of Microsoft's "winnls.h" header file might include
+   additional codes; the current version matches the Unicode Consortium's
+   table.
+*/
+const value_string ms_country_codes[] = {
+       {  0,   "Default"},
+       {  1,   "USA"},
+       {  2,   "Canada"},
+       {  7,   "Russia"},
+       { 20,   "Egypt"},
+       { 27,   "South Africa"},
+       { 30,   "Greece"},
+       { 31,   "Netherlands"},
+       { 32,   "Belgium"},
+       { 33,   "France"},
+       { 34,   "Spain"},
+       { 36,   "Hungary"},
+       { 39,   "Italy"},
+       { 40,   "Romania"},
+       { 41,   "Switzerland"},
+       { 43,   "Austria"},
+       { 44,   "United Kingdom"},
+       { 45,   "Denmark"},
+       { 46,   "Sweden"},
+       { 47,   "Norway"},
+       { 48,   "Poland"},
+       { 49,   "Germany"},
+       { 51,   "Peru"},
+       { 52,   "Mexico"},
+       { 54,   "Argentina"},
+       { 55,   "Brazil"},
+       { 56,   "Chile"},
+       { 57,   "Colombia"},
+       { 58,   "Venezuela"},
+       { 60,   "Malaysia"},
+       { 61,   "Australia"},
+       { 62,   "Indonesia"},
+       { 63,   "Philippines"},
+       { 64,   "New Zealand"},
+       { 65,   "Singapore"},
+       { 66,   "Thailand"},
+       { 81,   "Japan"},
+       { 82,   "South Korea"},
+       { 84,   "Viet Nam"},
+       { 86,   "China"},
+       { 90,   "Turkey"},
+       { 91,   "India"},
+       { 92,   "Pakistan"},
+       {212,   "Morocco"},
+       {213,   "Algeria"},
+       {216,   "Tunisia"},
+       {218,   "Libya"},
+       {254,   "Kenya"},
+       {263,   "Zimbabwe"},
+       {298,   "Faroe Islands"},
+       {351,   "Portugal"},
+       {352,   "Luxembourg"},
+       {353,   "Ireland"},
+       {354,   "Iceland"},
+       {355,   "Albania"},
+       {358,   "Finland"},
+       {359,   "Bulgaria"},
+       {370,   "Lithuania"},
+       {371,   "Latvia"},
+       {372,   "Estonia"},
+       {374,   "Armenia"},
+       {375,   "Belarus"},
+       {380,   "Ukraine"},
+       {381,   "Serbia"},
+       {385,   "Croatia"},
+       {386,   "Slovenia"},
+       {389,   "Macedonia"},
+       {420,   "Czech Republic"},
+       {421,   "Slovak Republic"},
+       {501,   "Belize"},
+       {502,   "Guatemala"},
+       {503,   "El Salvador"},
+       {504,   "Honduras"},
+       {505,   "Nicaragua"},
+       {506,   "Costa Rica"},
+       {507,   "Panama"},
+       {591,   "Bolivia"},
+       {593,   "Ecuador"},
+       {595,   "Paraguay"},
+       {598,   "Uruguay"},
+       {673,   "Brunei Darussalam"},
+       {852,   "Hong Kong"},
+       {853,   "Macau"},
+       {886,   "Taiwan"},
+       {960,   "Maldives"},
+       {961,   "Lebanon"},
+       {962,   "Jordan"},
+       {963,   "Syria"},
+       {964,   "Iraq"},
+       {965,   "Kuwait"},
+       {966,   "Saudi Arabia"},
+       {967,   "Yemen"},
+       {968,   "Oman"},
+       {971,   "United Arab Emirates"},
+       {972,   "Israel"},
+       {973,   "Bahrain"},
+       {974,   "Qatar"},
+       {976,   "Mongolia"},
+       {981,   "Iran"},
+       {994,   "Azerbaijan"},
+       {995,   "Georgia"},
+       {996,   "Kyrgyzstan"},
+
+       {0,     NULL}
+};
+
 /*
  * NT error codes.
  *
@@ -13689,7 +14298,6 @@ dissect_smb(tvbuff_t *tvb, packet_info *pinfo, proto_tree *parent_tree)
         guint32 nt_status = 0;
         guint8 errclass = 0;
         guint16 errcode = 0;
-       guint16 uid, pid, tid, mid;
        guint32 pid_mid;
        conversation_t *conversation;
 
@@ -13724,11 +14332,11 @@ dissect_smb(tvbuff_t *tvb, packet_info *pinfo, proto_tree *parent_tree)
        } else {
                si.unicode = FALSE;
        }
-       tid = tvb_get_letohs(tvb, offset+24);
-       pid = tvb_get_letohs(tvb, offset+26);
-       uid = tvb_get_letohs(tvb, offset+28);
-       mid = tvb_get_letohs(tvb, offset+30);
-       pid_mid = (pid << 16) | mid;
+       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;
 
@@ -13768,14 +14376,17 @@ dissect_smb(tvbuff_t *tvb, packet_info *pinfo, proto_tree *parent_tree)
                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(
+                       smb_saved_info_hash_unmatched, 
+                       smb_saved_info_equal_unmatched);
                conversation_add_proto_data(conversation, proto_smb, si.ct);
        }
 
        if( (si.request)
-           &&  (mid==0)
-           &&  (uid==0)
-           &&  (pid==0)
-           &&  (tid==0) ){
+           &&  (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 
                */
@@ -13953,6 +14564,11 @@ dissect_smb(tvbuff_t *tvb, packet_info *pinfo, proto_tree *parent_tree)
                                sip = g_mem_chunk_alloc(smb_saved_info_chunk);
                                sip->frame_req = pinfo->fd->num;
                                sip->frame_res = 0;
+                               sip->flags = 0;
+                               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->extra_info = NULL;
                                g_hash_table_insert(si.ct->unmatched, (void *)pid_mid, sip);
@@ -14068,19 +14684,19 @@ 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, 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, 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, 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, mid);
+       proto_tree_add_uint(htree, hf_smb_mid, tvb, offset, 2, si.mid);
        offset += 2;
 
        pinfo->private_data = &si;
@@ -14099,7 +14715,8 @@ dissect_smb(tvbuff_t *tvb, packet_info *pinfo, proto_tree *parent_tree)
                                 */
                                col_append_fstr(
                                        pinfo->cinfo, COL_INFO, ", Error: %s",
-                                       val_to_str(nt_status, NT_errors, "%s"));
+                                       val_to_str(nt_status, NT_errors,
+                                           "Unknown (0x%08X)"));
                        }
                } else {
                        /*
@@ -15567,6 +16184,14 @@ proto_register_smb(void)
                { "Level of Interest", "smb.qfi_loi", FT_UINT16, BASE_DEC,
                VALS(qfsi_vals), 0, "Level of interest for QUERY_FS_INFORMATION2 command", HFILL }},
 
+       { &hf_smb_nt_rename_level,
+               { "Level of Interest", "smb.ntr_loi", FT_UINT16, BASE_DEC,
+               VALS(nt_rename_vals), 0, "NT Rename level", HFILL }},
+
+       { &hf_smb_cluster_count,
+               { "Cluster count", "smb.ntr_clu", FT_UINT32, BASE_DEC,
+               NULL, 0, "Number of clusters", HFILL }},
+
        { &hf_smb_ea_size,
                { "EA Size", "smb.ea_size", FT_UINT32, BASE_DEC,
                NULL, 0, "Size of file's EA information", HFILL }},
@@ -15747,6 +16372,18 @@ proto_register_smb(void)
                { "Free Units", "smb.free_alloc_units", FT_UINT64, BASE_DEC,
                NULL, 0, "Number of free allocation units", HFILL }},
 
+       { &hf_smb_soft_quota_limit,
+               { "(Soft) Quota Treshold", "smb.quota.soft.default", FT_UINT64, BASE_DEC,
+               NULL, 0, "Soft Quota treshold", HFILL }},
+
+       { &hf_smb_hard_quota_limit,
+               { "(Hard) Quota Limit", "smb.quota.hard.default", FT_UINT64, BASE_DEC,
+               NULL, 0, "Hard Quota limit", HFILL }},
+
+       { &hf_smb_user_quota_used,
+               { "Quota Used", "smb.quota.used", FT_UINT64, BASE_DEC,
+               NULL, 0, "How much Quota is used by this user", HFILL }},
+
        { &hf_smb_max_name_len,
                { "Max name length", "smb.fs_max_name_len", FT_UINT32, BASE_DEC,
                NULL, 0, "Maximum length of each file name component in number of bytes", HFILL }},
@@ -15839,6 +16476,10 @@ proto_register_smb(void)
                { "Num ACEs", "smb.acl.num_aces", FT_UINT32, BASE_DEC,
                NULL, 0, "Number of ACE structures for this ACL", HFILL }},
 
+       { &hf_smb_user_quota_offset,
+               { "Next Offset", "smb.quota.user.offset", FT_UINT32, BASE_DEC,
+               NULL, 0, "Relative offset to next user quota structure", HFILL }},
+
        { &hf_smb_ace_type,
                { "Type", "smb.ace.type", FT_UINT8, BASE_DEC,
                VALS(ace_type_vals), 0, "Type of ACE", HFILL }},
@@ -15876,7 +16517,7 @@ proto_register_smb(void)
                TFS(&tfs_ace_flags_failed_access), 0x80, "Should failed accesses be audited?", HFILL }},
 
        { &hf_smb_sec_desc_type_owner_defaulted,
-               { "Onwer Defaulted", "smb.sec_desc.type.owner_defaulted", FT_BOOLEAN, 16,
+               { "Owner Defaulted", "smb.sec_desc.type.owner_defaulted", FT_BOOLEAN, 16,
                TFS(&tfs_sec_desc_type_owner_defaulted), 0x0001, "Is Owner Defaulted set?", HFILL }},
 
        { &hf_smb_sec_desc_type_group_defaulted,
@@ -15927,6 +16568,22 @@ proto_register_smb(void)
                { "Self Relative", "smb.sec_desc.type.self_relative", FT_BOOLEAN, 16,
                TFS(&tfs_sec_desc_type_self_relative), 0x8000, "Is this SecDesc self relative?", HFILL }},
 
+       { &hf_smb_quota_flags_deny_disk,
+               { "Deny Disk", "smb.quota.flags.deny_disk", FT_BOOLEAN, 8,
+               TFS(&tfs_quota_flags_deny_disk), 0x02, "Is the default quota limit enforced?", HFILL }},
+
+       { &hf_smb_quota_flags_log_limit,
+               { "Log Limit", "smb.quota.flags.log_limit", FT_BOOLEAN, 8,
+               TFS(&tfs_quota_flags_log_limit), 0x20, "Should the server log an event when the limit is exceeded?", HFILL }},
+
+       { &hf_smb_quota_flags_log_warning,
+               { "Log Warning", "smb.quota.flags.log_warning", FT_BOOLEAN, 8,
+               TFS(&tfs_quota_flags_log_warning), 0x10, "Should the server log an event when the warning level is exceeded?", HFILL }},
+
+       { &hf_smb_quota_flags_enabled,
+               { "Enabled", "smb.quota.flags.enabled", FT_BOOLEAN, 8,
+               TFS(&tfs_quota_flags_enabled), 0x01, "Is quotas enabled of this FS?", HFILL }},
+
        };
        static gint *ett[] = {
                &ett_smb,
@@ -15972,6 +16629,8 @@ proto_register_smb(void)
                &ett_smb_nt_share_access,
                &ett_smb_nt_security_flags,
                &ett_smb_nt_trans_setup,
+               &ett_smb_nt_trans_data,
+               &ett_smb_nt_trans_param,
                &ett_smb_nt_notify_completion_filter,
                &ett_smb_nt_ioctl_flags,
                &ett_smb_security_information_mask,
@@ -15995,6 +16654,7 @@ proto_register_smb(void)
                &ett_smb_ace,
                &ett_smb_ace_flags,
                &ett_smb_sec_desc_type,
+               &ett_smb_quotaflags,
        };
        module_t *smb_module;
 
@@ -16006,11 +16666,11 @@ proto_register_smb(void)
        smb_module = prefs_register_protocol(proto_smb, NULL);
        prefs_register_bool_preference(smb_module, "trans_reassembly",
                "Reassemble SMB Transaction payload",
-               "Whether the dissector should do reassembly the payload of SMB Transaction commands spanning multiple SMB PDUs",
+               "Whether the dissector should reassemble the payload of SMB Transaction commands spanning multiple SMB PDUs",
                &smb_trans_reassembly);
        prefs_register_bool_preference(smb_module, "dcerpc_reassembly",
                "Reassemble DCERPC over SMB",
-               "Whether the dissector should do reassembly of DCERPC over SMB commands",
+               "Whether the dissector should reassemble DCERPC over SMB commands",
                &smb_dcerpc_reassembly);
        register_init_routine(smb_trans_reassembly_init);
        register_init_routine(smb_dcerpc_reassembly_init);