diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-10 20:34:10 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-10 20:34:10 +0000 |
commit | e4ba6dbc3f1e76890b22773807ea37fe8fa2b1bc (patch) | |
tree | 68cb5ef9081156392f1dd62a00c6ccc1451b93df /epan/dissectors/packet-smb.c | |
parent | Initial commit. (diff) | |
download | wireshark-e4ba6dbc3f1e76890b22773807ea37fe8fa2b1bc.tar.xz wireshark-e4ba6dbc3f1e76890b22773807ea37fe8fa2b1bc.zip |
Adding upstream version 4.2.2.upstream/4.2.2
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'epan/dissectors/packet-smb.c')
-rw-r--r-- | epan/dissectors/packet-smb.c | 21451 |
1 files changed, 21451 insertions, 0 deletions
diff --git a/epan/dissectors/packet-smb.c b/epan/dissectors/packet-smb.c new file mode 100644 index 00000000..b62e6b25 --- /dev/null +++ b/epan/dissectors/packet-smb.c @@ -0,0 +1,21451 @@ +/* packet-smb.c + * Routines for smb packet dissection + * Copyright 1999, Richard Sharpe <rsharpe@ns.aus.com> + * 2001 Rewrite by Ronnie Sahlberg and Guy Harris + * + * Wireshark - Network traffic analyzer + * By Gerald Combs <gerald@wireshark.org> + * Copyright 1998 Gerald Combs + * + * Copied from packet-pop.c + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +#include "config.h" + +#include <epan/packet.h> +#include <epan/exceptions.h> +#include <epan/strutil.h> +#include <epan/prefs.h> +#include <epan/reassemble.h> +#include <epan/tap.h> +#include <epan/srt_table.h> +#include <epan/expert.h> +#include <epan/to_str.h> +#include <epan/export_object.h> + +#include "packet-windows-common.h" +#include "packet-smb.h" +#include "packet-ipx.h" +#include "packet-idp.h" +#include "packet-smb-common.h" +#include "packet-smb-mailslot.h" +#include "packet-smb-pipe.h" +#include "packet-ntlmssp.h" +#include "packet-smb2.h" + +void proto_register_smb(void); +void proto_reg_handoff_smb(void); + +/* + * Various specifications and documents about SMB can be found in + * + * ftp://ftp.microsoft.com/developr/drg/CIFS/ + * + * and a CIFS specification from the Storage Networking Industry Association + * can be found on a link from the page at + * + * http://www.snia.org/tech_activities/CIFS + * + * (it supercedes the document at + * + * ftp://ftp.microsoft.com/developr/drg/CIFS/draft-leach-cifs-v1-spec-01.txt + * + * ). + * + * There are also some Open Group publications documenting CIFS available + * for download; catalog entries for them are at: + * + * http://www.opengroup.org/products/publications/catalog/c209.htm + * + * http://www.opengroup.org/products/publications/catalog/c195.htm + * + * The document "NT LAN Manager SMB File Sharing Protocol Extensions" + * can be found at + * + * http://www.samba.org/samba/ftp/specs/smb-nt01.doc + * + * (or, presumably a similar path under the Samba mirrors). As the + * ".doc" indicates, it's a Word document. Some of the specs from the + * Microsoft FTP site can be found in the + * + * http://www.samba.org/samba/ftp/specs/ + * + * directory as well. + * + * Beware - these specs may have errors. + * + * Microsoft's public protocol specifications, including MS-CIFS and + * other SMB-related specifications, can be found at + * + * http://msdn.microsoft.com/en-us/library/cc216513.aspx + * + * See also + * + * https://wiki.samba.org/index.php/UNIX_Extensions + */ + +/* DFS referral entry flags */ +#define REFENT_FLAGS_NAME_LIST_REFERRAL 0x0002 +#define REFENT_FLAGS_TARGET_SET_BOUNDARY 0x0004 + + +static int proto_smb = -1; +static int hf_smb_cmd = -1; +static int hf_smb_andxcmd = -1; +static int hf_smb_mapped_in = -1; +static int hf_smb_unmapped_in = -1; +static int hf_smb_opened_in = -1; +static int hf_smb_closed_in = -1; +static int hf_smb_key = -1; +static int hf_smb_session_id = -1; +static int hf_smb_sequence_num = -1; +static int hf_smb_group_id = -1; +static int hf_smb_pid = -1; +static int hf_smb_tid = -1; +static int hf_smb_uid = -1; +static int hf_smb_mid = -1; +static int hf_smb_pid_high = -1; +static int hf_smb_sig = -1; +static int hf_smb_response_to = -1; +static int hf_smb_time = -1; +static int hf_smb_response_in = -1; +static int hf_smb_continuation_to = -1; +static int hf_smb_nt_status = -1; +static int hf_smb_error_class = -1; +static int hf_smb_error_code = -1; +static int hf_smb_reserved = -1; +static int hf_smb_create_flags = -1; +static int hf_smb_create_options = -1; +static int hf_smb_share_access = -1; +static int hf_smb_access_mask = -1; +static int hf_smb_flags = -1; +static int hf_smb_flags_lock = -1; +static int hf_smb_flags_receive_buffer = -1; +static int hf_smb_flags_caseless = -1; +static int hf_smb_flags_canon = -1; +static int hf_smb_flags_oplock = -1; +static int hf_smb_flags_notify = -1; +static int hf_smb_flags_response = -1; +static int hf_smb_flags2 = -1; +static int hf_smb_flags2_long_names_allowed = -1; +static int hf_smb_flags2_ea = -1; +static int hf_smb_flags2_sec_sig = -1; +static int hf_smb_flags2_compressed = -1; +static int hf_smb_flags2_sec_sig_required = -1; +static int hf_smb_flags2_long_names_used = -1; +static int hf_smb_flags2_reparse_path = -1; +static int hf_smb_flags2_esn = -1; +static int hf_smb_flags2_dfs = -1; +static int hf_smb_flags2_roe = -1; +static int hf_smb_flags2_nt_error = -1; +static int hf_smb_flags2_string = -1; +static int hf_smb_word_count = -1; +static int hf_smb_byte_count = -1; +static int hf_smb_buffer_format = -1; +static int hf_smb_dialect = -1; +static int hf_smb_dialect_name = -1; +static int hf_smb_dialect_index = -1; +static int hf_smb_max_trans_buf_size = -1; +static int hf_smb_max_mpx_count = -1; +static int hf_smb_max_vcs_num = -1; +static int hf_smb_session_key = -1; +static int hf_smb_server_timezone = -1; +static int hf_smb_challenge_length = -1; +static int hf_smb_challenge = -1; +static int hf_smb_primary_domain = -1; +static int hf_smb_server = -1; +static int hf_smb_max_raw_buf_size = -1; +static int hf_smb_server_guid = -1; +static int hf_smb_volume_guid = -1; +static int hf_smb_security_blob_len = -1; +static int hf_smb_security_blob = -1; +static int hf_smb_sm16 = -1; +static int hf_smb_sm_mode16 = -1; +static int hf_smb_sm_password16 = -1; +static int hf_smb_sm = -1; +static int hf_smb_sm_mode = -1; +static int hf_smb_sm_password = -1; +static int hf_smb_sm_signatures = -1; +static int hf_smb_sm_sig_required = -1; +static int hf_smb_rm = -1; +static int hf_smb_rm_read = -1; +static int hf_smb_rm_write = -1; +static int hf_smb_server_date_time = -1; +static int hf_smb_server_smb_date = -1; +static int hf_smb_server_smb_time = -1; +static int hf_smb_server_cap = -1; +static int hf_smb_server_cap_raw_mode = -1; +static int hf_smb_server_cap_mpx_mode = -1; +static int hf_smb_server_cap_unicode = -1; +static int hf_smb_server_cap_large_files = -1; +static int hf_smb_server_cap_nt_smbs = -1; +static int hf_smb_server_cap_rpc_remote_apis = -1; +static int hf_smb_server_cap_nt_status = -1; +static int hf_smb_server_cap_level_ii_oplocks = -1; +static int hf_smb_server_cap_lock_and_read = -1; +static int hf_smb_server_cap_nt_find = -1; +static int hf_smb_server_cap_dfs = -1; +static int hf_smb_server_cap_infolevel_passthru = -1; +static int hf_smb_server_cap_large_readx = -1; +static int hf_smb_server_cap_large_writex = -1; +static int hf_smb_server_cap_lwio = -1; +static int hf_smb_server_cap_unix = -1; +static int hf_smb_server_cap_compressed_data = -1; +static int hf_smb_server_cap_dynamic_reauth = -1; +static int hf_smb_server_cap_extended_security = -1; +static int hf_smb_system_time = -1; +static int hf_smb_unknown = -1; +static int hf_smb_dir_name = -1; +static int hf_smb_echo_count = -1; +static int hf_smb_echo_data = -1; +static int hf_smb_echo_seq_num = -1; +static int hf_smb_max_buf_size = -1; +static int hf_smb_password = -1; +static int hf_smb_password_len = -1; +static int hf_smb_ansi_password = -1; +static int hf_smb_ansi_password_len = -1; +static int hf_smb_unicode_password = -1; +static int hf_smb_unicode_password_len = -1; +static int hf_smb_path = -1; +static int hf_smb_service = -1; +static int hf_smb_move_flags = -1; +static int hf_smb_move_flags_file = -1; +static int hf_smb_move_flags_dir = -1; +static int hf_smb_move_flags_verify = -1; +static int hf_smb_files_moved = -1; +static int hf_smb_file_access_mask_read_data = -1; +static int hf_smb_file_access_mask_write_data = -1; +static int hf_smb_file_access_mask_append_data = -1; +static int hf_smb_file_access_mask_read_ea = -1; +static int hf_smb_file_access_mask_write_ea = -1; +static int hf_smb_file_access_mask_execute = -1; +static int hf_smb_file_access_mask_read_attribute = -1; +static int hf_smb_file_access_mask_write_attribute = -1; +static int hf_smb_dir_access_mask_list = -1; +static int hf_smb_dir_access_mask_add_file = -1; +static int hf_smb_dir_access_mask_add_subdir = -1; +static int hf_smb_dir_access_mask_read_ea = -1; +static int hf_smb_dir_access_mask_write_ea = -1; +static int hf_smb_dir_access_mask_traverse = -1; +static int hf_smb_dir_access_mask_delete_child = -1; +static int hf_smb_dir_access_mask_read_attribute = -1; +static int hf_smb_dir_access_mask_write_attribute = -1; +static int hf_smb_copy_flags = -1; +static int hf_smb_copy_flags_file = -1; +static int hf_smb_copy_flags_dir = -1; +static int hf_smb_copy_flags_dest_mode = -1; +static int hf_smb_copy_flags_source_mode = -1; +static int hf_smb_copy_flags_verify = -1; +static int hf_smb_copy_flags_tree_copy = -1; +static int hf_smb_copy_flags_ea_action = -1; +static int hf_smb_count = -1; +static int hf_smb_count_low = -1; +static int hf_smb_count_high = -1; +static int hf_smb_file_name = -1; +static int hf_smb_open_function = -1; +static int hf_smb_open_function_open = -1; +static int hf_smb_open_function_create = -1; +static int hf_smb_fid = -1; +static int hf_smb_file_attr_16bit = -1; +static int hf_smb_file_attr_8bit = -1; +static int hf_smb_file_attr_read_only_16bit = -1; +static int hf_smb_file_attr_read_only_8bit = -1; +static int hf_smb_file_attr_hidden_16bit = -1; +static int hf_smb_file_attr_hidden_8bit = -1; +static int hf_smb_file_attr_system_16bit = -1; +static int hf_smb_file_attr_system_8bit = -1; +static int hf_smb_file_attr_volume_16bit = -1; +static int hf_smb_file_attr_volume_8bit = -1; +static int hf_smb_file_attr_directory_16bit = -1; +static int hf_smb_file_attr_directory_8bit = -1; +static int hf_smb_file_attr_archive_16bit = -1; +static int hf_smb_file_attr_archive_8bit = -1; +#if 0 +static int hf_smb_file_attr_device = -1; +static int hf_smb_file_attr_normal = -1; +static int hf_smb_file_attr_temporary = -1; +static int hf_smb_file_attr_sparse = -1; +static int hf_smb_file_attr_reparse = -1; +static int hf_smb_file_attr_compressed = -1; +static int hf_smb_file_attr_offline = -1; +static int hf_smb_file_attr_not_content_indexed = -1; +static int hf_smb_file_attr_encrypted = -1; +#endif +static int hf_smb_file_size = -1; +static int hf_smb_search_attribute = -1; +static int hf_smb_search_attribute_read_only = -1; +static int hf_smb_search_attribute_hidden = -1; +static int hf_smb_search_attribute_system = -1; +static int hf_smb_search_attribute_volume = -1; +static int hf_smb_search_attribute_directory = -1; +static int hf_smb_search_attribute_archive = -1; +static int hf_smb_access_mode = -1; +static int hf_smb_access_sharing = -1; +static int hf_smb_access_locality = -1; +static int hf_smb_access_caching = -1; +static int hf_smb_access_writetru = -1; +static int hf_smb_desired_access = -1; +static int hf_smb_granted_access = -1; +static int hf_smb_create_time = -1; +static int hf_smb_modify_time = -1; +static int hf_smb_backup_time = -1; +static int hf_smb_mac_alloc_block_count = -1; +static int hf_smb_mac_alloc_block_size = -1; +static int hf_smb_mac_free_block_count = -1; +static int hf_smb_mac_fndrinfo = -1; +static int hf_smb_mac_root_file_count = -1; +static int hf_smb_mac_root_dir_count = -1; +static int hf_smb_mac_file_count = -1; +static int hf_smb_mac_dir_count = -1; +static int hf_smb_mac_sup = -1; +static int hf_smb_mac_sup_access_ctrl = -1; +static int hf_smb_mac_sup_getset_comments = -1; +static int hf_smb_mac_sup_desktopdb_calls = -1; +static int hf_smb_mac_sup_unique_ids = -1; +static int hf_smb_mac_sup_streams = -1; +static int hf_smb_create_dos_date = -1; +static int hf_smb_create_dos_time = -1; +static int hf_smb_last_write_time = -1; +static int hf_smb_last_write_dos_date = -1; +static int hf_smb_last_write_dos_time = -1; +static int hf_smb_access_time = -1; +static int hf_smb_access_dos_date = -1; +static int hf_smb_access_dos_time = -1; +static int hf_smb_old_file_name = -1; +static int hf_smb_offset = -1; +static int hf_smb_remaining = -1; +static int hf_smb_padding = -1; +static int hf_smb_file_data = -1; +/* static int hf_smb_raw_ea_data = -1; */ +static int hf_smb_total_data_len = -1; +static int hf_smb_data_len = -1; +static int hf_smb_data_len_low = -1; +static int hf_smb_data_len_high = -1; +static int hf_smb_seek_mode = -1; +static int hf_smb_data_size = -1; +static int hf_smb_alloc_size = -1; +static int hf_smb_alloc_size64 = -1; +static int hf_smb_max_count = -1; +static int hf_smb_max_count_low = -1; +static int hf_smb_max_count_high = -1; +static int hf_smb_min_count = -1; +static int hf_smb_timeout = -1; +static int hf_smb_high_offset = -1; +static int hf_smb_units = -1; +static int hf_smb_bpu = -1; +static int hf_smb_blocksize = -1; +static int hf_smb_freeunits = -1; +static int hf_smb_data_offset = -1; +static int hf_smb_dcm = -1; +static int hf_smb_request_mask = -1; +static int hf_smb_response_mask = -1; +static int hf_smb_search_id = -1; +static int hf_smb_write_mode = -1; +static int hf_smb_write_mode_write_through = -1; +static int hf_smb_write_mode_return_remaining = -1; +static int hf_smb_write_mode_raw = -1; +static int hf_smb_write_mode_message_start = -1; +static int hf_smb_write_mode_connectionless = -1; +static int hf_smb_resume_key_len = -1; +static int hf_smb_resume_find_id = -1; +static int hf_smb_resume_server_cookie = -1; +static int hf_smb_resume_client_cookie = -1; +static int hf_smb_andxoffset = -1; +static int hf_smb_lock_type = -1; +static int hf_smb_lock_type_large = -1; +static int hf_smb_lock_type_cancel = -1; +static int hf_smb_lock_type_change = -1; +static int hf_smb_lock_type_oplock = -1; +static int hf_smb_lock_type_shared = -1; +static int hf_smb_locking_ol = -1; +static int hf_smb_number_of_locks = -1; +static int hf_smb_number_of_unlocks = -1; +static int hf_smb_lock_long_offset = -1; +static int hf_smb_lock_long_length = -1; +static int hf_smb_file_type = -1; +static int hf_smb_ipc_state = -1; +static int hf_smb_ipc_state_nonblocking = -1; +static int hf_smb_ipc_state_endpoint = -1; +static int hf_smb_ipc_state_pipe_type = -1; +static int hf_smb_ipc_state_read_mode = -1; +static int hf_smb_ipc_state_icount = -1; +static int hf_smb_server_fid = -1; +static int hf_smb_open_flags = -1; +static int hf_smb_open_flags_add_info = -1; +static int hf_smb_open_flags_ex_oplock = -1; +static int hf_smb_open_flags_batch_oplock = -1; +static int hf_smb_open_flags_ealen = -1; +static int hf_smb_open_action = -1; +static int hf_smb_open_action_open = -1; +static int hf_smb_open_action_lock = -1; +static int hf_smb_vc_num = -1; +static int hf_smb_account = -1; +static int hf_smb_os = -1; +static int hf_smb_lanman = -1; +static int hf_smb_setup_action = -1; +static int hf_smb_setup_action_guest = -1; +static int hf_smb_fs = -1; +static int hf_smb_connect_flags = -1; +static int hf_smb_connect_flags_dtid = -1; +static int hf_smb_connect_flags_ext_sig = -1; +static int hf_smb_connect_flags_ext_resp = -1; +static int hf_smb_connect_support = -1; +static int hf_smb_connect_support_search = -1; +static int hf_smb_connect_support_in_dfs = -1; +static int hf_smb_connect_support_csc_mask_vals = -1; +static int hf_smb_connect_support_uniquefilename = -1; +static int hf_smb_connect_support_extended_signature = -1; +static int hf_smb_max_setup_count = -1; +static int hf_smb_total_param_count = -1; +static int hf_smb_total_data_count = -1; +static int hf_smb_max_param_count = -1; +static int hf_smb_max_data_count = -1; +static int hf_smb_param_disp16 = -1; +static int hf_smb_param_count16 = -1; +static int hf_smb_param_offset16 = -1; +static int hf_smb_param_disp32 = -1; +static int hf_smb_param_count32 = -1; +static int hf_smb_param_offset32 = -1; +static int hf_smb_data_disp16 = -1; +static int hf_smb_data_count16 = -1; +static int hf_smb_data_offset16 = -1; +static int hf_smb_data_disp32 = -1; +static int hf_smb_data_count32 = -1; +static int hf_smb_data_offset32 = -1; +static int hf_smb_setup_count = -1; +static int hf_smb_nt_trans_subcmd = -1; +static int hf_smb_nt_ioctl_isfsctl = -1; +static int hf_smb_nt_ioctl_flags_completion_filter = -1; +static int hf_smb_nt_ioctl_flags_root_handle = -1; +static int hf_smb_nt_notify_action = -1; +static int hf_smb_nt_notify_watch_tree = -1; +static int hf_smb_nt_notify_completion_filter = -1; +static int hf_smb_nt_notify_stream_write = -1; +static int hf_smb_nt_notify_stream_size = -1; +static int hf_smb_nt_notify_stream_name = -1; +static int hf_smb_nt_notify_security = -1; +static int hf_smb_nt_notify_ea = -1; +static int hf_smb_nt_notify_creation = -1; +static int hf_smb_nt_notify_last_access = -1; +static int hf_smb_nt_notify_last_write = -1; +static int hf_smb_nt_notify_size = -1; +static int hf_smb_nt_notify_attributes = -1; +static int hf_smb_nt_notify_dir_name = -1; +static int hf_smb_nt_notify_file_name = -1; +static int hf_smb_root_dir_fid = -1; +static int hf_smb_nt_create_disposition = -1; +static int hf_smb_sd_length = -1; +static int hf_smb_ea_list_length = -1; +static int hf_smb_ea_flags = -1; +static int hf_smb_ea_name_length = -1; +static int hf_smb_ea_data_length = -1; +static int hf_smb_ea_name = -1; +static int hf_smb_ea_data = -1; +static int hf_smb_file_name_len = -1; +static int hf_smb_nt_impersonation_level = -1; +static int hf_smb_nt_security_flags = -1; +static int hf_smb_nt_security_flags_context_tracking = -1; +static int hf_smb_nt_security_flags_effective_only = -1; +static int hf_smb_nt_access_mask_generic_read = -1; +static int hf_smb_nt_access_mask_generic_write = -1; +static int hf_smb_nt_access_mask_generic_execute = -1; +static int hf_smb_nt_access_mask_generic_all = -1; +static int hf_smb_nt_access_mask_maximum_allowed = -1; +static int hf_smb_nt_access_mask_system_security = -1; +static int hf_smb_nt_access_mask_synchronize = -1; +static int hf_smb_nt_access_mask_write_owner = -1; +static int hf_smb_nt_access_mask_write_dac = -1; +static int hf_smb_nt_access_mask_read_control = -1; +static int hf_smb_nt_access_mask_delete = -1; +static int hf_smb_nt_access_mask_write_attributes = -1; +static int hf_smb_nt_access_mask_read_attributes = -1; +static int hf_smb_nt_access_mask_delete_child = -1; +static int hf_smb_nt_access_mask_execute = -1; +static int hf_smb_nt_access_mask_write_ea = -1; +static int hf_smb_nt_access_mask_read_ea = -1; +static int hf_smb_nt_access_mask_append = -1; +static int hf_smb_nt_access_mask_write = -1; +static int hf_smb_nt_access_mask_read = -1; +static int hf_smb_nt_create_bits_oplock = -1; +static int hf_smb_nt_create_bits_boplock = -1; +static int hf_smb_nt_create_bits_dir = -1; +static int hf_smb_nt_create_bits_ext_resp = -1; +static int hf_smb_nt_create_options_directory_file = -1; +static int hf_smb_nt_create_options_write_through = -1; +static int hf_smb_nt_create_options_sequential_only = -1; +static int hf_smb_nt_create_options_no_intermediate_buffering = -1; +static int hf_smb_nt_create_options_sync_io_alert = -1; +static int hf_smb_nt_create_options_sync_io_nonalert = -1; +static int hf_smb_nt_create_options_non_directory_file = -1; +static int hf_smb_nt_create_options_create_tree_connection = -1; +static int hf_smb_nt_create_options_complete_if_oplocked = -1; +static int hf_smb_nt_create_options_no_ea_knowledge = -1; +static int hf_smb_nt_create_options_eight_dot_three_only = -1; +static int hf_smb_nt_create_options_random_access = -1; +static int hf_smb_nt_create_options_delete_on_close = -1; +static int hf_smb_nt_create_options_open_by_fileid = -1; +static int hf_smb_nt_create_options_backup_intent = -1; +static int hf_smb_nt_create_options_no_compression = -1; +static int hf_smb_nt_create_options_reserve_opfilter = -1; +static int hf_smb_nt_create_options_open_reparse_point = -1; +static int hf_smb_nt_create_options_open_no_recall = -1; +static int hf_smb_nt_create_options_open_for_free_space_query = -1; +static int hf_smb_nt_share_access_read = -1; +static int hf_smb_nt_share_access_write = -1; +static int hf_smb_nt_share_access_delete = -1; +static int hf_smb_file_eattr = -1; +static int hf_smb_file_eattr_read_only = -1; +static int hf_smb_file_eattr_hidden = -1; +static int hf_smb_file_eattr_system = -1; +static int hf_smb_file_eattr_volume = -1; +static int hf_smb_file_eattr_directory = -1; +static int hf_smb_file_eattr_archive = -1; +static int hf_smb_file_eattr_device = -1; +static int hf_smb_file_eattr_normal = -1; +static int hf_smb_file_eattr_temporary = -1; +static int hf_smb_file_eattr_sparse = -1; +static int hf_smb_file_eattr_reparse = -1; +static int hf_smb_file_eattr_compressed = -1; +static int hf_smb_file_eattr_offline = -1; +static int hf_smb_file_eattr_not_content_indexed = -1; +static int hf_smb_file_eattr_encrypted = -1; +static int hf_smb_size_returned_quota_data = -1; +static int hf_smb_sec_desc_len = -1; +static int hf_smb_nt_qsd = -1; +static int hf_smb_nt_qsd_owner = -1; +static int hf_smb_nt_qsd_group = -1; +static int hf_smb_nt_qsd_dacl = -1; +static int hf_smb_nt_qsd_sacl = -1; +static int hf_smb_extended_attributes = -1; +static int hf_smb_oplock_level = -1; +static int hf_smb_response_type = -1; +static int hf_smb_create_action = -1; +static int hf_smb_file_id = -1; +static int hf_smb_file_id_64bit = -1; +static int hf_smb_ea_error_offset = -1; +static int hf_smb_end_of_file = -1; +static int hf_smb_replace = -1; +static int hf_smb_root_dir_handle = -1; +static int hf_smb_target_name_len = -1; +static int hf_smb_target_name = -1; +static int hf_smb_device_type = -1; +static int hf_smb_is_directory = -1; +static int hf_smb_next_entry_offset = -1; +static int hf_smb_change_time = -1; +static int hf_smb_setup_len = -1; +static int hf_smb_print_mode = -1; +static int hf_smb_print_identifier = -1; +static int hf_smb_restart_index = -1; +static int hf_smb_print_queue_date = -1; +static int hf_smb_print_queue_dos_date = -1; +static int hf_smb_print_queue_dos_time = -1; +static int hf_smb_print_status = -1; +static int hf_smb_print_spool_file_number = -1; +static int hf_smb_print_spool_file_size = -1; +static int hf_smb_print_spool_file_name = -1; +static int hf_smb_start_index = -1; +static int hf_smb_originator_name = -1; +static int hf_smb_destination_name = -1; +static int hf_smb_message_len = -1; +static int hf_smb_message = -1; +static int hf_smb_mgid = -1; +static int hf_smb_forwarded_name = -1; +static int hf_smb_machine_name = -1; +static int hf_smb_cancel_to = -1; +static int hf_smb_trans2_subcmd = -1; +static int hf_smb_trans_name = -1; +static int hf_smb_transaction_flags = -1; +static int hf_smb_transaction_flags_dtid = -1; +static int hf_smb_transaction_flags_owt = -1; +static int hf_smb_search_count = -1; +static int hf_smb_search_pattern = -1; +static int hf_smb_ff2 = -1; +static int hf_smb_ff2_backup = -1; +static int hf_smb_ff2_continue = -1; +static int hf_smb_ff2_resume = -1; +static int hf_smb_ff2_close_eos = -1; +static int hf_smb_ff2_close = -1; +static int hf_smb_ff2_information_level = -1; +static int hf_smb_qpi_loi = -1; +static int hf_smb_spi_loi = -1; +#if 0 +static int hf_smb_sfi = -1; +static int hf_smb_sfi_writetru = -1; +static int hf_smb_sfi_caching = -1; +#endif +static int hf_smb_storage_type = -1; +static int hf_smb_resume = -1; +static int hf_smb_max_referral_level = -1; +static int hf_smb_qfsi_information_level = -1; +static int hf_smb_sfsi_information_level = -1; +static int hf_smb_number_of_links = -1; +static int hf_smb_delete_pending = -1; +static int hf_smb_index_number = -1; +static int hf_smb_position = -1; +/* static int hf_smb_current_offset = -1; */ +static int hf_smb_t2_alignment = -1; +static int hf_smb_t2_stream_name_length = -1; +static int hf_smb_t2_stream_size = -1; +static int hf_smb_t2_stream_name = -1; +static int hf_smb_t2_compressed_file_size = -1; +static int hf_smb_t2_compressed_format = -1; +static int hf_smb_t2_compressed_unit_shift = -1; +static int hf_smb_t2_compressed_chunk_shift = -1; +static int hf_smb_t2_compressed_cluster_shift = -1; +static int hf_smb_t2_marked_for_deletion = -1; +static int hf_smb_dfs_path_consumed = -1; +static int hf_smb_dfs_num_referrals = -1; +static int hf_smb_get_dfs_flags = -1; +static int hf_smb_get_dfs_server_hold_storage = -1; +static int hf_smb_get_dfs_fielding = -1; +static int hf_smb_dfs_referral_version = -1; +static int hf_smb_dfs_referral_size = -1; +static int hf_smb_dfs_referral_server_type = -1; +static int hf_smb_dfs_referral_flags = -1; +static int hf_smb_dfs_referral_flags_name_list_referral = -1; +static int hf_smb_dfs_referral_flags_target_set_boundary = -1; +static int hf_smb_dfs_referral_node_offset = -1; +static int hf_smb_dfs_referral_node = -1; +static int hf_smb_dfs_referral_proximity = -1; +static int hf_smb_dfs_referral_ttl = -1; +static int hf_smb_dfs_referral_path_offset = -1; +static int hf_smb_dfs_referral_path = -1; +static int hf_smb_dfs_referral_alt_path_offset = -1; +static int hf_smb_dfs_referral_alt_path = -1; +static int hf_smb_dfs_referral_domain_offset = -1; +static int hf_smb_dfs_referral_number_of_expnames = -1; +static int hf_smb_dfs_referral_expnames_offset = -1; +static int hf_smb_dfs_referral_domain_name = -1; +static int hf_smb_dfs_referral_expname = -1; +static int hf_smb_dfs_referral_server_guid = -1; +static int hf_smb_end_of_search = -1; +static int hf_smb_last_name_offset = -1; +static int hf_smb_fn_information_level = -1; +static int hf_smb_monitor_handle = -1; +static int hf_smb_change_count = -1; +static int hf_smb_file_index = -1; +static int hf_smb_short_file_name = -1; +static int hf_smb_short_file_name_len = -1; +static int hf_smb_fs_id = -1; +static int hf_smb_sector_unit = -1; +static int hf_smb_fs_units = -1; +static int hf_smb_fs_sector = -1; +static int hf_smb_avail_units = -1; +static int hf_smb_volume_serial_num = -1; +static int hf_smb_volume_label_len = -1; +static int hf_smb_volume_label = -1; +static int hf_smb_free_alloc_units64 = -1; +static int hf_smb_caller_free_alloc_units64 = -1; +static int hf_smb_actual_free_alloc_units64 = -1; +static int hf_smb_max_name_len = -1; +static int hf_smb_fs_name_len = -1; +static int hf_smb_fs_name = -1; +static int hf_smb_device_char = -1; +static int hf_smb_device_char_removable = -1; +static int hf_smb_device_char_read_only = -1; +static int hf_smb_device_char_floppy = -1; +static int hf_smb_device_char_write_once = -1; +static int hf_smb_device_char_remote = -1; +static int hf_smb_device_char_mounted = -1; +static int hf_smb_device_char_virtual = -1; +static int hf_smb_device_char_secure_open = -1; +static int hf_smb_device_char_ts = -1; +static int hf_smb_device_char_webdav = -1; +static int hf_smb_device_char_aat = -1; +static int hf_smb_device_char_portable = -1; +static int hf_smb_fs_attr = -1; +static int hf_smb_fs_attr_css = -1; +static int hf_smb_fs_attr_cpn = -1; +static int hf_smb_fs_attr_uod = -1; +static int hf_smb_fs_attr_pacls = -1; +static int hf_smb_fs_attr_fc = -1; +static int hf_smb_fs_attr_vq = -1; +static int hf_smb_fs_attr_ssf = -1; +static int hf_smb_fs_attr_srp = -1; +static int hf_smb_fs_attr_srs = -1; +static int hf_smb_fs_attr_sla = -1; +static int hf_smb_fs_attr_vic = -1; +static int hf_smb_fs_attr_soids = -1; +static int hf_smb_fs_attr_se = -1; +static int hf_smb_fs_attr_ns = -1; +static int hf_smb_fs_attr_rov = -1; +static int hf_smb_fs_attr_swo = -1; +static int hf_smb_fs_attr_st = -1; +static int hf_smb_fs_attr_shl = -1; +static int hf_smb_fs_attr_sis = -1; +static int hf_smb_fs_attr_sbr = -1; +static int hf_smb_fs_attr_ssv = -1; +static int hf_smb_quota_flags = -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_change_time = -1; +static int hf_smb_length_of_sid = -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 int hf_smb_segments = -1; +static int hf_smb_segment = -1; +static int hf_smb_segment_overlap = -1; +static int hf_smb_segment_overlap_conflict = -1; +static int hf_smb_segment_multiple_tails = -1; +static int hf_smb_segment_too_long_fragment = -1; +static int hf_smb_segment_error = -1; +static int hf_smb_segment_count = -1; +static int hf_smb_reassembled_length = -1; +static int hf_smb_pipe_write_len = -1; +static int hf_smb_unix_major_version = -1; +static int hf_smb_unix_minor_version = -1; +static int hf_smb_unix_capability = -1; +static int hf_smb_unix_capability_fcntl = -1; +static int hf_smb_unix_capability_posix_acl = -1; +static int hf_smb_unix_capability_xattr = -1; +static int hf_smb_unix_capability_attr = -1; +static int hf_smb_unix_capability_posix_paths = -1; +static int hf_smb_unix_capability_posix_path_ops = -1; +static int hf_smb_unix_capability_large_read = -1; +static int hf_smb_unix_capability_large_write = -1; +static int hf_smb_unix_capability_encryption = -1; +static int hf_smb_unix_capability_mandatory_crypto = -1; +static int hf_smb_unix_capability_proxy = -1; +static int hf_smb_unix_file_link_dest = -1; +static int hf_smb_unix_file_size = -1; +static int hf_smb_unix_file_num_bytes = -1; +static int hf_smb_unix_file_last_status = -1; +static int hf_smb_unix_file_last_access = -1; +static int hf_smb_unix_file_last_change = -1; +static int hf_smb_unix_file_creation_time = -1; +static int hf_smb_unix_file_uid = -1; +static int hf_smb_unix_file_gid = -1; +static int hf_smb_unix_file_type = -1; +static int hf_smb_unix_file_dev_major = -1; +static int hf_smb_unix_file_dev_minor = -1; +static int hf_smb_unix_file_unique_id = -1; +static int hf_smb_unix_file_permissions = -1; +static int hf_smb_unix_file_nlinks = -1; +static int hf_smb_unix_info2_file_flags = -1; +static int hf_smb_unix_info2_file_flags_mask = -1; +static int hf_smb_unix_info2_file_flags_secure_delete = -1; +static int hf_smb_unix_info2_file_flags_enable_undelete = -1; +static int hf_smb_unix_info2_file_flags_synchronous = -1; +static int hf_smb_unix_info2_file_flags_immutable = -1; +static int hf_smb_unix_info2_file_flags_append_only = -1; +static int hf_smb_unix_info2_file_flags_do_not_backup = -1; +static int hf_smb_unix_info2_file_flags_no_update_atime = -1; +static int hf_smb_unix_info2_file_flags_hidden = -1; +static int hf_smb_unix_file_name_length = -1; +static int hf_smb_unix_file_name = -1; +static int hf_smb_unix_find_file_nextoffset = -1; +static int hf_smb_unix_find_file_resumekey = -1; +static int hf_smb_unix_whoami_mapflags = -1; +static int hf_smb_unix_whoami_mapflags_mask = -1; +static int hf_smb_unix_whoami_num_supl_gids = -1; +static int hf_smb_unix_whoami_num_supl_sids = -1; +static int hf_smb_unix_whoami_sids_buflen = -1; +static int hf_smb_disposition_delete_on_close = -1; +static int hf_smb_pipe_info_flag = -1; +static int hf_smb_mode = -1; +static int hf_smb_attribute = -1; +static int hf_smb_reparse_tag = -1; +static int hf_smb_logged_in = -1; +static int hf_smb_logged_out = -1; +static int hf_smb_file_rw_offset = -1; +static int hf_smb_file_rw_length = -1; +static int hf_smb_posix_acl_version = -1; +static int hf_smb_posix_num_file_aces = -1; +static int hf_smb_posix_num_def_aces = -1; +static int hf_smb_posix_ace_type = -1; +static int hf_smb_posix_ace_flags = -1; +static int hf_smb_posix_ace_perm_read = -1; +static int hf_smb_posix_ace_perm_write = -1; +static int hf_smb_posix_ace_perm_execute = -1; +static int hf_smb_posix_ace_perm_owner_uid = -1; +static int hf_smb_posix_ace_perm_owner_gid = -1; +static int hf_smb_posix_ace_perm_uid = -1; +static int hf_smb_posix_ace_perm_gid = -1; +static int hf_smb_trans_data_setup_word = -1; +static int hf_smb_trans_data_parameters = -1; +static int hf_smb_trans_data = -1; +static int hf_smb_extra_byte_parameters = -1; +static int hf_smb_file_access_mask_full_control = -1; +static int hf_smb_dir_access_mask_full_control = -1; +static int hf_smb_word_unk_response_format = -1; +static int hf_smb_nt_transaction_setup = -1; +static int hf_smb_server_component = -1; +static int hf_smb_byte_parameters = -1; +static int hf_smb_word_parameters = -1; + +static gint ett_smb = -1; +static gint ett_smb_fid = -1; +static gint ett_smb_tid = -1; +static gint ett_smb_uid = -1; +static gint ett_smb_hdr = -1; +static gint ett_smb_command = -1; +static gint ett_smb_fileattributes = -1; +static gint ett_smb_capabilities = -1; +static gint ett_smb_aflags = -1; +static gint ett_smb_dialect = -1; +static gint ett_smb_dialects = -1; +static gint ett_smb_mode = -1; +static gint ett_smb_rawmode = -1; +static gint ett_smb_flags = -1; +static gint ett_smb_flags2 = -1; +static gint ett_smb_desiredaccess = -1; +static gint ett_smb_search = -1; +static gint ett_smb_file = -1; +static gint ett_smb_openfunction = -1; +static gint ett_smb_filetype = -1; +static gint ett_smb_openaction = -1; +static gint ett_smb_writemode = -1; +static gint ett_smb_lock_type = -1; +static gint ett_smb_ssetupandxaction = -1; +static gint ett_smb_optionsup = -1; +static gint ett_smb_time_date = -1; +static gint ett_smb_move_copy_flags = -1; +static gint ett_smb_file_attributes = -1; +static gint ett_smb_search_resume_key = -1; +static gint ett_smb_search_dir_info = -1; +static gint ett_smb_unlocks = -1; +static gint ett_smb_unlock = -1; +static gint ett_smb_locks = -1; +static gint ett_smb_lock = -1; +static gint ett_smb_open_flags = -1; +static gint ett_smb_ipc_state = -1; +static gint ett_smb_open_action = -1; +static gint ett_smb_setup_action = -1; +static gint ett_smb_connect_flags = -1; +static gint ett_smb_connect_support_bits = -1; +static gint ett_smb_nt_access_mask = -1; +static gint ett_smb_nt_create_bits = -1; +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; +static gint ett_smb_print_queue_entry = -1; +static gint ett_smb_transaction_flags = -1; +static gint ett_smb_transaction_params = -1; +static gint ett_smb_find_first2_flags = -1; +static gint ett_smb_mac_support_flags = -1; +#if 0 +static gint ett_smb_ioflag = -1; +#endif +static gint ett_smb_transaction_data = -1; +static gint ett_smb_stream_info = -1; +static gint ett_smb_dfs_referrals = -1; +static gint ett_smb_dfs_referral = -1; +static gint ett_smb_dfs_referral_flags = -1; +static gint ett_smb_dfs_referral_expnames = -1; +static gint ett_smb_get_dfs_flags = -1; +static gint ett_smb_ff2_data = -1; +static gint ett_smb_device_characteristics = -1; +static gint ett_smb_fs_attributes = -1; +static gint ett_smb_segments = -1; +static gint ett_smb_segment = -1; +static gint ett_smb_quotaflags = -1; +static gint ett_smb_secblob = -1; +static gint ett_smb_unicode_password = -1; +static gint ett_smb_ea = -1; +static gint ett_smb_unix_capabilities = -1; +static gint ett_smb_unix_whoami_gids = -1; +static gint ett_smb_unix_whoami_sids = -1; +static gint ett_smb_posix_ace = -1; +static gint ett_smb_posix_ace_perms = -1; +static gint ett_smb_info2_file_flags = -1; + +static expert_field ei_smb_missing_word_parameters = EI_INIT; +static expert_field ei_smb_mal_information_level = EI_INIT; +static expert_field ei_smb_not_implemented = EI_INIT; +static expert_field ei_smb_nt_transaction_setup = EI_INIT; +static expert_field ei_smb_posix_ace_type = EI_INIT; +static expert_field ei_smb_info_level_unknown = EI_INIT; +static expert_field ei_smb_info_level_not_understood = EI_INIT; + +static int smb_tap = -1; +static int smb_eo_tap = -1; + +static dissector_handle_t smb_handle; +static dissector_handle_t gssapi_handle; +static dissector_handle_t ntlmssp_handle; + +static const fragment_items smb_frag_items = { + &ett_smb_segment, + &ett_smb_segments, + + &hf_smb_segments, + &hf_smb_segment, + &hf_smb_segment_overlap, + &hf_smb_segment_overlap_conflict, + &hf_smb_segment_multiple_tails, + &hf_smb_segment_too_long_fragment, + &hf_smb_segment_error, + &hf_smb_segment_count, + NULL, + &hf_smb_reassembled_length, + /* Reassembled data field */ + NULL, + "segments" +}; + +static proto_tree *top_tree_global = NULL; /* ugly */ + +static int dissect_smb_command(tvbuff_t *tvb, packet_info *pinfo, int offset, proto_tree *smb_tree, guint8 cmd, gboolean first_pdu, smb_info_t *si); + +#define SMB_NUM_PROCEDURES 256 +#define SMB_SRT_TABLE_INDEX 0 +#define TRANS2_SRT_TABLE_INDEX 1 +#define NT_SRT_TABLE_INDEX 2 + +static void +smbstat_init(struct register_srt* srt _U_, GArray* srt_array) +{ + srt_stat_table *smb_srt_table; + srt_stat_table *trans2_srt_table; + srt_stat_table *nt_srt_table; + guint32 i; + + smb_srt_table = init_srt_table("SMB Commands", NULL, srt_array, SMB_NUM_PROCEDURES, "Commands", "smb.cmd", NULL); + trans2_srt_table = init_srt_table("Transaction2 Sub-Commands", NULL, srt_array, SMB_NUM_PROCEDURES, "Transaction2 Commands", "smb.trans2.cmd", NULL); + nt_srt_table = init_srt_table("NT Transaction Sub-Commands", NULL, srt_array, SMB_NUM_PROCEDURES, "NT Transaction Sub-Commands", "smb.nt.function", NULL); + for (i = 0; i < SMB_NUM_PROCEDURES; i++) + { + init_srt_table_row(smb_srt_table, i, val_to_str_ext_const(i, &smb_cmd_vals_ext, "<unknown>")); + init_srt_table_row(trans2_srt_table, i, val_to_str_ext_const(i, &trans2_cmd_vals_ext, "<unknown>")); + init_srt_table_row(nt_srt_table, i, val_to_str_ext_const(i, &nt_cmd_vals_ext, "<unknown>")); + } +} + +static tap_packet_status +smbstat_packet(void *pss, packet_info *pinfo, epan_dissect_t *edt _U_, const void *prv, tap_flags_t flags _U_) +{ + guint i = 0; + srt_stat_table *smb_srt_table; + srt_data_t *data = (srt_data_t *)pss; + const smb_info_t *si = (const smb_info_t *)prv; + + /* we are only interested in reply packets */ + if (si->request) { + return TAP_PACKET_DONT_REDRAW; + } + /* if we havnt seen the request, just ignore it */ + if (!si->sip) { + return TAP_PACKET_DONT_REDRAW; + } + + if (si->cmd == 0xA0 && si->sip->extra_info_type == SMB_EI_NTI) { + smb_nt_transact_info_t *sti = (smb_nt_transact_info_t *)si->sip->extra_info; + + /*nt transaction*/ + if (sti) { + i = NT_SRT_TABLE_INDEX; + smb_srt_table = g_array_index(data->srt_array, srt_stat_table*, i); + add_srt_table_data(smb_srt_table, sti->subcmd, &si->sip->req_time, pinfo); + } + } else if (si->cmd == 0x32 && si->sip->extra_info_type == SMB_EI_T2I) { + smb_transact2_info_t *st2i = (smb_transact2_info_t *)si->sip->extra_info; + + /*transaction2*/ + if (st2i) { + i = TRANS2_SRT_TABLE_INDEX; + smb_srt_table = g_array_index(data->srt_array, srt_stat_table*, i); + add_srt_table_data(smb_srt_table, st2i->subcmd, &si->sip->req_time, pinfo); + } + } else { + i = SMB_SRT_TABLE_INDEX; + smb_srt_table = g_array_index(data->srt_array, srt_stat_table*, i); + add_srt_table_data(smb_srt_table, si->cmd, &si->sip->req_time, pinfo); + } + + return TAP_PACKET_REDRAW; + +} + +/* + * Export object functionality + */ +/* These flags show what kind of data the object contains + (designed to be or'ed) */ +#define SMB_EO_CONTAINS_NOTHING 0x00 +#define SMB_EO_CONTAINS_READS 0x01 +#define SMB_EO_CONTAINS_WRITES 0x02 +#define SMB_EO_CONTAINS_READSANDWRITES 0x03 + +static const value_string smb_eo_contains_string[] = { + {SMB_EO_CONTAINS_NOTHING, "" }, + {SMB_EO_CONTAINS_READS, "R" }, + {SMB_EO_CONTAINS_WRITES, "W" }, + {SMB_EO_CONTAINS_READSANDWRITES, "R&W"}, + {0, NULL} +}; + +/* Strings that describes the SMB object type */ +static const value_string smb_fid_types[] = { + {SMB_FID_TYPE_UNKNOWN,"UNKNOWN"}, + {SMB_FID_TYPE_FILE,"FILE"}, + {SMB_FID_TYPE_DIR,"DIRECTORY (Not Implemented)"}, + {SMB_FID_TYPE_PIPE,"PIPE (Not Implemented)"}, + {0, NULL} +}; + +static const value_string smb2_fid_types[] = { + {SMB2_FID_TYPE_UNKNOWN,"UNKNOWN"}, + {SMB2_FID_TYPE_FILE,"FILE"}, + {SMB2_FID_TYPE_DIR,"DIRECTORY (Not Implemented)"}, + {SMB2_FID_TYPE_PIPE,"PIPE (Not Implemented)"}, + {SMB2_FID_TYPE_OTHER,"OTHER (Not Implemented)"}, + {0, NULL} +}; + + +/* This struct contains the relationship between + the row# in the export_object window and the file being captured; + the row# in this GSList will match the row# in the entry list */ + +typedef struct _active_file { + guint16 tid, uid; + guint32 fid; /* 16-bit fid (smb) or 32-bit compressed fid (smb2) */ + guint64 file_length; /* The last free reported offset. We treat it as the file length */ + guint64 data_gathered; /* The actual total of data gathered */ + guint8 flag_contains; /* What kind of data it contains */ + GSList *free_chunk_list; /* A list of virtual "holes" in the file stream stored in memory */ + gboolean is_out_of_memory; /* TRUE if we cannot allocate memory for this file */ +} active_file ; + +/* This is the GSList that will contain all the files that we are tracking */ +static GSList *GSL_active_files = NULL; + +/* We define a free chunk in a file as an start offset and end offset + Consider a free chunk as a "hole" in a file that we are capturing */ +typedef struct _free_chunk { + guint64 start_offset; + guint64 end_offset; +} free_chunk; + +/* insert_chunk function will recalculate the free_chunk_list, the data_size, + the end_of_file, and the data_gathered as appropriate. + It will also insert the data chunk that is coming in the right + place of the file in memory. + HINTS: + file->data_gathered contains the real data gathered independently from the file length + file->file_length contains the length of the file in memory, i.e., + the last offset captured. In most cases, the real + file length would be different. +*/ +static void +insert_chunk(active_file *file, export_object_entry_t *entry, const smb_eo_t *eo_info) +{ + gint nfreechunks = g_slist_length(file->free_chunk_list); + gint i; + free_chunk *current_free_chunk; + free_chunk *new_free_chunk; + guint64 chunk_offset = eo_info->smb_file_offset; + guint64 chunk_length = eo_info->payload_len; + guint64 chunk_end_offset = chunk_offset + chunk_length-1; + /* Size of file in memory */ + guint64 calculated_size = chunk_offset + chunk_length; + gpointer dest_memory_addr; + + /* Let's recalculate the file length and data gathered */ + if ((file->data_gathered == 0) && (nfreechunks == 0)) { + /* If this is the first entry for this file, we first create an initial free chunk */ + new_free_chunk = g_new(free_chunk, 1); + new_free_chunk->start_offset = 0; + new_free_chunk->end_offset = MAX(file->file_length, chunk_end_offset+1) - 1; + file->free_chunk_list = NULL; + file->free_chunk_list = g_slist_append(file->free_chunk_list, new_free_chunk); + nfreechunks += 1; + } else { + if (chunk_end_offset > file->file_length-1) { + new_free_chunk = g_new(free_chunk, 1); + new_free_chunk->start_offset = file->file_length; + new_free_chunk->end_offset = chunk_end_offset; + file->free_chunk_list = g_slist_append(file->free_chunk_list, new_free_chunk); + nfreechunks += 1; + } + } + file->file_length = MAX(file->file_length, chunk_end_offset+1); + + /* Recalculate each free chunk according with the incoming data chunk */ + for (i=0; i<nfreechunks; i++) { + current_free_chunk = (free_chunk *)g_slist_nth_data(file->free_chunk_list, i); + /* 1. data chunk before the free chunk? */ + /* -> free chunk is not altered and no new data gathered */ + if (chunk_end_offset<current_free_chunk->start_offset) { + continue; + } + /* 2. data chunk overlaps the first part of free_chunk */ + /* -> free chunk shrinks from the beginning */ + if (chunk_offset<=current_free_chunk->start_offset && chunk_end_offset>=current_free_chunk->start_offset && chunk_end_offset<current_free_chunk->end_offset) { + file->data_gathered += chunk_end_offset-current_free_chunk->start_offset+1; + current_free_chunk->start_offset=chunk_end_offset+1; + continue; + } + /* 3. data chunk overlaps completely the free chunk */ + /* -> free chunk is removed */ + if (chunk_offset<=current_free_chunk->start_offset && chunk_end_offset>=current_free_chunk->end_offset) { + file->data_gathered += current_free_chunk->end_offset-current_free_chunk->start_offset+1; + file->free_chunk_list = g_slist_remove(file->free_chunk_list, current_free_chunk); + g_free(current_free_chunk); + nfreechunks -= 1; + if (nfreechunks == 0) { /* The free chunk list is empty */ + g_slist_free(file->free_chunk_list); + file->free_chunk_list = NULL; + break; + } + i--; + continue; + } + /* 4. data chunk is inside the free chunk */ + /* -> free chunk is split into two */ + if (chunk_offset>current_free_chunk->start_offset && chunk_end_offset<current_free_chunk->end_offset) { + new_free_chunk = g_new(free_chunk, 1); + new_free_chunk->start_offset = chunk_end_offset + 1; + new_free_chunk->end_offset = current_free_chunk->end_offset; + current_free_chunk->end_offset = chunk_offset-1; + file->free_chunk_list = g_slist_insert(file->free_chunk_list, new_free_chunk, i + 1); + file->data_gathered += chunk_length; + continue; + } + /* 5.- data chunk overlaps the end part of free chunk */ + /* -> free chunk shrinks from the end */ + if (chunk_offset>current_free_chunk->start_offset && chunk_offset<=current_free_chunk->end_offset && chunk_end_offset>=current_free_chunk->end_offset) { + file->data_gathered += current_free_chunk->end_offset-chunk_offset+1; + current_free_chunk->end_offset = chunk_offset-1; + continue; + } + /* 6.- data chunk is after the free chunk */ + /* -> free chunk is not altered and no new data gathered */ + if (chunk_offset>current_free_chunk->end_offset) { + continue; + } + } + + /* Now, let's insert the data chunk into memory + ...first, we shall be able to allocate the memory */ + if (!entry->payload_data) { + /* This is a New file */ + if (calculated_size > G_MAXUINT32) { + /* + * The argument to g_try_malloc() is + * a gsize, however the maximum size of a file + * is 32-bit. If the calculated size is + * bigger than that, we just say the attempt + * to allocate memory failed. + */ + entry->payload_data = NULL; + } else { + entry->payload_data = (guint8 *)g_try_malloc((gsize)calculated_size); + entry->payload_len = (size_t)calculated_size; + } + if (!entry->payload_data) { + /* Memory error */ + file->is_out_of_memory = TRUE; + } + } else { + /* This is an existing file in memory */ + if (calculated_size > (guint64) entry->payload_len && + !file->is_out_of_memory) { + /* We need more memory */ + if (calculated_size > G_MAXUINT32) { + /* + * As for g_try_malloc(), so for + * g_try_realloc(). + */ + dest_memory_addr = NULL; + } else { + dest_memory_addr = g_try_realloc( + entry->payload_data, + (gsize)calculated_size); + } + if (!dest_memory_addr) { + /* Memory error */ + file->is_out_of_memory = TRUE; + /* We don't have memory for this file. + Free the current file content from memory */ + g_free(entry->payload_data); + entry->payload_data = NULL; + entry->payload_len = 0; + } else { + entry->payload_data = (guint8 *)dest_memory_addr; + entry->payload_len = (size_t)calculated_size; + } + } + } + /* ...then, put the chunk of the file in the right place */ + if (!file->is_out_of_memory) { + dest_memory_addr = entry->payload_data + chunk_offset; + memmove(dest_memory_addr, eo_info->payload_data, eo_info->payload_len); + } +} + +/* We use this function to obtain the index in the GSL of a given file */ +static int +find_incoming_file(GSList *GSL_active_files_p, active_file *incoming_file) +{ + int i, row, last; + active_file *in_list_file; + + row = -1; + last = g_slist_length(GSL_active_files_p) - 1; + + /* We lookup in reverse order because it is more likely that the file + is one of the latest */ + for (i=last; i>=0; i--) { + in_list_file = (active_file *)g_slist_nth_data(GSL_active_files_p, i); + /* The best-working criteria of two identical files is that the file + that is the same of the file that we are analyzing is the last one + in the list that has the same tid and the same fid */ + /* note that we have excluded in_list_file->uid == incoming_file->uid + from the comparison, because a file can be opened by different + SMB users and it is still the same file */ + if (in_list_file->tid == incoming_file->tid && + in_list_file->fid == incoming_file->fid) { + row = i; + break; + } + } + + return row; +} + +static tap_packet_status +smb_eo_packet(void *tapdata, packet_info *pinfo, epan_dissect_t *edt _U_, const void *data, tap_flags_t flags _U_) +{ + export_object_list_t *object_list = (export_object_list_t *)tapdata; + const smb_eo_t *eo_info = (const smb_eo_t *)data; + + export_object_entry_t *entry; + export_object_entry_t *current_entry; + active_file incoming_file; + gint active_row; + active_file *new_file; + active_file *current_file; + guint8 contains; + gboolean is_supported_filetype; + gfloat percent; + + const gchar *aux_smb_fid_type_string; + + if (eo_info->smbversion==1) { + /* Is this an eo_smb supported file_type? (right now we only support FILE) */ + is_supported_filetype = (eo_info->fid_type == SMB_FID_TYPE_FILE); + aux_smb_fid_type_string = val_to_str_const(eo_info->fid_type, smb_fid_types, "?"); + + /* What kind of data this packet contains? */ + switch(eo_info->cmd) { + case SMB_COM_READ_ANDX: + case SMB_COM_READ: + contains = SMB_EO_CONTAINS_READS; + break; + case SMB_COM_WRITE_ANDX: + case SMB_COM_WRITE: + contains = SMB_EO_CONTAINS_WRITES; + break; + default: + contains = SMB_EO_CONTAINS_NOTHING; + break; + } + } else { + /* Is this an eo_smb supported file_type? (right now we only support FILE) */ + is_supported_filetype = (eo_info->fid_type == SMB2_FID_TYPE_FILE ); + aux_smb_fid_type_string = val_to_str_const(eo_info->fid_type, smb2_fid_types, "?"); + + /* What kind of data this packet contains? */ + switch(eo_info->cmd) { + case SMB2_COM_READ: + contains = SMB_EO_CONTAINS_READS; + break; + case SMB2_COM_WRITE: + contains = SMB_EO_CONTAINS_WRITES; + break; + default: + contains = SMB_EO_CONTAINS_NOTHING; + break; + } + } + + + /* Is this data from an already tracked file or not? */ + incoming_file.tid = eo_info->tid; + incoming_file.uid = eo_info->uid; + incoming_file.fid = eo_info->fid; + active_row = find_incoming_file(GSL_active_files, &incoming_file); + + if (active_row == -1) { /* This is a new-tracked file */ + /* Construct the entry in the list of active files */ + entry = g_new(export_object_entry_t, 1); + entry->payload_data = NULL; + entry->payload_len = 0; + new_file = g_new(active_file, 1); + new_file->tid = incoming_file.tid; + new_file->uid = incoming_file.uid; + new_file->fid = incoming_file.fid; + new_file->file_length = eo_info->end_of_file; + new_file->flag_contains = contains; + new_file->free_chunk_list = NULL; + new_file->data_gathered = 0; + new_file->is_out_of_memory = FALSE; + entry->pkt_num = pinfo->num; + + entry->hostname=g_filename_display_name(eo_info->hostname); + entry->filename=g_filename_display_name(eo_info->filename); + + /* Insert the first chunk in the chunk list of this file */ + if (is_supported_filetype) { + insert_chunk(new_file, entry, eo_info); + } + + if (new_file->is_out_of_memory) { + entry->content_type = + ws_strdup_printf("%s (%"PRIu64"?/%"PRIu64") %s [mem!!]", + aux_smb_fid_type_string, + new_file->data_gathered, + new_file->file_length, + try_val_to_str(contains, smb_eo_contains_string)); + } else { + if (new_file->file_length > 0) { + percent = (gfloat) (100*new_file->data_gathered/new_file->file_length); + } else { + percent = 0.0f; + } + + entry->content_type = + ws_strdup_printf("%s (%"PRIu64"/%"PRIu64") %s [%5.2f%%]", + aux_smb_fid_type_string, + new_file->data_gathered, + new_file->file_length, + try_val_to_str(contains, smb_eo_contains_string), + percent); + } + + object_list->add_entry(object_list->gui_data, entry); + GSL_active_files = g_slist_append(GSL_active_files, new_file); + } + else if (is_supported_filetype) { + current_file = (active_file *)g_slist_nth_data(GSL_active_files, active_row); + /* Recalculate the current file flags */ + current_file->flag_contains = current_file->flag_contains|contains; + current_entry = object_list->get_entry(object_list->gui_data, active_row); + + insert_chunk(current_file, current_entry, eo_info); + + /* Modify the current_entry object_type string */ + if (current_file->is_out_of_memory) { + current_entry->content_type = + ws_strdup_printf("%s (%"PRIu64"?/%"PRIu64") %s [mem!!]", + aux_smb_fid_type_string, + current_file->data_gathered, + current_file->file_length, + try_val_to_str(current_file->flag_contains, smb_eo_contains_string)); + } else { + percent = (gfloat) (100*current_file->data_gathered/current_file->file_length); + current_entry->content_type = + ws_strdup_printf("%s (%"PRIu64"/%"PRIu64") %s [%5.2f%%]", + aux_smb_fid_type_string, + current_file->data_gathered, + current_file->file_length, + try_val_to_str(current_file->flag_contains, smb_eo_contains_string), + percent); + } + } + + return TAP_PACKET_REDRAW; /* State changed - window should be redrawn */ +} + +/* This is the eo_reset_cb function that is used in the export_object module + to cleanup any previous private data of the export object functionality before perform + the eo_reset function or when the window closes */ +static void +smb_eo_cleanup(void) +{ + int i, last; + active_file *in_list_file; + + /* Free any previous data structures used in previous invocation to the + export_object_smb function */ + last = g_slist_length(GSL_active_files); + if (GSL_active_files) { + for (i=last-1; i>=0; i--) { + in_list_file = (active_file *)g_slist_nth_data(GSL_active_files, i); + if (in_list_file->free_chunk_list) { + g_slist_free(in_list_file->free_chunk_list); + in_list_file->free_chunk_list = NULL; + } + g_free(in_list_file); + } + g_slist_free(GSL_active_files); + GSL_active_files = NULL; + } +} + +/* + * Macros for use in the main dissector routines for an SMB. + */ + +#define WORD_COUNT \ + /* Word Count */ \ + wc = tvb_get_guint8(tvb, offset); \ + proto_tree_add_uint(tree, hf_smb_word_count, \ + tvb, offset, 1, wc); \ + offset += 1; \ + if (wc == 0) goto bytecount; + +#define BYTE_COUNT \ + bytecount: \ + bc = tvb_get_letohs(tvb, offset); \ + proto_tree_add_uint(tree, hf_smb_byte_count, \ + tvb, offset, 2, bc); \ + offset += 2; \ + if (bc == 0) goto endofcommand; + +#define CHECK_BYTE_COUNT(len) \ + if (bc < len) goto endofcommand; + +#define COUNT_BYTES(len) {\ + int tmp; \ + tmp = len; \ + offset += tmp; \ + bc -= tmp; \ + } + +#define END_OF_SMB \ + if (bc != 0) { \ + gint bc_remaining; \ + bc_remaining = tvb_reported_length_remaining(tvb, offset); \ + if ( ((gint)bc) > bc_remaining) { \ + bc = bc_remaining; \ + } \ + if (bc) { \ + proto_tree_add_item(tree, hf_smb_extra_byte_parameters, tvb, offset, bc, ENC_NA); \ + } \ + offset += bc; \ + } \ + endofcommand: + +/* + * Macros for use in routines called by them. + */ +#define CHECK_BYTE_COUNT_SUBR(len) \ + if (*bcp < len) { \ + *trunc = TRUE; \ + return offset; \ + } + +#define CHECK_STRING_SUBR(fn) \ + if (fn == NULL) { \ + *trunc = TRUE; \ + return offset; \ + } + +#define COUNT_BYTES_SUBR(len) \ + offset += len; \ + *bcp -= len; + +/* + * Macros for use when dissecting transaction parameters and data + */ +#define CHECK_BYTE_COUNT_TRANS(len) \ + if (bc < len) return offset; + +#define CHECK_STRING_TRANS(fn) \ + if (fn == NULL) return offset; + +#define COUNT_BYTES_TRANS(len) \ + offset += len; \ + bc -= len; + +/* + * Macros for use in subrroutines dissecting transaction parameters or data + */ +#define CHECK_BYTE_COUNT_TRANS_SUBR(len) \ + if (*bcp < len) return offset; + +#define CHECK_STRING_TRANS_SUBR(fn) \ + if (fn == NULL) return offset; + +#define COUNT_BYTES_TRANS_SUBR(len) \ + offset += len; \ + *bcp -= len; + +gboolean sid_display_hex = FALSE; +gboolean sid_name_snooping = FALSE; + +/* ExportObject preferences variable */ +gboolean eosmb_take_name_as_fid = FALSE ; +/* Utility to get an str reprensenting ipv4 or ipv6 address */ +const gchar *tree_ip_str(packet_info *pinfo, guint16 cmd) { + const gchar *buf; + + if ( cmd == SMB_COM_READ_ANDX || + cmd == SMB_COM_READ || + cmd == SMB2_COM_READ) { + buf = address_to_str(wmem_packet_scope(), &pinfo->src); + } else { + buf = address_to_str(wmem_packet_scope(), &pinfo->dst); + } + + return buf; +} + + +/* ExportObject feed function*/ +static void +feed_eo_smb(guint16 cmd, guint16 fid, tvbuff_t * tvb, packet_info *pinfo, guint16 dataoffset, guint32 datalen, guint32 chunk_len, + guint64 file_offset, smb_info_t *si) { + + smb_eo_t *eo_info; /* eo_info variable to pass info. to + export object and aux */ + smb_tid_info_t *tid_info = NULL; + smb_fid_info_t *fid_info = NULL; + smb_fid_info_t *suspect_fid_info = NULL; + tvbuff_t *data_tvb; + GSList *GSL_iterator; + + /* Create a new tvb to point to the payload data */ + data_tvb = tvb_new_subset_length(tvb, dataoffset, datalen); + /* Create the eo_info to pass to the listener */ + eo_info = wmem_new(wmem_packet_scope(), smb_eo_t); + + /* Try to get fid_info and tid_info */ + if (fid_info == NULL) { + GSL_iterator = si->ct->GSL_fid_info; + while (GSL_iterator) { + suspect_fid_info = (smb_fid_info_t *)GSL_iterator->data; + if (suspect_fid_info->opened_in > pinfo->num) break; + if ((suspect_fid_info->tid == si->tid) && (suspect_fid_info->fid == fid)) + fid_info = suspect_fid_info; + GSL_iterator = g_slist_next(GSL_iterator); + } + } + + + tid_info = (smb_tid_info_t *)wmem_tree_lookup32(si->ct->tid_tree, si->tid); + + /* Construct the eo_info structure */ + eo_info->smbversion = 1; + if (tid_info) { + if (tid_info->filename) { + eo_info->hostname = tid_info->filename; + } else { + eo_info->hostname = wmem_strdup_printf(wmem_packet_scope(), "\\\\%s\\TREEID_UNKNOWN", tree_ip_str(pinfo, cmd)); + } + } + else eo_info->hostname = wmem_strdup_printf(wmem_packet_scope(), "\\\\%s\\TREEID_%i", tree_ip_str(pinfo, cmd), si->tid); + if (fid_info) { + eo_info->filename = NULL; + if (fid_info->fsi) + if (fid_info->fsi->filename) + eo_info->filename = (gchar *) fid_info->fsi->filename; + if (!eo_info->filename) eo_info->filename = wmem_strdup_printf(wmem_packet_scope(), "\\FILEID_%i", fid); + eo_info->fid_type = fid_info->type; + eo_info->end_of_file = fid_info->end_of_file; + } else { + eo_info->fid_type = SMB_FID_TYPE_UNKNOWN; + eo_info->filename = wmem_strdup_printf(wmem_packet_scope(), "\\FILEID_%i", fid); + eo_info->end_of_file = 0; + } + if (eosmb_take_name_as_fid) { + eo_info->fid = g_str_hash(eo_info->filename); + } else { + eo_info->fid = fid; + } + eo_info->tid = si->tid; + eo_info->uid = si->uid; + eo_info->payload_len = datalen; + eo_info->payload_data = tvb_get_ptr(data_tvb, 0, datalen); + eo_info->smb_file_offset = file_offset; + eo_info->smb_chunk_len = chunk_len; + eo_info->cmd = cmd; + /* Queue data to the listener */ + + tap_queue_packet(smb_eo_tap, pinfo, eo_info); +} /* feed_eo_smb */ + +/* Compare function to maintain the GSL_fid_info ordered + Order criteria: packet where the fid was opened */ +static gint +fid_cmp(smb_fid_info_t *fida, smb_fid_info_t *fidb) +{ + return (fida->opened_in - fidb->opened_in); +} + +/* XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX + These are needed by the reassembly of SMB Transaction payload and DCERPC over SMB + XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX */ +static gboolean smb_trans_reassembly = TRUE; +gboolean smb_dcerpc_reassembly = TRUE; + +static reassembly_table smb_trans_reassembly_table; + +static fragment_head * +smb_trans_defragment(proto_tree *tree _U_, packet_info *pinfo, tvbuff_t *tvb, + int offset, guint count, guint pos, guint totlen, smb_info_t *si) +{ + fragment_head *fd_head = NULL; + int more_frags; + + /* Don't pass the reassembly code data that doesn't exist */ + /* Fail if some or all of the fragment is located beyond the total length */ + if ( !tvb_bytes_exist(tvb, offset, count) || (pos > totlen) || (count > totlen) || ((pos + count) > totlen)) { + THROW(ReportedBoundsError); + } + + more_frags = totlen > (pos + count); + + DISSECTOR_ASSERT(si); + + if (si->sip == NULL) { + /* + * We don't have the frame number of the request. + */ + return NULL; + } + + if (!pinfo->fd->visited) { + fd_head = fragment_add(&smb_trans_reassembly_table, tvb, offset, + pinfo, si->sip->frame_req, NULL, + pos, count, more_frags); + } else { + fd_head = fragment_get(&smb_trans_reassembly_table, + pinfo, si->sip->frame_req, NULL); + } + + if (!fd_head || !(fd_head->flags & FD_DEFRAGMENTED)) { + /* This is continued - mark it as such, so we recognize + continuation responses. + */ + si->sip->flags |= SMB_SIF_IS_CONTINUED; + } else { + /* We've finished reassembling, so there are no more + continuation responses. + */ + si->sip->flags &= ~SMB_SIF_IS_CONTINUED; + } + + /* we only show the defragmented packet for the first fragment, + or else we might end up with dissecting one HUGE transaction PDU + a LOT of times. (first fragment is the only one containing the setup + bytes) + I have seen ONE Transaction PDU that is ~60kb, spanning many Transaction + SMBs. Takes a LOT of time dissecting and is not fun. + */ + if ( (pos == 0) && fd_head && (fd_head->flags & FD_DEFRAGMENTED)) { + return fd_head; + } else { + return NULL; + } +} + + + + + +/* XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX + These variables and functions are used to match + responses with calls + XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX */ +/* + * The information we need to save about a request in order to show the + * frame number of the request in the dissection of the reply. + */ +typedef struct { + guint32 frame; + guint32 pid_mid; +} smb_saved_info_key_t; + +/* unmatched smb_saved_info structures. + For unmatched smb_saved_info structures we store the smb_saved_info + structure using the MID and the PID as the key. + + Oh, yes, the key is really a pointer, but we use it as if it was an integer. + Ugly, yes. Not portable to DEC-20 Yes. But it saves a few bytes. + The key is the PID in the upper 16 bits and the MID in the lower 16 bits. +*/ +static gint +smb_saved_info_equal_unmatched(gconstpointer k1, gconstpointer k2) +{ + register guint32 key1 = GPOINTER_TO_UINT(k1); + register guint32 key2 = GPOINTER_TO_UINT(k2); + return key1 == key2; +} +static guint +smb_saved_info_hash_unmatched(gconstpointer k) +{ + register guint32 key = GPOINTER_TO_UINT(k); + return key; +} + +/* matched smb_saved_info structures. + For matched smb_saved_info structures we store the smb_saved_info + structure twice in the table using the frame number, and a combination + of the MID and the PID, as the key. + The frame number is guaranteed to be unique but if ever someone makes + some change that will renumber the frames in a capture we are in BIG trouble. + This is not likely though since that would break (among other things) all the + reassembly routines as well. + + We also need the MID as there may be more than one SMB request or reply + in a single frame, and we also need the PID as there may be more than + one outstanding request with the same MID and different PIDs. +*/ +static gint +smb_saved_info_equal_matched(gconstpointer k1, gconstpointer k2) +{ + const smb_saved_info_key_t *key1 = (const smb_saved_info_key_t *)k1; + const smb_saved_info_key_t *key2 = (const smb_saved_info_key_t *)k2; + return (key1->frame == key2->frame) && (key1->pid_mid == key2->pid_mid); +} +static guint +smb_saved_info_hash_matched(gconstpointer k) +{ + const smb_saved_info_key_t *key = (const smb_saved_info_key_t *)k; + return key->frame + key->pid_mid; +} + +static GSList *conv_tables = NULL; + +static gint +smb_find_unicode_null_offset(tvbuff_t *tvb, gint offset, const gint maxlength, const guint16 needle, const guint encoding) +{ + guint captured_length = tvb_captured_length(tvb); + if (G_LIKELY((guint) offset > captured_length)) { + return -1; + } + + guint limit = captured_length - offset; + + /* Only search to end of tvbuff, w/o throwing exception. */ + if (maxlength >= 0 && limit > (guint) maxlength) { + /* Maximum length doesn't go past end of tvbuff; search + to that value. */ + limit = (guint) maxlength; + } + + limit = limit & ~1; + + while(limit){ + if (needle == tvb_get_guint16(tvb, offset, encoding)){ + return offset; + } + offset += 2; + limit -= 2; + } + return -1; +} + +/* XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX + End of request/response matching functions + XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX */ + +/* Turn a little-endian Unicode '\0'-terminated string into a string we + can display. + If exactlen==TRUE then us_lenp contains the exact len of the string in + bytes. It might not be null terminated ! + bc specifies the number of bytes in the byte parameters; Windows 2000, + at least, appears, in some cases, to put only 1 byte of 0 at the end + of a Unicode string if the byte count +*/ +static gchar * +unicode_to_str(tvbuff_t *tvb, int offset, int *us_lenp, gboolean exactlen, + guint16 bc) +{ + int len; + if (exactlen) { + return tvb_get_string_enc(wmem_packet_scope(), tvb, offset, *us_lenp, ENC_UTF_16|ENC_LITTLE_ENDIAN); + } else { + /* Handle the odd cases where Windows 2000 has a Unicode + * string followed by a single NUL byte when the string + * takes up the entire byte count. + */ + len = smb_find_unicode_null_offset(tvb, offset, bc, 0, ENC_LITTLE_ENDIAN); + if (len == -1) { + if (bc % 2 == 1 && tvb_get_guint8(tvb, offset + bc - 1) == 0) { + *us_lenp = bc; + return tvb_get_string_enc(wmem_packet_scope(), tvb, offset, bc - 1, ENC_UTF_16|ENC_LITTLE_ENDIAN); + } + } + return tvb_get_stringz_enc(wmem_packet_scope(), tvb, offset, us_lenp, ENC_UTF_16|ENC_LITTLE_ENDIAN); + } +} + +/* nopad == TRUE : Do not add any padding before this string + * exactlen == TRUE : len contains the exact len of the string in bytes. + * bc: pointer to variable with amount of data left in the byte parameters + * region + */ +static const gchar * +get_unicode_or_ascii_string(tvbuff_t *tvb, int *offsetp, + gboolean useunicode, int *len, gboolean nopad, gboolean exactlen, + guint16 *bcp) +{ + const gchar *string; + int string_len = 0; + int copylen; + + if (*bcp == 0) { + /* Not enough data in buffer */ + return NULL; + } + + if (useunicode) { + if ((!nopad) && (*offsetp % 2)) { + (*offsetp)++; /* Looks like a pad byte there sometimes */ + (*bcp)--; + + if (*bcp == 0) { + /* Not enough data in buffer */ + return NULL; + } + } + + if(exactlen){ + string_len = *len; + if (string_len < 0) { + /* This probably means it's a very large unsigned number; just set + it to the largest signed number, so that we throw the appropriate + exception. */ + string_len = INT_MAX; + } else if (string_len > *bcp){ + string_len = *bcp; + } + } + + string = unicode_to_str(tvb, *offsetp, &string_len, exactlen, *bcp); + } else { + /* XXX: Use the local OEM (extended ASCII DOS) code page. + * On US English machines that means ENC_CP437, but it + * could be CP850 (which contains the characters of + * ISO-8859-1, arranged differently), CP866, etc. + * Using ENC_ASCII is safest. + * + * There could be a preference for local code page. + * (The same should apply in packet-smb-browser.c too) + */ + if(exactlen){ + copylen = *len; + + if (copylen < 0) { + /* This probably means it's a very large unsigned number; just set + it to the largest signed number, so that we throw the appropriate + exception. */ + copylen = INT_MAX; + } + + return tvb_get_string_enc(wmem_packet_scope(), tvb, *offsetp, copylen, ENC_ASCII); + } else { + return tvb_get_stringz_enc(wmem_packet_scope(), tvb, *offsetp, len, ENC_ASCII); + } + } + + *len = string_len; + return string; +} + +typedef struct _smb_uid_t { + char *domain; + char *account; + int logged_in; + int logged_out; +} smb_uid_t; + +static void +smb_file_specific_rights(tvbuff_t *tvb, gint offset, proto_tree *tree, guint32 mask) +{ + static int * const mask_flags[] = { + &hf_smb_file_access_mask_write_attribute, + &hf_smb_file_access_mask_read_attribute, + &hf_smb_file_access_mask_execute, + &hf_smb_file_access_mask_write_ea, + &hf_smb_file_access_mask_read_ea, + &hf_smb_file_access_mask_append_data, + &hf_smb_file_access_mask_write_data, + &hf_smb_file_access_mask_read_data, + NULL + }; + + mask &= 0x0000ffff; + if (mask == 0x000001ff) { + proto_tree_add_uint(tree, hf_smb_file_access_mask_full_control, tvb, offset, 4, mask); + } + + proto_tree_add_bitmask_list_value(tree, tvb, offset, 4, mask_flags, mask); +} +static struct access_mask_info smb_file_access_mask_info = { + "FILE", /* Name of specific rights */ + smb_file_specific_rights, /* Dissection function */ + NULL, /* Generic mapping table */ + NULL /* Standard mapping table */ +}; + + +static void +smb_dir_specific_rights(tvbuff_t *tvb, gint offset, proto_tree *tree, guint32 mask) +{ + static int * const mask_flags[] = { + &hf_smb_dir_access_mask_write_attribute, + &hf_smb_dir_access_mask_read_attribute, + &hf_smb_dir_access_mask_delete_child, + &hf_smb_dir_access_mask_traverse, + &hf_smb_dir_access_mask_write_ea, + &hf_smb_dir_access_mask_read_ea, + &hf_smb_dir_access_mask_add_subdir, + &hf_smb_dir_access_mask_add_file, + &hf_smb_dir_access_mask_list, + NULL + }; + + mask &= 0x0000ffff; + if (mask == 0x000001ff) { + proto_tree_add_uint(tree, hf_smb_dir_access_mask_full_control, tvb, offset, 4, mask); + } + + proto_tree_add_bitmask_list_value(tree, tvb, offset, 4, mask_flags, mask); +} +static struct access_mask_info smb_dir_access_mask_info = { + "DIR", /* Name of specific rights */ + smb_dir_specific_rights, /* Dissection function */ + NULL, /* Generic mapping table */ + NULL /* Standard mapping table */ +}; + + + +static const value_string buffer_format_vals[] = { + {1, "Data Block"}, + {2, "Dialect"}, + {3, "Pathname"}, + {4, "ASCII"}, + {5, "Variable Block"}, + {0, NULL} +}; + +#define POSIX_ACE_TYPE_USER_OBJ 0x01 +#define POSIX_ACE_TYPE_USER 0x02 +#define POSIX_ACE_TYPE_GROUP_OBJ 0x04 +#define POSIX_ACE_TYPE_GROUP 0x08 +#define POSIX_ACE_TYPE_MASK 0x10 +#define POSIX_ACE_TYPE_OTHER 0x20 +static const value_string ace_type_vals[] = { + {POSIX_ACE_TYPE_USER_OBJ, "User Obj"}, + {POSIX_ACE_TYPE_USER, "User"}, + {POSIX_ACE_TYPE_GROUP_OBJ, "Group Obj"}, + {POSIX_ACE_TYPE_GROUP, "Group"}, + {POSIX_ACE_TYPE_MASK, "Mask"}, + {POSIX_ACE_TYPE_OTHER, "Other"}, + {0, NULL} +}; + +/* + * UTIME - this is *almost* like a UNIX time stamp, except that it's + * in seconds since January 1, 1970, 00:00:00 *local* time, not since + * January 1, 1970, 00:00:00 GMT. + * + * This means we have to do some extra work to convert it. This code is + * based on the Samba code: + * + * Unix SMB/Netbios implementation. + * Version 1.9. + * time handling functions + * Copyright (C) Andrew Tridgell 1992-1998 + */ + +/* + * Yield the difference between *A and *B, in seconds, ignoring leap + * seconds. + */ +#define TM_YEAR_BASE 1900 + +static int +tm_diff(struct tm *a, struct tm *b) +{ + int ay = a->tm_year + (TM_YEAR_BASE - 1); + int by = b->tm_year + (TM_YEAR_BASE - 1); + int intervening_leap_days = + (ay/4 - by/4) - (ay/100 - by/100) + (ay/400 - by/400); + int years = ay - by; + int days = + 365*years + intervening_leap_days + (a->tm_yday - b->tm_yday); + int hours = 24*days + (a->tm_hour - b->tm_hour); + int minutes = 60*hours + (a->tm_min - b->tm_min); + int seconds = 60*minutes + (a->tm_sec - b->tm_sec); + + return seconds; +} + +/* + * Return the UTC offset in seconds west of UTC, or 0 if it cannot be + * determined. + */ +static int +TimeZone(time_t t) +{ + struct tm *tm = gmtime(&t); + struct tm tm_utc; + + if (tm == NULL) + return 0; + tm_utc = *tm; + tm = localtime(&t); + if (tm == NULL) + return 0; + return tm_diff(&tm_utc, tm); +} + +/* + * Return the same value as TimeZone, but it should be more efficient. + * + * We keep a table of DST offsets to prevent calling localtime() on each + * call of this function. This saves a LOT of time on many unixes. + * + * Updated by Paul Eggert <eggert@twinsun.com> + */ +#ifndef CHAR_BIT +#define CHAR_BIT 8 +#endif + +#ifndef TIME_T_MIN +#define TIME_T_MIN ((time_t) ((time_t)0 < (time_t) -1 ? (time_t) 0 \ + : ~ (time_t) 0 << (sizeof (time_t) * CHAR_BIT - 1))) +#endif +#ifndef TIME_T_MAX +#define TIME_T_MAX ((time_t) (~ (time_t) 0 - TIME_T_MIN)) +#endif + +static int +TimeZoneFaster(time_t t) +{ + static struct dst_table {time_t start, end; int zone;} *tdt; + static struct dst_table *dst_table = NULL; + static int table_size = 0; + int i; + int zone = 0; + + if (t == 0) + t = time(NULL); + + /* Tunis has a 8 day DST region, we need to be careful ... */ +#define MAX_DST_WIDTH (365*24*60*60) +#define MAX_DST_SKIP (7*24*60*60) + + for (i = 0; i < table_size; i++) { + if ((t >= dst_table[i].start) && (t <= dst_table[i].end)) + break; + } + + if (i < table_size) { + zone = dst_table[i].zone; + } else { + time_t low, high; + + zone = TimeZone(t); + if (dst_table == NULL) + tdt = (struct dst_table *)g_malloc(sizeof(dst_table[0])*(i+1)); + else + tdt = (struct dst_table *)g_realloc(dst_table, sizeof(dst_table[0])*(i+1)); + if (tdt == NULL) { + g_free(dst_table); + table_size = 0; + } else { + dst_table = tdt; + table_size++; + + dst_table[i].zone = zone; + dst_table[i].start = dst_table[i].end = t; + + /* no entry will cover more than 6 months */ + low = t - MAX_DST_WIDTH/2; + /* XXX - what if t < MAX_DST_WIDTH/2? */ + + high = t + MAX_DST_WIDTH/2; + /* XXX - what if this overflows? */ + + /* + * Widen the new entry using two bisection searches. + */ + while (low+60*60 < dst_table[i].start) { + if (dst_table[i].start - low > MAX_DST_SKIP*2) + t = dst_table[i].start - MAX_DST_SKIP; + else + t = low + (dst_table[i].start-low)/2; + if (TimeZone(t) == zone) + dst_table[i].start = t; + else + low = t; + } + + while (high-60*60 > dst_table[i].end) { + if (high - dst_table[i].end > MAX_DST_SKIP*2) + t = dst_table[i].end + MAX_DST_SKIP; + else + t = high - (high-dst_table[i].end)/2; + if (TimeZone(t) == zone) + dst_table[i].end = t; + else + high = t; + } + } + } + return zone; +} + +/* + * Return the UTC offset in seconds west of UTC, adjusted for extra time + * offset, for a local time value. If ut = lt + LocTimeDiff(lt), then + * lt = ut - TimeDiff(ut), but the converse does not necessarily hold near + * daylight savings transitions because some local times are ambiguous. + * LocTimeDiff(t) equals TimeDiff(t) except near daylight savings transitions. + */ +static int +LocTimeDiff(time_t lt) +{ + int d = TimeZoneFaster(lt); + time_t t = lt + d; + + /* if overflow occurred, ignore all the adjustments so far */ + if (((t < lt) ^ (d < 0))) + t = lt; + + /* + * Now t should be close enough to the true UTC to yield the + * right answer. + */ + return TimeZoneFaster(t); +} + +static int +dissect_smb_UTIME(tvbuff_t *tvb, proto_tree *tree, int offset, int hf_date) +{ + guint32 timeval; + nstime_t ts; + + ts.secs = timeval = tvb_get_letohl(tvb, offset); + ts.nsecs = 0; + if (timeval == 0xffffffff) { + proto_tree_add_time_format_value(tree, hf_date, tvb, offset, 4, &ts, + "No time specified (0xffffffff)"); + offset += 4; + return offset; + } + + /* + * We add the local time offset. + */ + ts.secs = timeval + LocTimeDiff(timeval); + + proto_tree_add_time(tree, hf_date, tvb, offset, 4, &ts); + offset += 4; + + return offset; +} + +static int +dissect_smb_datetime(tvbuff_t *tvb, proto_tree *parent_tree, int offset, + int hf_date, int hf_dos_date, int hf_dos_time, gboolean time_first) +{ + guint16 dos_time, dos_date; + proto_item *item = NULL; + proto_tree *tree = NULL; + struct tm tm; + time_t t; + nstime_t tv; + + static const int mday_noleap[12] = { + 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 + }; + static const int mday_leap[12] = { + 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 + }; + +#define ISLEAP(y) ((((y) % 4) == 0) && ((((y) % 100) != 0) || (((y) % 400) == 0))) + + if (time_first) { + dos_time = tvb_get_letohs(tvb, offset); + dos_date = tvb_get_letohs(tvb, offset+2); + } else { + dos_date = tvb_get_letohs(tvb, offset); + dos_time = tvb_get_letohs(tvb, offset+2); + } + + if (((dos_date == 0xffff) && (dos_time == 0xffff)) || + ((dos_date == 0) && (dos_time == 0))) { + /* + * No date/time specified. + */ + if (parent_tree) { + tv.secs = 0; + tv.nsecs = 0; + proto_tree_add_time_format_value(parent_tree, hf_date, tvb, offset, 4, + &tv, "No time specified (0x%08x)", + ((dos_date << 16) | dos_time)); + } + offset += 4; + return offset; + } + + tm.tm_sec = (dos_time & 0x1f) * 2; + tm.tm_min = (dos_time>>5) & 0x3f; + tm.tm_hour = (dos_time>>11) & 0x1f; + tm.tm_mday = dos_date & 0x1f; + tm.tm_mon = ((dos_date>>5) & 0x0f) - 1; + tm.tm_year = ((dos_date>>9) & 0x7f) + 1980 - 1900; + tm.tm_isdst = -1; + + /* + * Do some sanity checks before calling "mktime()"; + * "mktime()" doesn't do them, it "normalizes" out-of-range + * values. + */ + if ((tm.tm_sec > 59) || (tm.tm_min > 59) || (tm.tm_hour > 23) || + (tm.tm_mon < 0) || (tm.tm_mon > 11) || + (ISLEAP(tm.tm_year + 1900) ? + (tm.tm_mday > mday_leap[tm.tm_mon]) : + (tm.tm_mday > mday_noleap[tm.tm_mon])) || + ((t = mktime(&tm)) == -1)) { + /* + * Invalid date/time. + */ + if (parent_tree) { + tv.secs = 0; + tv.nsecs = 0; + item = proto_tree_add_time_format_value(parent_tree, hf_date, tvb, offset, 4, + &tv, "Invalid time (0x%08x)", ((dos_date << 16) | dos_time)); + tree = proto_item_add_subtree(item, ett_smb_time_date); + if (time_first) { + proto_tree_add_uint_format(tree, hf_dos_time, tvb, offset, 2, dos_time, "DOS Time: %02d:%02d:%02d (0x%04x)", tm.tm_hour, tm.tm_min, tm.tm_sec, dos_time); + proto_tree_add_uint_format(tree, hf_dos_date, tvb, offset+2, 2, dos_date, "DOS Date: %04d-%02d-%02d (0x%04x)", tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, dos_date); + } else { + proto_tree_add_uint_format(tree, hf_dos_date, tvb, offset, 2, dos_date, "DOS Date: %04d-%02d-%02d (0x%04x)", tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, dos_date); + proto_tree_add_uint_format(tree, hf_dos_time, tvb, offset+2, 2, dos_time, "DOS Time: %02d:%02d:%02d (0x%04x)", tm.tm_hour, tm.tm_min, tm.tm_sec, dos_time); + } + } + offset += 4; + return offset; + } + + tv.secs = t; + tv.nsecs = 0; + + if (parent_tree) { + item = proto_tree_add_time(parent_tree, hf_date, tvb, offset, 4, &tv); + tree = proto_item_add_subtree(item, ett_smb_time_date); + if (time_first) { + proto_tree_add_uint_format(tree, hf_dos_time, tvb, offset, 2, dos_time, "DOS Time: %02d:%02d:%02d (0x%04x)", tm.tm_hour, tm.tm_min, tm.tm_sec, dos_time); + proto_tree_add_uint_format(tree, hf_dos_date, tvb, offset+2, 2, dos_date, "DOS Date: %04d-%02d-%02d (0x%04x)", tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, dos_date); + } else { + proto_tree_add_uint_format(tree, hf_dos_date, tvb, offset, 2, dos_date, "DOS Date: %04d-%02d-%02d (0x%04x)", tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, dos_date); + proto_tree_add_uint_format(tree, hf_dos_time, tvb, offset+2, 2, dos_time, "DOS Time: %02d:%02d:%02d (0x%04x)", tm.tm_hour, tm.tm_min, tm.tm_sec, dos_time); + } + } + + offset += 4; + + return offset; +} + +static const true_false_string tfs_disposition_delete_on_close = { + "DELETE this file when closed", + "Normal access, do not delete on close" +}; + +static const true_false_string tfs_pipe_info_flag = { + "SET NAMED PIPE mode", + "Clear NAMED PIPE mode" +}; + + +static const value_string da_access_vals[] = { + { 0, "Open for reading"}, + { 1, "Open for writing"}, + { 2, "Open for reading and writing"}, + { 3, "Open for execute"}, + {0, NULL} +}; +static const value_string da_sharing_vals[] = { + { 0, "Compatibility mode"}, + { 1, "Deny read/write/execute (exclusive)"}, + { 2, "Deny write"}, + { 3, "Deny read/execute"}, + { 4, "Deny none"}, + {0, NULL} +}; +static const value_string da_locality_vals[] = { + { 0, "Locality of reference unknown"}, + { 1, "Mainly sequential access"}, + { 2, "Mainly random access"}, + { 3, "Random access with some locality"}, + {0, NULL} +}; +static const true_false_string tfs_da_caching = { + "Do not cache this file", + "Caching permitted on this file" +}; +static const true_false_string tfs_da_writetru = { + "Write through enabled", + "Write through disabled" +}; +static int +dissect_access(tvbuff_t *tvb, proto_tree *parent_tree, int offset, int hf_access) +{ + static int * const flags[] = { + &hf_smb_access_writetru, + &hf_smb_access_caching, + &hf_smb_access_locality, + &hf_smb_access_sharing, + &hf_smb_access_mode, + NULL + }; + + proto_tree_add_bitmask(parent_tree, tvb, offset, hf_access, ett_smb_desiredaccess, flags, ENC_LITTLE_ENDIAN); + offset += 2; + + return offset; +} + +#define SMB_FILE_ATTRIBUTE_READ_ONLY 0x00000001 +#define SMB_FILE_ATTRIBUTE_HIDDEN 0x00000002 +#define SMB_FILE_ATTRIBUTE_SYSTEM 0x00000004 +#define SMB_FILE_ATTRIBUTE_VOLUME 0x00000008 +#define SMB_FILE_ATTRIBUTE_DIRECTORY 0x00000010 +#define SMB_FILE_ATTRIBUTE_ARCHIVE 0x00000020 +#define SMB_FILE_ATTRIBUTE_DEVICE 0x00000040 +#define SMB_FILE_ATTRIBUTE_NORMAL 0x00000080 +#define SMB_FILE_ATTRIBUTE_TEMPORARY 0x00000100 +#define SMB_FILE_ATTRIBUTE_SPARSE 0x00000200 +#define SMB_FILE_ATTRIBUTE_REPARSE 0x00000400 +#define SMB_FILE_ATTRIBUTE_COMPRESSED 0x00000800 +#define SMB_FILE_ATTRIBUTE_OFFLINE 0x00001000 +#define SMB_FILE_ATTRIBUTE_NOT_CONTENT_INDEXED 0x00002000 +#define SMB_FILE_ATTRIBUTE_ENCRYPTED 0x00004000 + +static const true_false_string tfs_file_attribute_read_only = { + "READ ONLY", + "NOT read only", +}; +static const true_false_string tfs_file_attribute_hidden = { + "HIDDEN", + "NOT hidden" +}; +static const true_false_string tfs_file_attribute_system = { + "SYSTEM file/dir", + "NOT a system file/dir" +}; +static const true_false_string tfs_file_attribute_volume = { + "VOLUME ID", + "NOT a volume ID" +}; +static const true_false_string tfs_file_attribute_directory = { + "DIRECTORY", + "NOT a directory" +}; +static const true_false_string tfs_file_attribute_archive = { + "Modified since last ARCHIVE", + "Has NOT been modified since last archive" +}; +static const true_false_string tfs_file_attribute_device = { + "A DEVICE", + "NOT a device" +}; +static const true_false_string tfs_file_attribute_normal = { + "An ordinary file/dir", + "Has some attribute set" +}; +static const true_false_string tfs_file_attribute_temporary = { + "A TEMPORARY file", + "NOT a temporary file" +}; +static const true_false_string tfs_file_attribute_sparse = { + "A SPARSE file", + "NOT a sparse file" +}; +static const true_false_string tfs_file_attribute_reparse = { + "Has an associated REPARSE POINT", + "Does NOT have an associated reparse point" +}; +static const true_false_string tfs_file_attribute_compressed = { + "COMPRESSED", + "Uncompressed" +}; +static const true_false_string tfs_file_attribute_offline = { + "OFFLINE", + "Online" +}; +static const true_false_string tfs_file_attribute_not_content_indexed = { + "CONTENT INDEXED", + "NOT content indexed" +}; +static const true_false_string tfs_file_attribute_encrypted = { + "This is an ENCRYPTED file", + "This is NOT an encrypted file" +}; + +/* + * Dissects an SMB_FILE_ATTRIBUTES, to use the term given to it by + * section 2.2.1.2.4 of [MS-CIFS], in cases where it's just file attributes, + * not search attributes. + */ +static int +dissect_file_attributes(tvbuff_t *tvb, proto_tree *parent_tree, int offset) +{ + static int * const flags[] = { + &hf_smb_file_attr_archive_16bit, + &hf_smb_file_attr_directory_16bit, + &hf_smb_file_attr_volume_16bit, + &hf_smb_file_attr_system_16bit, + &hf_smb_file_attr_hidden_16bit, + &hf_smb_file_attr_read_only_16bit, + NULL + }; + + proto_tree_add_bitmask(parent_tree, tvb, offset, hf_smb_file_attr_16bit, ett_smb_file_attributes, flags, ENC_LITTLE_ENDIAN); + offset += 2; + + return offset; +} + +/* + * 3.11 in the SNIA CIFS spec + * SMB_EXT_FILE_ATTR, section 2.2.1.2.3 in the [MS-CIFS] spec + */ +static int +dissect_file_ext_attr_bits(tvbuff_t *tvb, proto_tree *parent_tree, int offset, + int len, guint32 mask) +{ + proto_item *item; + /* + * XXX - Network Monitor disagrees on some of the + * bits, e.g. the bits above temporary are "atomic write" + * and "transaction write", and it says nothing about the + * bits above that. + * + * Does the Win32 API documentation, or the NT Native API book, + * suggest anything? + */ + static int * const mask_fields[] = { + &hf_smb_file_eattr_read_only, + &hf_smb_file_eattr_hidden, + &hf_smb_file_eattr_system, + &hf_smb_file_eattr_volume, + &hf_smb_file_eattr_directory, + &hf_smb_file_eattr_archive, + &hf_smb_file_eattr_device, + &hf_smb_file_eattr_normal, + &hf_smb_file_eattr_temporary, + &hf_smb_file_eattr_sparse, + &hf_smb_file_eattr_reparse, + &hf_smb_file_eattr_compressed, + &hf_smb_file_eattr_offline, + &hf_smb_file_eattr_not_content_indexed, + &hf_smb_file_eattr_encrypted, + NULL + }; + + item = proto_tree_add_bitmask_value_with_flags(parent_tree, tvb, offset, + hf_smb_file_eattr, ett_smb_file_attributes, mask_fields, mask, BMT_NO_APPEND); + if (len == 0) + proto_item_set_generated(item); + + offset += len; + + return offset; +} + +/* 3.11 */ +static int +dissect_file_ext_attr(tvbuff_t *tvb, proto_tree *parent_tree, int offset) +{ + guint32 mask; + + mask = tvb_get_letohl(tvb, offset); + + offset = dissect_file_ext_attr_bits(tvb, parent_tree, offset, 4, mask); + + return offset; +} + +static int +dissect_dir_info_file_attributes(tvbuff_t *tvb, proto_tree *parent_tree, int offset) +{ + static int * const flags[] = { + &hf_smb_file_attr_read_only_8bit, + &hf_smb_file_attr_hidden_8bit, + &hf_smb_file_attr_system_8bit, + &hf_smb_file_attr_volume_8bit, + &hf_smb_file_attr_directory_8bit, + &hf_smb_file_attr_archive_8bit, + NULL + }; + + proto_tree_add_bitmask(parent_tree, tvb, offset, hf_smb_file_attr_8bit, ett_smb_file_attributes, flags, ENC_NA); + offset += 1; + + return offset; +} + +static const true_false_string tfs_search_attribute_read_only = { + "Include READ ONLY files in search results", + "Do NOT include read only files in search results", +}; +static const true_false_string tfs_search_attribute_hidden = { + "Include HIDDEN files in search results", + "Do NOT include hidden files in search results" +}; +static const true_false_string tfs_search_attribute_system = { + "Include SYSTEM files in search results", + "Do NOT include system files in search results" +}; +static const true_false_string tfs_search_attribute_volume = { + "Include VOLUME IDs in search results", + "Do NOT include volume IDs in search results" +}; +static const true_false_string tfs_search_attribute_directory = { + "Include DIRECTORIES in search results", + "Do NOT include directories in search results" +}; +static const true_false_string tfs_search_attribute_archive = { + "Include ARCHIVE files in search results", + "Do NOT include archive files in search results" +}; + +/* + * Dissects an SMB_FILE_ATTRIBUTES, to use the term given to it by + * section 2.2.1.2.4 of [MS-CIFS], in cases where it's search attributes. + */ +static int +dissect_search_attributes(tvbuff_t *tvb, proto_tree *parent_tree, int offset) +{ + static int * const flags[] = { + &hf_smb_search_attribute_read_only, + &hf_smb_search_attribute_hidden, + &hf_smb_search_attribute_system, + &hf_smb_search_attribute_volume, + &hf_smb_search_attribute_directory, + &hf_smb_search_attribute_archive, + NULL + }; + + proto_tree_add_bitmask(parent_tree, tvb, offset, hf_smb_search_attribute, ett_smb_search, flags, ENC_LITTLE_ENDIAN); + offset += 2; + + return offset; +} + +#if 0 +/* + * XXX - this isn't used. + * Is this used for anything? NT Create AndX doesn't use it. + * Is there some 16-bit attribute field with more bits than Read Only, + * Hidden, System, Volume ID, Directory, and Archive? + */ +static int +dissect_extended_file_attributes(tvbuff_t *tvb, packet_info *pinfo, proto_tree *parent_tree, int offset) +{ + static int * const flags[] = { + &hf_smb_file_attr_read_only_16bit, + &hf_smb_file_attr_hidden_16bit, + &hf_smb_file_attr_system_16bit, + &hf_smb_file_attr_volume_16bit, + &hf_smb_file_attr_directory_16bit, + &hf_smb_file_attr_archive_16bit, + &hf_smb_file_attr_device, + &hf_smb_file_attr_normal, + &hf_smb_file_attr_temporary, + &hf_smb_file_attr_sparse, + &hf_smb_file_attr_reparse, + &hf_smb_file_attr_compressed, + &hf_smb_file_attr_offline, + &hf_smb_file_attr_not_content_indexed, + &hf_smb_file_attr_encrypted, + NULL + }; + + proto_tree_add_bitmask(parent_tree, tvb, offset, hf_smb_file_eattr, ett_smb_file_attributes, flags, ENC_LITTLE_ENDIAN); + offset += 2; + + return offset; +} +#endif + + +#define SERVER_CAP_RAW_MODE 0x00000001 +#define SERVER_CAP_MPX_MODE 0x00000002 +#define SERVER_CAP_UNICODE 0x00000004 +#define SERVER_CAP_LARGE_FILES 0x00000008 +#define SERVER_CAP_NT_SMBS 0x00000010 +#define SERVER_CAP_RPC_REMOTE_APIS 0x00000020 +#define SERVER_CAP_STATUS32 0x00000040 +#define SERVER_CAP_LEVEL_II_OPLOCKS 0x00000080 +#define SERVER_CAP_LOCK_AND_READ 0x00000100 +#define SERVER_CAP_NT_FIND 0x00000200 +#define SERVER_CAP_DFS 0x00001000 +#define SERVER_CAP_INFOLEVEL_PASSTHRU 0x00002000 +#define SERVER_CAP_LARGE_READX 0x00004000 +#define SERVER_CAP_LARGE_WRITEX 0x00008000 +#define SERVER_CAP_LWIO 0x00010000 +#define SERVER_CAP_UNIX 0x00800000 +#define SERVER_CAP_COMPRESSED_DATA 0x02000000 +#define SERVER_CAP_DYNAMIC_REAUTH 0x20000000 +#define SERVER_CAP_EXTENDED_SECURITY 0x80000000 + +static const true_false_string tfs_server_cap_raw_mode = { + "Read Raw and Write Raw are supported", + "Read Raw and Write Raw are not supported" +}; +static const true_false_string tfs_server_cap_mpx_mode = { + "Read Mpx and Write Mpx are supported", + "Read Mpx and Write Mpx are not supported" +}; +static const true_false_string tfs_server_cap_unicode = { + "Unicode strings are supported", + "Unicode strings are not supported" +}; +static const true_false_string tfs_server_cap_large_files = { + "Large files are supported", + "Large files are not supported", +}; +static const true_false_string tfs_server_cap_nt_smbs = { + "NT SMBs are supported", + "NT SMBs are not supported" +}; +static const true_false_string tfs_server_cap_rpc_remote_apis = { + "RPC remote APIs are supported", + "RPC remote APIs are not supported" +}; +static const true_false_string tfs_server_cap_nt_status = { + "NT status codes are supported", + "NT status codes are not supported" +}; +static const true_false_string tfs_server_cap_level_ii_oplocks = { + "Level 2 oplocks are supported", + "Level 2 oplocks are not supported" +}; +static const true_false_string tfs_server_cap_lock_and_read = { + "Lock and Read is supported", + "Lock and Read is not supported" +}; +static const true_false_string tfs_server_cap_nt_find = { + "NT Find is supported", + "NT Find is not supported" +}; +static const true_false_string tfs_server_cap_dfs = { + "Dfs is supported", + "Dfs is not supported" +}; +static const true_false_string tfs_server_cap_infolevel_passthru = { + "NT information level request passthrough is supported", + "NT information level request passthrough is not supported" +}; +static const true_false_string tfs_server_cap_large_readx = { + "Large Read andX is supported", + "Large Read andX is not supported" +}; +static const true_false_string tfs_server_cap_large_writex = { + "Large Write andX is supported", + "Large Write andX is not supported" +}; +static const true_false_string tfs_server_cap_lwio = { + "LWIO ioctl/fsctl is supported", + "LWIO ioctl/fsctl is not supported" +}; +static const true_false_string tfs_server_cap_unix = { + "UNIX extensions are supported", + "UNIX extensions are not supported" +}; +static const true_false_string tfs_server_cap_compressed_data = { + "Compressed data transfer is supported", + "Compressed data transfer is not supported" +}; +static const true_false_string tfs_server_cap_dynamic_reauth = { + "Dynamic Reauth is supported", + "Dynamic Reauth is not supported" +}; +static const true_false_string tfs_server_cap_extended_security = { + "Extended security exchanges are supported", + "Extended security exchanges are not supported" +}; +static int +dissect_negprot_capabilities(tvbuff_t *tvb, proto_tree *parent_tree, int offset) +{ + guint32 mask; + + static int * const flags[] = { + &hf_smb_server_cap_raw_mode, + &hf_smb_server_cap_mpx_mode, + &hf_smb_server_cap_unicode, + &hf_smb_server_cap_large_files, + &hf_smb_server_cap_nt_smbs, + &hf_smb_server_cap_rpc_remote_apis, + &hf_smb_server_cap_nt_status, + &hf_smb_server_cap_level_ii_oplocks, + &hf_smb_server_cap_lock_and_read, + &hf_smb_server_cap_nt_find, + &hf_smb_server_cap_dfs, + &hf_smb_server_cap_infolevel_passthru, + &hf_smb_server_cap_large_readx, + &hf_smb_server_cap_large_writex, + &hf_smb_server_cap_lwio, + &hf_smb_server_cap_unix, + &hf_smb_server_cap_compressed_data, + &hf_smb_server_cap_dynamic_reauth, + &hf_smb_server_cap_extended_security, + NULL + }; + + mask = tvb_get_letohl(tvb, offset); + proto_tree_add_bitmask(parent_tree, tvb, offset, hf_smb_server_cap, ett_smb_capabilities, flags, ENC_LITTLE_ENDIAN); + + return mask; +} + +#define RAWMODE_READ 0x0001 +#define RAWMODE_WRITE 0x0002 +static const true_false_string tfs_rm_read = { + "Read Raw is supported", + "Read Raw is not supported" +}; +static const true_false_string tfs_rm_write = { + "Write Raw is supported", + "Write Raw is not supported" +}; + +static int +dissect_negprot_rawmode(tvbuff_t *tvb, proto_tree *parent_tree, int offset) +{ + static int * const flags[] = { + &hf_smb_rm_read, + &hf_smb_rm_write, + NULL + }; + + proto_tree_add_bitmask(parent_tree, tvb, offset, hf_smb_rm, ett_smb_rawmode, flags, ENC_LITTLE_ENDIAN); + + offset += 2; + + return offset; +} + +#define SECURITY_MODE_MODE 0x01 +#define SECURITY_MODE_PASSWORD 0x02 +#define SECURITY_MODE_SIGNATURES 0x04 +#define SECURITY_MODE_SIG_REQUIRED 0x08 +static const true_false_string tfs_sm_mode = { + "USER security mode", + "SHARE security mode" +}; +static const true_false_string tfs_sm_password = { + "ENCRYPTED password. Use challenge/response", + "PLAINTEXT password" +}; +static const true_false_string tfs_sm_signatures = { + "Security signatures ENABLED", + "Security signatures NOT enabled" +}; +static const true_false_string tfs_sm_sig_required = { + "Security signatures REQUIRED", + "Security signatures NOT required" +}; + +static int +dissect_negprot_security_mode(tvbuff_t *tvb, proto_tree *parent_tree, int offset, int wc) +{ + static int * const flags13[] = { + &hf_smb_sm_mode16, + &hf_smb_sm_password16, + NULL + }; + static int * const flags17[] = { + &hf_smb_sm_mode, + &hf_smb_sm_password, + &hf_smb_sm_signatures, + &hf_smb_sm_sig_required, + NULL + }; + + switch(wc) { + case 13: + proto_tree_add_bitmask(parent_tree, tvb, offset, hf_smb_sm16, ett_smb_mode, flags13, ENC_LITTLE_ENDIAN); + offset += 2; + break; + + case 17: + proto_tree_add_bitmask(parent_tree, tvb, offset, hf_smb_sm, ett_smb_mode, flags17, ENC_LITTLE_ENDIAN); + offset += 1; + break; + } + + return offset; +} + +#define MAX_DIALECTS 20 +struct negprot_dialects { + int num; + char *name[MAX_DIALECTS+1]; +}; + +static int +dissect_negprot_request(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int offset, proto_tree *smb_tree _U_, smb_info_t *si) +{ + proto_tree *tr = NULL; + proto_item *ti; + guint16 bc; + guint8 wc; + struct negprot_dialects *dialects = NULL; + + DISSECTOR_ASSERT(si); + + WORD_COUNT; + + BYTE_COUNT; + + tr = proto_tree_add_subtree(tree, tvb, offset, -1, ett_smb_dialects, &ti, "Requested Dialects"); + + if (!pinfo->fd->visited && si->sip) { + dialects = wmem_new(wmem_file_scope(), struct negprot_dialects); + dialects->num = 0; + si->sip->extra_info_type = SMB_EI_DIALECTS; + si->sip->extra_info = dialects; + } + + while (bc) { + int len; + const guint8 *str; + proto_item *dit = NULL; + proto_tree *dtr = NULL; + + /* XXX - what if this runs past bc? */ + tvb_ensure_bytes_exist(tvb, offset+1, 1); + + /* XXX: This is an OEM String according to MS-CIFS and + * should use the local OEM (extended ASCII DOS) code page, + * It doesn't appear than any known dialect strings use + * anything outside ASCII, though. + * + * There could be a dissector preference for local code page. + */ + str = tvb_get_stringz_enc(pinfo->pool, tvb, offset+1, &len, ENC_ASCII); + + if (tr) { + dit = proto_tree_add_string(tr, hf_smb_dialect, tvb, offset, len+1, str); + dtr = proto_item_add_subtree(dit, ett_smb_dialect); + } + + /* Buffer Format */ + CHECK_BYTE_COUNT(1); + proto_tree_add_item(dtr, hf_smb_buffer_format, tvb, offset, 1, + ENC_LITTLE_ENDIAN); + COUNT_BYTES(1); + + /*Dialect Name */ + CHECK_BYTE_COUNT(len); + proto_tree_add_item(dtr, hf_smb_dialect_name, tvb, + offset, len, ENC_ASCII); + COUNT_BYTES(len); + + if (!pinfo->fd->visited && dialects && (dialects->num < MAX_DIALECTS)) { + dialects->name[dialects->num++] = wmem_strdup(wmem_file_scope(), str); + } + } + proto_item_set_len(ti, bc); + + END_OF_SMB + + return offset; +} + +static int +dissect_negprot_response(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int offset, proto_tree *smb_tree _U_, smb_info_t *si) +{ + guint8 wc; + guint16 dialect; + const char *dn; + int dn_len; + guint16 bc; + guint16 chl = 0; + guint32 caps = 0; + gint16 tz; + const char *dialect_name = NULL; + struct negprot_dialects *dialects = NULL; + + DISSECTOR_ASSERT(si); + + WORD_COUNT; + + /* Dialect Index */ + dialect = tvb_get_letohs(tvb, offset); + + if (si->sip && (si->sip->extra_info_type == SMB_EI_DIALECTS)) { + dialects = (struct negprot_dialects *)si->sip->extra_info; + if (dialect < dialects->num) { + dialect_name = dialects->name[dialect]; + } + } + if (!dialect_name) { + dialect_name = "unknown"; + } + + switch(wc) { + case 1: + if (dialect == 0xffff) { + /* + * Server doesn't support any of the dialects the + * client listed. + */ + proto_tree_add_uint_format_value(tree, hf_smb_dialect_index, + tvb, offset, 2, dialect, + "-1, server does not support any of the listed dialects"); + } else { + /* + * A dialect was selected; this should be + * Core Protocol. + */ + proto_tree_add_uint(tree, hf_smb_dialect_index, + tvb, offset, 2, dialect); + } + break; + case 13: + /* + * Server selected a dialect from LAN Manager 1.0 through + * LAN Manager 2.1. + */ + proto_tree_add_uint_format_value(tree, hf_smb_dialect_index, + tvb, offset, 2, dialect, + "%u, Greater than CORE PROTOCOL and up to LANMAN2.1", dialect); + break; + case 17: + /* + * Server selected NT LAN Manager. + */ + proto_tree_add_uint_format_value(tree, hf_smb_dialect_index, + tvb, offset, 2, dialect, + "%u: %s", dialect, dialect_name); + break; + default: + proto_tree_add_item(tree, hf_smb_word_unk_response_format, tvb, offset, wc*2, ENC_NA); + offset += wc*2; + goto bytecount; + } + offset += 2; + + switch(wc) { + case 13: + /* + * Server selected a dialect from LAN Manager 1.0 through + * LAN Manager 2.1. + */ + + /* Security Mode */ + offset = dissect_negprot_security_mode(tvb, tree, offset, wc); + + /* Maximum Transmit Buffer Size */ + proto_tree_add_item(tree, hf_smb_max_trans_buf_size, + tvb, offset, 2, ENC_LITTLE_ENDIAN); + offset += 2; + + /* Maximum Multiplex Count */ + proto_tree_add_item(tree, hf_smb_max_mpx_count, + tvb, offset, 2, ENC_LITTLE_ENDIAN); + offset += 2; + + /* Maximum Vcs Number */ + proto_tree_add_item(tree, hf_smb_max_vcs_num, + tvb, offset, 2, ENC_LITTLE_ENDIAN); + offset += 2; + + /* raw mode */ + offset = dissect_negprot_rawmode(tvb, tree, offset); + + /* session key */ + proto_tree_add_item(tree, hf_smb_session_key, + tvb, offset, 4, ENC_LITTLE_ENDIAN); + offset += 4; + + /* current time and date at server */ + offset = dissect_smb_datetime(tvb, tree, offset, hf_smb_server_date_time, hf_smb_server_smb_date, hf_smb_server_smb_time, + TRUE); + + /* time zone */ + tz = tvb_get_letohs(tvb, offset); + proto_tree_add_int_format_value(tree, hf_smb_server_timezone, tvb, offset, 2, tz, "%d min from UTC", tz); + offset += 2; + + /* + * The LAN Manager 1 and 2.0 specs say these are the + * first 2 of 4 reserved bytes; the LAN Manager 2.1 + * spec says it's a 2-byte encryption key (challenge) + * length. + */ + chl = tvb_get_letohs(tvb, offset); + proto_tree_add_uint(tree, hf_smb_challenge_length, tvb, offset, 2, chl); + offset += 2; + + /* 2 reserved bytes */ + proto_tree_add_item(tree, hf_smb_reserved, tvb, offset, 2, ENC_NA); + offset += 2; + + break; + + case 17: + /* + * Server selected NT LAN Manager. + */ + + /* Security Mode */ + offset = dissect_negprot_security_mode(tvb, tree, offset, wc); + + /* Maximum Multiplex Count */ + proto_tree_add_item(tree, hf_smb_max_mpx_count, + tvb, offset, 2, ENC_LITTLE_ENDIAN); + offset += 2; + + /* Maximum Vcs Number */ + proto_tree_add_item(tree, hf_smb_max_vcs_num, + tvb, offset, 2, ENC_LITTLE_ENDIAN); + offset += 2; + + /* Maximum Transmit Buffer Size */ + proto_tree_add_item(tree, hf_smb_max_trans_buf_size, + tvb, offset, 4, ENC_LITTLE_ENDIAN); + offset += 4; + + /* maximum raw buffer size */ + proto_tree_add_item(tree, hf_smb_max_raw_buf_size, + tvb, offset, 4, ENC_LITTLE_ENDIAN); + offset += 4; + + /* session key */ + proto_tree_add_item(tree, hf_smb_session_key, + tvb, offset, 4, ENC_LITTLE_ENDIAN); + offset += 4; + + /* server capabilities */ + caps = dissect_negprot_capabilities(tvb, tree, offset); + offset += 4; + + /* system time */ + offset = dissect_nt_64bit_time(tvb, tree, offset, + hf_smb_system_time); + + /* time zone */ + tz = tvb_get_letohs(tvb, offset); + proto_tree_add_int_format_value(tree, hf_smb_server_timezone, + tvb, offset, 2, tz, + "%d min from UTC", tz); + offset += 2; + + /* challenge length */ + chl = tvb_get_guint8(tvb, offset); + proto_tree_add_uint(tree, hf_smb_challenge_length, + tvb, offset, 1, chl); + offset += 1; + + break; + } + + BYTE_COUNT; + + switch(wc) { + case 13: + /* + * Server selected a dialect from LAN Manager 1.0 through + * LAN Manager 2.1. + */ + + /* encrypted challenge/response data */ + if (chl) { + CHECK_BYTE_COUNT(chl); + proto_tree_add_item(tree, hf_smb_challenge, tvb, offset, chl, ENC_NA); + COUNT_BYTES(chl); + } + + /* + * Primary domain. + * + * XXX - not present if negotiated dialect isn't + * "DOS LANMAN 2.1" or "LANMAN2.1", but we'd either + * have to see the request, or assume what dialect strings + * were sent, to determine that. + * + * Is this something other than a primary domain if the + * negotiated dialect is Windows for Workgroups 3.1a? + * It appears to be 8 bytes of binary data in at least + * one capture - is that an encryption key or something + * such as that? + */ + dn = get_unicode_or_ascii_string(tvb, &offset, + si->unicode, &dn_len, FALSE, FALSE, &bc); + if (dn == NULL) + goto endofcommand; + proto_tree_add_string(tree, hf_smb_primary_domain, tvb, + offset, dn_len, dn); + COUNT_BYTES(dn_len); + break; + + case 17: + /* + * Server selected NT LAN Manager. + */ + if (!(caps & SERVER_CAP_EXTENDED_SECURITY)) { + /* encrypted challenge/response data */ + /* XXX - is this aligned on an even boundary? */ + if (chl) { + CHECK_BYTE_COUNT(chl); + proto_tree_add_item(tree, hf_smb_challenge, + tvb, offset, chl, ENC_NA); + COUNT_BYTES(chl); + } + + /* domain */ + /* + * This string is special; at least in some captures, + * it's in Unicode, even if "Unicode strings" isn't + * set in the flags2 field. If the "Unicode support" + * flag is set in the server capabilities field, + * that seems to indicate that it's in Unicode for + * those captures. + * + * So fetch it in Unicode either if it's set in the + * flags2 field *or* in the capabilities field. + * + * XXX - I've seen captures where "Unicode strings" + * isn't set, "Unicode support" is set in the server + * capabilities field, and the primary domain string + * is in the local code page; that may just have + * a buggy server, though. + * + * Clients tend, at least according to the + * footnote in MS-CIFS for the DomainName field + * in the Negotiate response, to ignore that + * field, so maybe servers put extra bytes in + * there without clients noticing. + */ + si->unicode = (caps & SERVER_CAP_UNICODE) || si->unicode; + + /* + * If we're fetching Unicode strings: + * + * This string is NOT padded to be 16-bit + * aligned; it's unaligned in some captures. + * + * However, it sometimes has an extra byte + * before it. If the byte count is not a + * multiple of 2, there must be an extra byte + * somewhere; it appears to be the byte just + * before this string, so check for an odd + * byte count, and skip that byte. + * + * If we're fetching local code page strings: + * + * In some cases there appears to be an extra + * byte before it. It's not clear what + * indicates its presence, if anything. + * + * However, at least one of those cases + * was one of the "the server set the + * Unicode support flag in capabilities, + * but sent the domain name in the local + * code page" captures mentioned above, + * so maybe it was just a buggy server. + * + * Again, as noted above, clients may just + * ignore that field, leaving servers "free" + * to mess it up. + */ + if (si->unicode && (bc % 2) != 0) { + /* Skip the padding */ + CHECK_BYTE_COUNT(1); + COUNT_BYTES(1); + } + dn = get_unicode_or_ascii_string(tvb, + &offset, si->unicode, &dn_len, TRUE, FALSE, + &bc); + if (dn == NULL) + goto endofcommand; + proto_tree_add_string(tree, hf_smb_primary_domain, + tvb, offset, dn_len, dn); + COUNT_BYTES(dn_len); + + /* server name, seen in w2k pro capture */ + dn = get_unicode_or_ascii_string(tvb, + &offset, si->unicode, &dn_len, TRUE, FALSE, + &bc); + if (dn == NULL) + goto endofcommand; + proto_tree_add_string(tree, hf_smb_server, + tvb, offset, dn_len, dn); + COUNT_BYTES(dn_len); + + } else { + proto_item *blob_item; + guint16 sbloblen; + + /* guid */ + /* XXX - show it in the standard Microsoft format + for GUIDs? */ + CHECK_BYTE_COUNT(16); + proto_tree_add_item(tree, hf_smb_server_guid, + tvb, offset, 16, ENC_NA); + COUNT_BYTES(16); + + /* security blob */ + /* If it runs past the end of the captured data, don't + * try to put all of it into the protocol tree as the + * raw security blob; we might get an exception on + * short frames and then we will not see anything at all + * of the security blob. + */ + sbloblen = bc; + if (sbloblen > tvb_reported_length_remaining(tvb, offset)) { + sbloblen = tvb_reported_length_remaining(tvb, offset); + } + blob_item = proto_tree_add_item( + tree, hf_smb_security_blob, + tvb, offset, sbloblen, ENC_NA); + + /* + * If Extended security and BCC == 16, then raw + * NTLMSSP is in use. We need to save this info + */ + + if (bc) { + tvbuff_t *gssapi_tvb; + proto_tree *gssapi_tree; + + gssapi_tree = proto_item_add_subtree( + blob_item, ett_smb_secblob); + + /* + * Set the reported length of this to + * the reported length of the blob, + * rather than the amount of data + * available from the blob, so that + * we'll throw the right exception if + * it's too short. + */ + gssapi_tvb = tvb_new_subset_length_caplen( + tvb, offset, sbloblen, bc); + + call_dissector( + gssapi_handle, gssapi_tvb, pinfo, + gssapi_tree); + + if (si->ct) + si->ct->raw_ntlmssp = 0; + + COUNT_BYTES(bc); + } + else { + + /* + * There is no blob. We just have to make sure + * that subsequent routines know to call the + * right things ... + */ + + if (si->ct) + si->ct->raw_ntlmssp = 1; + + } + } + break; + } + + END_OF_SMB + + return offset; +} + + +static int +dissect_old_dir_request(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int offset, proto_tree *smb_tree _U_, smb_info_t *si) +{ + int dn_len; + const char *dn; + guint8 wc; + guint16 bc; + + DISSECTOR_ASSERT(si); + + WORD_COUNT; + + BYTE_COUNT; + + /* buffer format */ + CHECK_BYTE_COUNT(1); + proto_tree_add_item(tree, hf_smb_buffer_format, tvb, offset, 1, ENC_LITTLE_ENDIAN); + COUNT_BYTES(1); + + /* dir name */ + dn = get_unicode_or_ascii_string(tvb, &offset, si->unicode, &dn_len, + FALSE, FALSE, &bc); + + if ((!pinfo->fd->visited) && si->sip) { + si->sip->extra_info_type = SMB_EI_FILENAME; + si->sip->extra_info = wmem_strdup(wmem_file_scope(), dn); + } + + if (dn == NULL) + goto endofcommand; + proto_tree_add_string(tree, hf_smb_dir_name, tvb, offset, dn_len, + dn); + COUNT_BYTES(dn_len); + + col_append_fstr(pinfo->cinfo, COL_INFO, ", Directory: %s", + format_text(wmem_packet_scope(), (const guchar *)dn, strlen(dn))); + + END_OF_SMB + + return offset; +} + +static int +dissect_empty(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, int offset, proto_tree *smb_tree _U_, smb_info_t *si) +{ + guint8 wc; + guint16 bc; + proto_item *item = NULL; + + DISSECTOR_ASSERT(si); + + if (si->sip && (si->sip->extra_info_type == SMB_EI_FILENAME)) { + item = proto_tree_add_string(tree, hf_smb_file_name, tvb, 0, 0, (const char *)si->sip->extra_info); + proto_item_set_generated(item); + } + + + WORD_COUNT; + + BYTE_COUNT; + + END_OF_SMB + + return offset; +} + +static int +dissect_rename_file_response(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, int offset, proto_tree *smb_tree _U_, smb_info_t *si) +{ + guint8 wc; + guint16 bc; + proto_item *item = NULL; + + DISSECTOR_ASSERT(si); + + if (si->sip && (si->sip->extra_info_type == SMB_EI_RENAMEDATA)) { + smb_rename_saved_info_t *rni = (smb_rename_saved_info_t *)si->sip->extra_info; + + item = proto_tree_add_string(tree, hf_smb_old_file_name, tvb, 0, 0, rni->old_name); + proto_item_set_generated(item); + item = proto_tree_add_string(tree, hf_smb_file_name, tvb, 0, 0, rni->new_name); + proto_item_set_generated(item); + } + + + WORD_COUNT; + + BYTE_COUNT; + + END_OF_SMB + + return offset; +} + +static int +dissect_echo_request(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, int offset, proto_tree *smb_tree _U_, smb_info_t *si _U_) +{ + guint16 ec, bc; + guint8 wc; + + WORD_COUNT; + + /* echo count */ + ec = tvb_get_letohs(tvb, offset); + proto_tree_add_uint(tree, hf_smb_echo_count, tvb, offset, 2, ec); + offset += 2; + + BYTE_COUNT; + + if (bc != 0) { + /* echo data */ + proto_tree_add_item(tree, hf_smb_echo_data, tvb, offset, bc, ENC_NA); + COUNT_BYTES(bc); + } + + END_OF_SMB + + return offset; +} + +static int +dissect_echo_response(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, int offset, proto_tree *smb_tree _U_, smb_info_t *si _U_) +{ + guint16 bc; + guint8 wc; + + WORD_COUNT; + + /* echo sequence number */ + proto_tree_add_item(tree, hf_smb_echo_seq_num, tvb, offset, 2, ENC_LITTLE_ENDIAN); + offset += 2; + + BYTE_COUNT; + + if (bc != 0) { + /* echo data */ + proto_tree_add_item(tree, hf_smb_echo_data, tvb, offset, bc, ENC_NA); + COUNT_BYTES(bc); + } + + END_OF_SMB + + return offset; +} + +static int +dissect_tree_connect_request(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int offset, proto_tree *smb_tree _U_, smb_info_t *si) +{ + int an_len, pwlen; + const char *an; + guint8 wc; + guint16 bc; + + DISSECTOR_ASSERT(si); + + WORD_COUNT; + + BYTE_COUNT; + + /* buffer format */ + CHECK_BYTE_COUNT(1); + proto_tree_add_item(tree, hf_smb_buffer_format, tvb, offset, 1, ENC_LITTLE_ENDIAN); + COUNT_BYTES(1); + + /* Path */ + an = get_unicode_or_ascii_string(tvb, &offset, + si->unicode, &an_len, FALSE, FALSE, &bc); + if (an == NULL) + goto endofcommand; + proto_tree_add_string(tree, hf_smb_path, tvb, + offset, an_len, an); + COUNT_BYTES(an_len); + + col_append_fstr(pinfo->cinfo, COL_INFO, ", Path: %s", + format_text(wmem_packet_scope(), (const guchar*)an, strlen(an))); + + /* buffer format */ + CHECK_BYTE_COUNT(1); + proto_tree_add_item(tree, hf_smb_buffer_format, tvb, offset, 1, ENC_LITTLE_ENDIAN); + COUNT_BYTES(1); + + /* password, ANSI */ + /* XXX - what if this runs past bc? */ + pwlen = tvb_strsize(tvb, offset); + CHECK_BYTE_COUNT(pwlen); + proto_tree_add_item(tree, hf_smb_password, + tvb, offset, pwlen, ENC_NA); + COUNT_BYTES(pwlen); + + /* buffer format */ + CHECK_BYTE_COUNT(1); + proto_tree_add_item(tree, hf_smb_buffer_format, tvb, offset, 1, ENC_LITTLE_ENDIAN); + COUNT_BYTES(1); + + /* Service */ + /* + * XXX - the SNIA CIFS spec "Strings that are never passed in + * Unicode are: ... The service name string in the + * Tree_Connect_AndX SMB". Is that claim false? + */ + an = get_unicode_or_ascii_string(tvb, &offset, + si->unicode, &an_len, FALSE, FALSE, &bc); + if (an == NULL) + goto endofcommand; + proto_tree_add_string(tree, hf_smb_service, tvb, + offset, an_len, an); + COUNT_BYTES(an_len); + + END_OF_SMB + + return offset; +} + +static int +dissect_smb_uid(tvbuff_t *tvb, proto_tree *parent_tree, int offset, smb_info_t *si) +{ + proto_item *item, *subitem; + proto_tree *tree; + smb_uid_t *smb_uid = NULL; + + item = proto_tree_add_uint(parent_tree, hf_smb_uid, tvb, offset, 2, si->uid); + tree = proto_item_add_subtree(item, ett_smb_uid); + + smb_uid = (smb_uid_t *)wmem_tree_lookup32(si->ct->uid_tree, si->uid); + if (smb_uid) { + if (smb_uid->domain && smb_uid->account) + proto_item_append_text(item, " ("); + if (smb_uid->domain) { + proto_item_append_text(item, "%s", smb_uid->domain); + subitem = proto_tree_add_string(tree, hf_smb_primary_domain, tvb, 0, 0, smb_uid->domain); + proto_item_set_generated(subitem); + } + if (smb_uid->account) { + proto_item_append_text(item, "\\%s", smb_uid->account); + subitem = proto_tree_add_string(tree, hf_smb_account, tvb, 0, 0, smb_uid->account); + proto_item_set_generated(subitem); + } + if (smb_uid->domain && smb_uid->account) + proto_item_append_text(item, ")"); + if (smb_uid->logged_in > 0) { + subitem = proto_tree_add_uint(tree, hf_smb_logged_in, tvb, 0, 0, smb_uid->logged_in); + proto_item_set_generated(subitem); + } + if (smb_uid->logged_out > 0) { + subitem = proto_tree_add_uint(tree, hf_smb_logged_out, tvb, 0, 0, smb_uid->logged_out); + proto_item_set_generated(subitem); + } + } + offset += 2; + + return offset; +} + +static int +dissect_smb_tid(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int offset, guint16 tid, gboolean is_created, gboolean is_closed, smb_info_t *si) +{ + proto_item *it; + proto_tree *tr; + smb_tid_info_t *tid_info = NULL; + + DISSECTOR_ASSERT(si); + + /* tid */ + it = proto_tree_add_uint(tree, hf_smb_tid, tvb, offset, 2, tid); + tr = proto_item_add_subtree(it, ett_smb_tid); + offset += 2; + + if ((!pinfo->fd->visited) && is_created) { + tid_info = wmem_new(wmem_file_scope(), smb_tid_info_t); + tid_info->opened_in = pinfo->num; + tid_info->closed_in = 0; + tid_info->type = SMB_FID_TYPE_UNKNOWN; + if (si->sip && (si->sip->extra_info_type == SMB_EI_TIDNAME)) { + tid_info->filename = (char *)si->sip->extra_info; + } else { + tid_info->filename = NULL; + } + wmem_tree_insert32(si->ct->tid_tree, tid, tid_info); + } + + if (!tid_info) { + tid_info = (smb_tid_info_t *)wmem_tree_lookup32_le(si->ct->tid_tree, tid); + } + if (!tid_info) { + return offset; + } + + if ((!pinfo->fd->visited) && is_closed) { + tid_info->closed_in = pinfo->num; + } + + if (tid_info->opened_in) { + if (tid_info->filename) { + proto_item_append_text(it, " (%s)", tid_info->filename); + + it = proto_tree_add_string(tr, hf_smb_path, tvb, 0, 0, tid_info->filename); + proto_item_set_generated(it); + } + + it = proto_tree_add_uint(tr, hf_smb_mapped_in, tvb, 0, 0, tid_info->opened_in); + proto_item_set_generated(it); + } + if (tid_info->closed_in) { + it = proto_tree_add_uint(tr, hf_smb_unmapped_in, tvb, 0, 0, tid_info->closed_in); + proto_item_set_generated(it); + } + + + return offset; +} + +static int +dissect_tree_connect_response(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int offset, proto_tree *smb_tree _U_, smb_info_t *si) +{ + guint8 wc; + guint16 bc; + + WORD_COUNT; + + /* Maximum Buffer Size */ + proto_tree_add_item(tree, hf_smb_max_buf_size, tvb, offset, 2, ENC_LITTLE_ENDIAN); + offset += 2; + + /* tid */ + offset = dissect_smb_tid(tvb, pinfo, tree, offset, tvb_get_letohs(tvb, offset), TRUE, FALSE, si); + + BYTE_COUNT; + + END_OF_SMB + + return offset; +} + + +static const true_false_string tfs_of_create = { + "Create file if it does not exist", + "Fail if file does not exist" +}; +static const value_string of_open[] = { + { 0, "Fail if file exists"}, + { 1, "Open file if it exists"}, + { 2, "Truncate file if it exists"}, + {0, NULL} +}; +static int +dissect_open_function(tvbuff_t *tvb, proto_tree *parent_tree, int offset) +{ + static int * const flags[] = { + &hf_smb_open_function_create, + &hf_smb_open_function_open, + NULL + }; + + proto_tree_add_bitmask(parent_tree, tvb, offset, hf_smb_open_function, ett_smb_openfunction, flags, ENC_LITTLE_ENDIAN); + offset += 2; + + return offset; +} + + +static const true_false_string tfs_mf_file = { + "Target must be a file", + "Target needn't be a file" +}; +static const true_false_string tfs_mf_dir = { + "Target must be a directory", + "Target needn't be a directory" +}; +static const true_false_string tfs_mf_verify = { + "MUST verify all writes", + "Don't have to verify writes" +}; +static int +dissect_move_flags(tvbuff_t *tvb, proto_tree *parent_tree, int offset) +{ + static int * const flags[] = { + &hf_smb_move_flags_verify, + &hf_smb_move_flags_dir, + &hf_smb_move_flags_file, + NULL + }; + + proto_tree_add_bitmask(parent_tree, tvb, offset, hf_smb_move_flags, ett_smb_move_copy_flags, flags, ENC_LITTLE_ENDIAN); + offset += 2; + + return offset; +} + +static const true_false_string tfs_cf_mode = { + "ASCII", + "Binary" +}; +static const true_false_string tfs_cf_tree_copy = { + "Copy is a tree copy", + "Copy is a file copy" +}; +static const true_false_string tfs_cf_ea_action = { + "Fail copy", + "Discard EAs" +}; +static int +dissect_copy_flags(tvbuff_t *tvb, proto_tree *parent_tree, int offset) +{ + static int * const flags[] = { + &hf_smb_copy_flags_ea_action, + &hf_smb_copy_flags_tree_copy, + &hf_smb_copy_flags_verify, + &hf_smb_copy_flags_source_mode, + &hf_smb_copy_flags_dest_mode, + &hf_smb_copy_flags_dir, + &hf_smb_copy_flags_file, + NULL + }; + + proto_tree_add_bitmask(parent_tree, tvb, offset, hf_smb_copy_flags, ett_smb_move_copy_flags, flags, ENC_LITTLE_ENDIAN); + offset += 2; + + return offset; +} + +static int +dissect_move_request(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int offset, proto_tree *smb_tree _U_, smb_info_t *si) +{ + int fn_len; + guint16 tid; + guint16 bc; + guint8 wc; + const char *fn; + + DISSECTOR_ASSERT(si); + + WORD_COUNT; + + /* tid */ + tid = tvb_get_letohs(tvb, offset); + offset = dissect_smb_tid(tvb, pinfo, tree, offset, tid, FALSE, FALSE, si); + + /* open function */ + offset = dissect_open_function(tvb, tree, offset); + + /* move flags */ + offset = dissect_move_flags(tvb, tree, offset); + + BYTE_COUNT; + + /* buffer format */ + CHECK_BYTE_COUNT(1); + proto_tree_add_item(tree, hf_smb_buffer_format, tvb, offset, 1, ENC_LITTLE_ENDIAN); + COUNT_BYTES(1); + + /* file name */ + fn = get_unicode_or_ascii_string(tvb, &offset, si->unicode, &fn_len, + FALSE, FALSE, &bc); + if (fn == NULL) + goto endofcommand; + proto_tree_add_string_format(tree, hf_smb_file_name, tvb, offset, + fn_len, fn, "Old File Name: %s", format_text(wmem_packet_scope(), (const guchar*)fn, strlen(fn))); + COUNT_BYTES(fn_len); + + col_append_fstr(pinfo->cinfo, COL_INFO, ", Old Name: %s", + format_text(wmem_packet_scope(), (const guchar*)fn, strlen(fn))); + + /* buffer format */ + CHECK_BYTE_COUNT(1); + proto_tree_add_item(tree, hf_smb_buffer_format, tvb, offset, 1, ENC_LITTLE_ENDIAN); + COUNT_BYTES(1); + + /* file name */ + fn = get_unicode_or_ascii_string(tvb, &offset, si->unicode, &fn_len, + FALSE, FALSE, &bc); + if (fn == NULL) + goto endofcommand; + proto_tree_add_string_format(tree, hf_smb_file_name, tvb, offset, + fn_len, fn, "New File Name: %s", format_text(wmem_packet_scope(), (const guchar*)fn, strlen(fn))); + COUNT_BYTES(fn_len); + + col_append_fstr(pinfo->cinfo, COL_INFO, ", New Name: %s", + format_text(wmem_packet_scope(), (const guchar*)fn, strlen(fn))); + + END_OF_SMB + + return offset; +} + +static int +dissect_copy_request(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int offset, proto_tree *smb_tree _U_, smb_info_t *si) +{ + int fn_len; + guint16 tid; + guint16 bc; + guint8 wc; + const char *fn; + + DISSECTOR_ASSERT(si); + + WORD_COUNT; + + /* tid */ + tid = tvb_get_letohs(tvb, offset); + offset = dissect_smb_tid(tvb, pinfo, tree, offset, tid, FALSE, FALSE, si); + + /* open function */ + offset = dissect_open_function(tvb, tree, offset); + + /* copy flags */ + offset = dissect_copy_flags(tvb, tree, offset); + + BYTE_COUNT; + + /* buffer format */ + CHECK_BYTE_COUNT(1); + proto_tree_add_item(tree, hf_smb_buffer_format, tvb, offset, 1, ENC_LITTLE_ENDIAN); + COUNT_BYTES(1); + + /* file name */ + fn = get_unicode_or_ascii_string(tvb, &offset, si->unicode, &fn_len, + FALSE, FALSE, &bc); + if (fn == NULL) + goto endofcommand; + proto_tree_add_string_format(tree, hf_smb_file_name, tvb, offset, + fn_len, fn, "Source File Name: %s", format_text(wmem_packet_scope(), (const guchar*)fn, strlen(fn))); + COUNT_BYTES(fn_len); + + col_append_fstr(pinfo->cinfo, COL_INFO, ", Source Name: %s", + format_text(wmem_packet_scope(), (const guchar*)fn, strlen(fn))); + + /* buffer format */ + CHECK_BYTE_COUNT(1); + proto_tree_add_item(tree, hf_smb_buffer_format, tvb, offset, 1, ENC_LITTLE_ENDIAN); + COUNT_BYTES(1); + + /* file name */ + fn = get_unicode_or_ascii_string(tvb, &offset, si->unicode, &fn_len, + FALSE, FALSE, &bc); + if (fn == NULL) + goto endofcommand; + proto_tree_add_string_format(tree, hf_smb_file_name, tvb, offset, + fn_len, fn, "Destination File Name: %s", + format_text(wmem_packet_scope(), (const guchar*)fn, strlen(fn))); + COUNT_BYTES(fn_len); + + col_append_fstr(pinfo->cinfo, COL_INFO, ", Destination Name: %s", format_text(wmem_packet_scope(), (const guchar*)fn, strlen(fn))); + + END_OF_SMB + + return offset; +} + +static int +dissect_move_copy_response(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, int offset, proto_tree *smb_tree _U_, smb_info_t *si) +{ + int fn_len; + const char *fn; + guint8 wc; + guint16 bc; + + DISSECTOR_ASSERT(si); + + WORD_COUNT; + + /* # of files moved */ + proto_tree_add_item(tree, hf_smb_files_moved, tvb, offset, 2, ENC_LITTLE_ENDIAN); + offset += 2; + + BYTE_COUNT; + + /* buffer format */ + CHECK_BYTE_COUNT(1); + proto_tree_add_item(tree, hf_smb_buffer_format, tvb, offset, 1, ENC_LITTLE_ENDIAN); + COUNT_BYTES(1); + + /* file name */ + fn = get_unicode_or_ascii_string(tvb, &offset, si->unicode, &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); + + END_OF_SMB + + return offset; +} + +static int +dissect_open_file_request(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int offset, proto_tree *smb_tree _U_, smb_info_t *si) +{ + int fn_len; + const char *fn; + guint8 wc; + guint16 bc; + smb_fid_saved_info_t *fsi; /* eo_smb needs to track this info */ + + DISSECTOR_ASSERT(si); + + WORD_COUNT; + + /* desired access */ + offset = dissect_access(tvb, tree, offset, hf_smb_desired_access); + + /* Search Attributes */ + offset = dissect_search_attributes(tvb, tree, offset); + + BYTE_COUNT; + + /* buffer format */ + CHECK_BYTE_COUNT(1); + proto_tree_add_item(tree, hf_smb_buffer_format, tvb, offset, 1, ENC_LITTLE_ENDIAN); + COUNT_BYTES(1); + + /* file name */ + fn = get_unicode_or_ascii_string(tvb, &offset, si->unicode, &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); + + /* store it for the fid->name/openframe/closeframe matching in + * dissect_smb_fid() called from the response. + */ + if ((!pinfo->fd->visited) && si->sip && fn) { + fsi = wmem_new0(wmem_file_scope(), smb_fid_saved_info_t); + fsi->filename = wmem_strdup(wmem_file_scope(), fn); + + si->sip->extra_info_type = SMB_EI_FILEDATA; + si->sip->extra_info = fsi; + } + + col_append_fstr(pinfo->cinfo, COL_INFO, ", Path: %s", + format_text(wmem_packet_scope(), (const guchar*)fn, strlen(fn))); + + END_OF_SMB + + return offset; +} + + + +static int +dissect_nt_create_bits(tvbuff_t *tvb, proto_tree *parent_tree, int offset, + int len, guint32 mask) +{ + proto_item *item = NULL; + /* + * XXX - it's 0x00000016 in at least one capture, but + * Network Monitor doesn't say what the 0x00000010 bit is. + * Does the Win32 API documentation, or NT Native API book, + * suggest anything? + * + * That is the extended response desired bit ... RJS, from Samba + * Well, maybe. Samba thinks it is, and uses it to encode + * OpLock granted as the high order bit of the Action field + * in the response. However, Windows does not do that. Or at least + * Win2K doesn't. + */ + static int * const fields[] = { + &hf_smb_nt_create_bits_oplock, + &hf_smb_nt_create_bits_boplock, + &hf_smb_nt_create_bits_dir, + &hf_smb_nt_create_bits_ext_resp, + NULL + }; + + item = proto_tree_add_bitmask_value_with_flags(parent_tree, tvb, offset, hf_smb_create_flags, ett_smb_nt_create_bits, + fields, mask, BMT_NO_APPEND); + + if (len == 0) + proto_item_set_generated(item); + + offset += len; + + return offset; +} + +/* FIXME: need to call dissect_nt_access_mask() instead */ +static int +dissect_smb_access_mask_bits(tvbuff_t *tvb, proto_tree *parent_tree, + int offset, int len, guint32 mask) +{ + proto_item *item; + /* + * Some of these bits come from + * + * http://www.samba.org/samba/ftp/specs/smb-nt01.doc + * + * and others come from the section on ZwOpenFile in "Windows(R) + * NT(R)/2000 Native API Reference". + */ + static int * const fields[] = { + &hf_smb_nt_access_mask_read, + &hf_smb_nt_access_mask_write, + &hf_smb_nt_access_mask_append, + &hf_smb_nt_access_mask_read_ea, + &hf_smb_nt_access_mask_write_ea, + &hf_smb_nt_access_mask_execute, + &hf_smb_nt_access_mask_delete_child, + &hf_smb_nt_access_mask_read_attributes, + &hf_smb_nt_access_mask_write_attributes, + &hf_smb_nt_access_mask_delete, + &hf_smb_nt_access_mask_read_control, + &hf_smb_nt_access_mask_write_dac, + &hf_smb_nt_access_mask_write_owner, + &hf_smb_nt_access_mask_synchronize, + &hf_smb_nt_access_mask_system_security, + &hf_smb_nt_access_mask_maximum_allowed, + &hf_smb_nt_access_mask_generic_all, + &hf_smb_nt_access_mask_generic_execute, + &hf_smb_nt_access_mask_generic_write, + &hf_smb_nt_access_mask_generic_read, + NULL + }; + + item = proto_tree_add_bitmask_value_with_flags(parent_tree, tvb, offset, hf_smb_access_mask, ett_smb_nt_access_mask, + fields, mask, BMT_NO_APPEND); + + if (len == 0) + proto_item_set_generated(item); + offset += len; + + return offset; +} + +int +dissect_smb_access_mask(tvbuff_t *tvb, proto_tree *parent_tree, int offset) +{ + guint32 mask; + + mask = tvb_get_letohl(tvb, offset); + + offset = dissect_smb_access_mask_bits(tvb, parent_tree, offset, 4, mask); + + return offset; +} + +#define SHARE_ACCESS_READ 0x00000001 +#define SHARE_ACCESS_WRITE 0x00000002 +#define SHARE_ACCESS_DELETE 0x00000004 + +static int +dissect_nt_share_access_bits(tvbuff_t *tvb, proto_tree *parent_tree, + int offset, int len, guint32 mask) +{ + proto_item *item; + static int * const fields[] = { + &hf_smb_nt_share_access_read, + &hf_smb_nt_share_access_write, + &hf_smb_nt_share_access_delete, + NULL + }; + + item = proto_tree_add_bitmask_value(parent_tree, tvb, offset, hf_smb_share_access, ett_smb_nt_share_access, fields, mask); + + if (len == 0) + proto_item_set_generated(item); + + offset += len; + + return offset; +} + +int +dissect_nt_share_access(tvbuff_t *tvb, proto_tree *parent_tree, int offset) +{ + guint32 mask; + + mask = tvb_get_letohl(tvb, offset); + + offset = dissect_nt_share_access_bits(tvb, parent_tree, offset, 4, mask); + + return offset; +} + + +static int +dissect_nt_create_options_bits(tvbuff_t *tvb, proto_tree *parent_tree, + int offset, int len, guint32 mask) +{ + proto_item *item; + /* + * From + * + * http://www.samba.org/samba/ftp/specs/smb-nt01.doc + */ + static int * const fields[] = { + &hf_smb_nt_create_options_directory_file, + &hf_smb_nt_create_options_write_through, + &hf_smb_nt_create_options_sequential_only, + &hf_smb_nt_create_options_no_intermediate_buffering, + &hf_smb_nt_create_options_sync_io_alert, + &hf_smb_nt_create_options_sync_io_nonalert, + &hf_smb_nt_create_options_non_directory_file, + &hf_smb_nt_create_options_create_tree_connection, + &hf_smb_nt_create_options_complete_if_oplocked, + &hf_smb_nt_create_options_no_ea_knowledge, + &hf_smb_nt_create_options_eight_dot_three_only, + &hf_smb_nt_create_options_random_access, + &hf_smb_nt_create_options_delete_on_close, + &hf_smb_nt_create_options_open_by_fileid, + &hf_smb_nt_create_options_backup_intent, + &hf_smb_nt_create_options_no_compression, + &hf_smb_nt_create_options_reserve_opfilter, + &hf_smb_nt_create_options_open_reparse_point, + &hf_smb_nt_create_options_open_no_recall, + &hf_smb_nt_create_options_open_for_free_space_query, + NULL + }; + + item = proto_tree_add_bitmask_value_with_flags(parent_tree, tvb, offset, hf_smb_create_options, ett_smb_nt_create_options, fields, mask, BMT_NO_APPEND); + if (len == 0) + proto_item_set_generated(item); + + offset += len; + + return offset; +} + +int +dissect_nt_create_options(tvbuff_t *tvb, proto_tree *parent_tree, int offset) +{ + guint32 mask; + + mask = tvb_get_letohl(tvb, offset); + + offset = dissect_nt_create_options_bits(tvb, parent_tree, offset, 4, mask); + + return offset; +} + + +/* fids are scoped by tcp session */ +smb_fid_info_t * +dissect_smb_fid(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int offset, + int len, guint16 fid, gboolean is_created, gboolean is_closed, gboolean is_generated, smb_info_t* si) +{ + smb_saved_info_t *sip; + proto_item *it; + proto_tree *tr; + smb_fid_info_t *fid_info = NULL; + smb_fid_info_t *suspect_fid_info = NULL; + /* We need this to use an array-accessed tree */ + GSList *GSL_iterator; + + DISSECTOR_ASSERT(si); + + sip = si->sip; + + it = proto_tree_add_uint(tree, hf_smb_fid, tvb, offset, len, fid); + if (is_generated) { + proto_item_set_generated(it); + } + tr = proto_item_add_subtree(it, ett_smb_fid); + col_append_fstr(pinfo->cinfo, COL_INFO, ", FID: 0x%04x", fid); + + if ((!pinfo->fd->visited) && is_created) { + fid_info = wmem_new(wmem_file_scope(), smb_fid_info_t); + fid_info->opened_in = pinfo->num; + fid_info->closed_in = 0; + fid_info->type = SMB_FID_TYPE_UNKNOWN; + fid_info->fid = fid; + fid_info->tid = si->tid; + if (si->sip && (si->sip->extra_info_type == SMB_EI_FILEDATA)) { + fid_info->fsi = (smb_fid_saved_info_t *)si->sip->extra_info; + } else { + fid_info->fsi = NULL; + } + /* We don't use the fid_tree anymore to access and + maintain the fid information of analyzed files. + (was wmem_tree_insert32(si->ct->fid_tree, fid, fid_info);) + We'll use a single list instead to keep track of the + files (fid) opened. + Note that the insert_sorted function allows to insert duplicates + but being inside this if section should prevent it */ + si->ct->GSL_fid_info = g_slist_insert_sorted( + si->ct->GSL_fid_info, + fid_info, + (GCompareFunc)fid_cmp); + } + + if (!fid_info) { + /* we use the single linked list to access this fid_info + (was fid_info = wmem_tree_lookup32(si->ct->fid_tree, fid);) */ + GSL_iterator = si->ct->GSL_fid_info; + while (GSL_iterator) { + suspect_fid_info = (smb_fid_info_t *)GSL_iterator->data; + if (suspect_fid_info->opened_in > pinfo->num) break; + if ((suspect_fid_info->tid == si->tid) && (suspect_fid_info->fid == fid)) + fid_info = (smb_fid_info_t *)suspect_fid_info; + GSL_iterator = g_slist_next(GSL_iterator); + } + } + if (!fid_info) { + return NULL; + } + + /* Store the fid in the transaction structure and remember if + it was in the request or in the reply we saw it + */ + if (sip && (!is_generated) && (!pinfo->fd->visited)) { + sip->fid = fid; + if (si->request) { + sip->fid_seen_in_request = TRUE; + } else { + sip->fid_seen_in_request = FALSE; + } + } + + if ((!pinfo->fd->visited) && is_closed) { + fid_info->closed_in = pinfo->num; + } + + if (fid_info->opened_in) { + it = proto_tree_add_uint(tr, hf_smb_opened_in, tvb, 0, 0, fid_info->opened_in); + proto_item_set_generated(it); + } + + if (fid_info->closed_in) { + it = proto_tree_add_uint(tr, hf_smb_closed_in, tvb, 0, 0, fid_info->closed_in); + proto_item_set_generated(it); + } + + + if (fid_info->opened_in) { + if (fid_info->fsi && fid_info->fsi->filename) { + it = proto_tree_add_string(tr, hf_smb_file_name, tvb, 0, 0, fid_info->fsi->filename); + proto_item_set_generated(it); + proto_item_append_text(tr, " (%s)", fid_info->fsi->filename); + dissect_nt_create_bits(tvb, tr, 0, 0, fid_info->fsi->create_flags); + dissect_smb_access_mask_bits(tvb, tr, 0, 0, fid_info->fsi->access_mask); + dissect_file_ext_attr_bits(tvb, tr, 0, 0, fid_info->fsi->file_attributes); + dissect_nt_share_access_bits(tvb, tr, 0, 0, fid_info->fsi->share_access); + dissect_nt_create_options_bits(tvb, tr, 0, 0, fid_info->fsi->create_options); + it = proto_tree_add_uint(tr, hf_smb_nt_create_disposition, tvb, 0, 0, fid_info->fsi->create_disposition); + proto_item_set_generated(it); + } + } + + return fid_info; +} + +static int +dissect_open_file_response(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int offset, proto_tree *smb_tree _U_, smb_info_t *si) +{ + guint8 wc; + guint16 bc; + guint16 fid; + smb_fid_info_t *fid_info = NULL; /* eo_smb needs to track this info */ + guint16 fattr; + gboolean isdir = FALSE; + + WORD_COUNT; + + /* fid */ + fid = tvb_get_letohs(tvb, offset); + + fid_info = dissect_smb_fid(tvb, pinfo, tree, offset, 2, fid, TRUE, FALSE, FALSE, si); + if (fid_info) { + /* This command is used to create and open a new file or open + and truncate an existing file to zero length */ + fid_info->end_of_file = 0; + if (fid_info->fsi) { + /* File Type */ + fattr = fid_info->fsi->file_attributes; + /* XXX Volumes considered as directories */ + isdir = (fattr & SMB_FILE_ATTRIBUTE_DIRECTORY) || (fattr & SMB_FILE_ATTRIBUTE_VOLUME); + if (isdir == 0) { + fid_info->type = SMB_FID_TYPE_FILE; + } else { + fid_info->type = SMB_FID_TYPE_DIR; + } + } + } + + offset += 2; + + /* File Attributes */ + offset = dissect_file_attributes(tvb, tree, offset); + + /* last write time */ + offset = dissect_smb_UTIME(tvb, tree, offset, hf_smb_last_write_time); + + /* File Size */ + proto_tree_add_item(tree, hf_smb_file_size, tvb, offset, 4, ENC_LITTLE_ENDIAN); + offset += 4; + + /* granted access */ + offset = dissect_access(tvb, tree, offset, hf_smb_granted_access); + + BYTE_COUNT; + + END_OF_SMB + + return offset; +} + +static int +dissect_query_information2_request(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int offset, proto_tree *smb_tree _U_, smb_info_t *si) +{ + guint8 wc; + guint16 bc; + guint16 fid; + + WORD_COUNT; + + /* fid */ + fid = tvb_get_letohs(tvb, offset); + dissect_smb_fid(tvb, pinfo, tree, offset, 2, fid, FALSE, FALSE, FALSE, si); + offset += 2; + + BYTE_COUNT; + + END_OF_SMB + + return offset; +} + +static int +dissect_close_print_file_request(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int offset, proto_tree *smb_tree _U_, smb_info_t *si) +{ + guint8 wc; + guint16 bc; + guint16 fid; + + WORD_COUNT; + + /* fid */ + fid = tvb_get_letohs(tvb, offset); + dissect_smb_fid(tvb, pinfo, tree, offset, 2, fid, FALSE, TRUE, FALSE, si); + offset += 2; + + BYTE_COUNT; + + END_OF_SMB + + return offset; +} + +static int +dissect_open_print_file_response(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int offset, proto_tree *smb_tree _U_, smb_info_t *si) +{ + guint8 wc; + guint16 bc; + guint16 fid; + + WORD_COUNT; + + /* fid */ + fid = tvb_get_letohs(tvb, offset); + dissect_smb_fid(tvb, pinfo, tree, offset, 2, fid, FALSE, FALSE, FALSE, si); + offset += 2; + + BYTE_COUNT; + + END_OF_SMB + + return offset; +} + +static int +dissect_create_new_response(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int offset, proto_tree *smb_tree _U_, smb_info_t *si) +{ + guint8 wc; + guint16 bc; + guint16 fid; + + WORD_COUNT; + + /* fid */ + fid = tvb_get_letohs(tvb, offset); + dissect_smb_fid(tvb, pinfo, tree, offset, 2, fid, TRUE, FALSE, FALSE, si); + offset += 2; + + BYTE_COUNT; + + END_OF_SMB + + return offset; +} + +static int +dissect_flush_file_request(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int offset, proto_tree *smb_tree _U_, smb_info_t *si) +{ + guint8 wc; + guint16 bc; + guint16 fid; + + WORD_COUNT; + + /* fid */ + fid = tvb_get_letohs(tvb, offset); + dissect_smb_fid(tvb, pinfo, tree, offset, 2, fid, FALSE, FALSE, FALSE, si); + offset += 2; + + BYTE_COUNT; + + END_OF_SMB + + return offset; +} + +static int +dissect_create_file_response(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int offset, proto_tree *smb_tree _U_, smb_info_t *si) +{ + guint8 wc; + guint16 bc; + guint16 fid; + smb_fid_info_t *fid_info = NULL; /* eo_smb needs to track this info */ + guint16 fattr; + gboolean isdir = FALSE; + + WORD_COUNT; + + /* fid */ + fid = tvb_get_letohs(tvb, offset); + fid_info = dissect_smb_fid(tvb, pinfo, tree, offset, 2, fid, TRUE, FALSE, FALSE, si); + if (fid_info) { + /* This command is used to create and open a new file or open + and truncate an existing file to zero length */ + fid_info->end_of_file = 0; + if (fid_info->fsi) { + /* File Type */ + fattr = fid_info->fsi->file_attributes; + /* XXX Volumes considered as directories */ + isdir = (fattr & SMB_FILE_ATTRIBUTE_DIRECTORY) || (fattr & SMB_FILE_ATTRIBUTE_VOLUME); + if (isdir == 0) { + fid_info->type = SMB_FID_TYPE_FILE; + } else { + fid_info->type = SMB_FID_TYPE_DIR; + } + } + } + + offset += 2; + + BYTE_COUNT; + + END_OF_SMB + + return offset; +} + +static int +dissect_create_file_request(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int offset, proto_tree *smb_tree _U_, smb_info_t *si) +{ + int fn_len; + const char *fn; + guint8 wc; + guint16 bc; + smb_fid_saved_info_t *fsi; /* eo_smb needs to track this info */ + guint32 file_attributes = 0; + + DISSECTOR_ASSERT(si); + + WORD_COUNT; + + /* file attributes */ + /* We read the two lower bytes into the four-bytes file-attributes, because they are compatible */ + file_attributes = tvb_get_letohs(tvb, offset); + offset = dissect_file_attributes(tvb, tree, offset); + + /* creation time */ + offset = dissect_smb_UTIME(tvb, tree, offset, hf_smb_create_time); + + BYTE_COUNT; + + /* buffer format */ + CHECK_BYTE_COUNT(1); + proto_tree_add_item(tree, hf_smb_buffer_format, tvb, offset, 1, ENC_LITTLE_ENDIAN); + COUNT_BYTES(1); + + /* File Name */ + fn = get_unicode_or_ascii_string(tvb, &offset, si->unicode, &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); + + /* store it for the fid->name/openframe/closeframe matching in + * dissect_smb_fid() called from the response. + */ + if ((!pinfo->fd->visited) && si->sip && fn) { + fsi = wmem_new0(wmem_file_scope(), smb_fid_saved_info_t); + fsi->filename = wmem_strdup(wmem_file_scope(), fn); + fsi->file_attributes = file_attributes; + + si->sip->extra_info_type = SMB_EI_FILEDATA; + si->sip->extra_info = fsi; + } + + + col_append_fstr(pinfo->cinfo, COL_INFO, ", Path: %s", + format_text(wmem_packet_scope(), (const guchar*)fn, strlen(fn))); + + END_OF_SMB + + return offset; +} + +static int +dissect_close_file_request(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int offset, proto_tree *smb_tree _U_, smb_info_t *si) +{ + guint8 wc; + guint16 bc, fid; + + WORD_COUNT; + + /* fid */ + fid = tvb_get_letohs(tvb, offset); + dissect_smb_fid(tvb, pinfo, tree, offset, 2, fid, FALSE, TRUE, FALSE, si); + offset += 2; + + /* last write time */ + offset = dissect_smb_UTIME(tvb, tree, offset, hf_smb_last_write_time); + + BYTE_COUNT; + + END_OF_SMB + + return offset; +} + +static int +dissect_delete_file_request(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int offset, proto_tree *smb_tree _U_, smb_info_t *si) +{ + int fn_len; + const char *fn; + guint8 wc; + guint16 bc; + + DISSECTOR_ASSERT(si); + + WORD_COUNT; + + /* search attributes */ + offset = dissect_search_attributes(tvb, tree, offset); + + BYTE_COUNT; + + /* buffer format */ + CHECK_BYTE_COUNT(1); + proto_tree_add_item(tree, hf_smb_buffer_format, tvb, offset, 1, ENC_LITTLE_ENDIAN); + COUNT_BYTES(1); + + /* file name */ + fn = get_unicode_or_ascii_string(tvb, &offset, si->unicode, &fn_len, + FALSE, FALSE, &bc); + + if ((!pinfo->fd->visited) && si->sip) { + si->sip->extra_info_type = SMB_EI_FILENAME; + si->sip->extra_info = wmem_strdup(wmem_file_scope(), fn); + } + + if (fn == NULL) + goto endofcommand; + proto_tree_add_string(tree, hf_smb_file_name, tvb, offset, fn_len, + fn); + COUNT_BYTES(fn_len); + + col_append_fstr(pinfo->cinfo, COL_INFO, ", Path: %s", + format_text(wmem_packet_scope(), (const guchar*)fn, strlen(fn))); + + END_OF_SMB + + return offset; +} + +static int +dissect_rename_file_request(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int offset, proto_tree *smb_tree _U_, smb_info_t *si) +{ + int fn_len; + const char *fn, *old_name = NULL, *new_name = NULL; + guint8 wc; + guint16 bc; + smb_rename_saved_info_t *rni = NULL; + + DISSECTOR_ASSERT(si); + + WORD_COUNT; + + /* search attributes */ + offset = dissect_search_attributes(tvb, tree, offset); + + BYTE_COUNT; + + /* buffer format */ + CHECK_BYTE_COUNT(1); + proto_tree_add_item(tree, hf_smb_buffer_format, tvb, offset, 1, ENC_LITTLE_ENDIAN); + COUNT_BYTES(1); + + /* old file name */ + fn = get_unicode_or_ascii_string(tvb, &offset, si->unicode, &fn_len, + FALSE, FALSE, &bc); + if (fn == NULL) + goto endofcommand; + old_name = fn; + proto_tree_add_string(tree, hf_smb_old_file_name, tvb, offset, fn_len, + fn); + COUNT_BYTES(fn_len); + + col_append_fstr(pinfo->cinfo, COL_INFO, ", Old Name: %s", + format_text(wmem_packet_scope(), (const guchar*)fn, strlen(fn))); + + /* buffer format */ + CHECK_BYTE_COUNT(1); + proto_tree_add_item(tree, hf_smb_buffer_format, tvb, offset, 1, ENC_LITTLE_ENDIAN); + COUNT_BYTES(1); + + /* file name */ + fn = get_unicode_or_ascii_string(tvb, &offset, si->unicode, &fn_len, + FALSE, FALSE, &bc); + if (fn == NULL) + goto endofcommand; + new_name = fn; + proto_tree_add_string(tree, hf_smb_file_name, tvb, offset, fn_len, + fn); + COUNT_BYTES(fn_len); + + col_append_fstr(pinfo->cinfo, COL_INFO, ", New Name: %s", + format_text(wmem_packet_scope(), (const guchar*)fn, strlen(fn))); + + END_OF_SMB + + /* save the offset/len for this transaction */ + if (si->sip && !pinfo->fd->visited) { + rni = wmem_new(wmem_file_scope(), smb_rename_saved_info_t); + rni->old_name = wmem_strdup(wmem_file_scope(), old_name); + rni->new_name = wmem_strdup(wmem_file_scope(), new_name); + + si->sip->extra_info_type = SMB_EI_RENAMEDATA; + si->sip->extra_info = rni; + } + + return offset; +} + +static int +dissect_nt_rename_file_request(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int offset, proto_tree *smb_tree _U_, smb_info_t *si) +{ + int fn_len; + const char *fn; + guint8 wc; + guint16 bc; + + DISSECTOR_ASSERT(si); + + WORD_COUNT; + + /* search attributes */ + offset = dissect_search_attributes(tvb, tree, offset); + + proto_tree_add_item(tree, hf_smb_nt_rename_level, tvb, offset, 2, ENC_LITTLE_ENDIAN); + offset += 2; + + proto_tree_add_item(tree, hf_smb_cluster_count, tvb, offset, 4, ENC_LITTLE_ENDIAN); + offset += 4; + + BYTE_COUNT; + + /* buffer format */ + CHECK_BYTE_COUNT(1); + proto_tree_add_item(tree, hf_smb_buffer_format, tvb, offset, 1, ENC_LITTLE_ENDIAN); + COUNT_BYTES(1); + + /* old file name */ + fn = get_unicode_or_ascii_string(tvb, &offset, si->unicode, &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); + + col_append_fstr(pinfo->cinfo, COL_INFO, ", Old Name: %s", + format_text(wmem_packet_scope(), (const guchar*)fn, strlen(fn))); + + /* buffer format */ + CHECK_BYTE_COUNT(1); + proto_tree_add_item(tree, hf_smb_buffer_format, tvb, offset, 1, ENC_LITTLE_ENDIAN); + COUNT_BYTES(1); + + /* file name */ + fn = get_unicode_or_ascii_string(tvb, &offset, si->unicode, &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); + + col_append_fstr(pinfo->cinfo, COL_INFO, ", New Name: %s", + format_text(wmem_packet_scope(), (const guchar*)fn, strlen(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 _U_, smb_info_t *si) +{ + guint16 bc; + guint8 wc; + const char *fn; + int fn_len; + + DISSECTOR_ASSERT(si); + + WORD_COUNT; + + BYTE_COUNT; + + /* Buffer Format */ + CHECK_BYTE_COUNT(1); + proto_tree_add_item(tree, hf_smb_buffer_format, tvb, offset, 1, ENC_LITTLE_ENDIAN); + COUNT_BYTES(1); + + /* File Name */ + fn = get_unicode_or_ascii_string(tvb, &offset, si->unicode, &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); + + col_append_fstr(pinfo->cinfo, COL_INFO, ", Path: %s", + format_text(wmem_packet_scope(), (const guchar*)fn, strlen(fn))); + + END_OF_SMB + + return offset; +} + +static int +dissect_query_information_response(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, int offset, proto_tree *smb_tree _U_, smb_info_t *si _U_) +{ + guint16 bc; + guint8 wc; + + WORD_COUNT; + + /* File Attributes */ + offset = dissect_file_attributes(tvb, tree, offset); + + /* Last Write Time */ + offset = dissect_smb_UTIME(tvb, tree, offset, hf_smb_last_write_time); + + /* File Size */ + proto_tree_add_item(tree, hf_smb_file_size, tvb, offset, 4, ENC_LITTLE_ENDIAN); + offset += 4; + + /* 10 reserved bytes */ + proto_tree_add_item(tree, hf_smb_reserved, tvb, offset, 10, ENC_NA); + offset += 10; + + BYTE_COUNT; + + END_OF_SMB + + return offset; +} + +static int +dissect_set_information_request(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int offset, proto_tree *smb_tree _U_, smb_info_t *si) +{ + int fn_len; + const char *fn; + guint8 wc; + guint16 bc; + + DISSECTOR_ASSERT(si); + + WORD_COUNT; + + /* file attributes */ + offset = dissect_file_attributes(tvb, tree, offset); + + /* last write time */ + offset = dissect_smb_UTIME(tvb, tree, offset, hf_smb_last_write_time); + + /* 10 reserved bytes */ + proto_tree_add_item(tree, hf_smb_reserved, tvb, offset, 10, ENC_NA); + offset += 10; + + BYTE_COUNT; + + /* buffer format */ + CHECK_BYTE_COUNT(1); + proto_tree_add_item(tree, hf_smb_buffer_format, tvb, offset, 1, ENC_LITTLE_ENDIAN); + COUNT_BYTES(1); + + /* file name */ + fn = get_unicode_or_ascii_string(tvb, &offset, si->unicode, &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); + + col_append_fstr(pinfo->cinfo, COL_INFO, ", Path: %s", + format_text(wmem_packet_scope(), (const guchar*)fn, strlen(fn))); + + END_OF_SMB + + return offset; +} + +typedef struct _rw_info_t { + guint64 offset; + guint32 len; + guint16 fid; +} rw_info_t; + +static int +dissect_read_file_request(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int offset, proto_tree *smb_tree _U_, smb_info_t *si) +{ + guint8 wc; + guint16 cnt = 0, bc; + guint32 ofs = 0; + unsigned int fid; + rw_info_t *rwi = NULL; + + WORD_COUNT; + + /* fid */ + fid = tvb_get_letohs(tvb, offset); + dissect_smb_fid(tvb, pinfo, tree, offset, 2, (guint16) fid, FALSE, FALSE, FALSE, si); + offset += 2; + + /* read count */ + cnt = tvb_get_letohs(tvb, offset); + proto_tree_add_item(tree, hf_smb_count, tvb, offset, 2, ENC_LITTLE_ENDIAN); + offset += 2; + + /* offset */ + ofs = tvb_get_letohl(tvb, offset); + proto_tree_add_item(tree, hf_smb_offset, tvb, offset, 4, ENC_LITTLE_ENDIAN); + offset += 4; + + col_append_fstr(pinfo->cinfo, COL_INFO, + ", %u byte%s at offset %u", cnt, + (cnt == 1) ? "" : "s", ofs); + + /* remaining */ + proto_tree_add_item(tree, hf_smb_remaining, tvb, offset, 2, ENC_LITTLE_ENDIAN); + offset += 2; + + /* save the offset/len for this transaction */ + if (si->sip && !pinfo->fd->visited) { + rwi = wmem_new(wmem_file_scope(), rw_info_t); + rwi->offset = ofs; + rwi->len = cnt; + rwi->fid = fid; + si->sip->extra_info_type = SMB_EI_RWINFO; + si->sip->extra_info = rwi; + } + + BYTE_COUNT; + + END_OF_SMB + + return offset; +} + +int +dissect_file_data(tvbuff_t *tvb, proto_tree *tree, int offset, guint16 bc, int dataoffset, guint16 datalen) +{ + int tvblen; + + 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, + ENC_NA); + offset += bc-datalen; + bc = datalen; + } + tvblen = tvb_reported_length_remaining(tvb, dataoffset > 0 ? dataoffset : offset ); + if (bc > tvblen) { + proto_tree_add_bytes_format_value(tree, hf_smb_file_data, tvb, dataoffset > 0 ? dataoffset : offset, tvblen, NULL, "Incomplete. Only %d of %u bytes", tvblen, bc); + if (dataoffset == -1 || dataoffset == offset) + offset += tvblen; + } else { + proto_tree_add_item(tree, hf_smb_file_data, tvb, dataoffset > 0 ? dataoffset : offset, bc, ENC_NA); + if (dataoffset == -1 || dataoffset == offset) + offset += bc; + } + 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, + void *data) +{ + 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, + ENC_NA); + offset += bc-datalen; + bc = datalen; + } + tvblen = tvb_reported_length_remaining(tvb, offset); + dcerpc_tvb = tvb_new_subset_length_caplen(tvb, offset, tvblen, bc); + dissect_pipe_dcerpc(dcerpc_tvb, pinfo, top_tree, tree, fid, data); + if (bc > tvblen) + offset += tvblen; + else + offset += bc; + return offset; +} + +/* + * transporting DCERPC over SMB seems to be implemented in various + * ways. We might just assume it can be done by an almost random + * mix of Trans/Read/Write calls + * + * if we suspect dcerpc, just send them all down to packet-smb-pipe.c + * and let him sort them out + */ +static int +dissect_file_data_maybe_dcerpc(tvbuff_t *tvb, packet_info *pinfo, + proto_tree *tree, proto_tree *top_tree, int offset, guint16 bc, + int dataoffset, guint16 datalen, guint32 ofs, guint16 fid, smb_info_t *si) +{ + DISSECTOR_ASSERT(si); + + if ( (si->sip && (si->sip->flags & SMB_SIF_TID_IS_IPC)) && (ofs == 0) ) { + /* dcerpc call */ + /* XXX - use the data offset to determine where the data starts? */ + return dissect_file_data_dcerpc(tvb, pinfo, tree, + top_tree, offset, bc, datalen, fid, si); + } else { + /* ordinary file data */ + return dissect_file_data(tvb, tree, offset, bc, dataoffset, datalen); + } +} + +static int +dissect_read_file_response(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int offset, proto_tree *smb_tree _U_, smb_info_t *si) +{ + guint16 cnt = 0, bc; + guint8 wc; + int fid = 0; + guint32 datalen = 0, dataoffset = 0; + guint32 tvblen; + rw_info_t *rwi = NULL; + + DISSECTOR_ASSERT(si); + + WORD_COUNT; + + /* read count */ + cnt = tvb_get_letohs(tvb, offset); + proto_tree_add_uint(tree, hf_smb_count, tvb, offset, 2, cnt); + offset += 2; + + /* 8 reserved bytes */ + proto_tree_add_item(tree, hf_smb_reserved, tvb, offset, 8, ENC_NA); + offset += 8; + BYTE_COUNT; + + /* buffer format */ + CHECK_BYTE_COUNT(1); + proto_tree_add_item(tree, hf_smb_buffer_format, tvb, offset, 1, ENC_LITTLE_ENDIAN); + COUNT_BYTES(1); + + /* data len */ + CHECK_BYTE_COUNT(2); + proto_tree_add_item(tree, hf_smb_data_len, tvb, offset, 2, ENC_LITTLE_ENDIAN); + datalen = tvb_get_letohs(tvb, offset); + COUNT_BYTES(2); + dataoffset = offset; + + /* file data, might be DCERPC on a pipe */ + if (bc) { + offset = dissect_file_data_maybe_dcerpc(tvb, pinfo, tree, + top_tree_global, offset, bc, -1, bc, 0, (guint16) fid, si); + bc = 0; + } + + /* If we have seen the request, then print which FID this refers to */ + if ((si->sip != NULL) && (si->sip->frame_req > 0) && (si->sip->extra_info_type == SMB_EI_FID)) { + fid = GPOINTER_TO_INT(si->sip->extra_info); + } + + if (si->sip && (si->sip->extra_info_type == SMB_EI_RWINFO)) { + rwi = (rw_info_t *)si->sip->extra_info; + } + if (rwi) { + proto_item *it; + + it = proto_tree_add_uint64(tree, hf_smb_file_rw_offset, tvb, 0, 0, rwi->offset); + + proto_item_set_generated(it); + it = proto_tree_add_uint(tree, hf_smb_file_rw_length, tvb, 0, 0, rwi->len); + proto_item_set_generated(it); + + /* we need the fid for the call to dcerpc below */ + fid = rwi->fid; + } + + /* feed the export object tap listener */ + tvblen = tvb_reported_length_remaining(tvb, dataoffset); + if (have_tap_listener(smb_eo_tap) && (datalen == tvblen) && rwi) { + feed_eo_smb(SMB_COM_READ, fid, tvb, pinfo, dataoffset, datalen, rwi->len, rwi->offset, si); + } + + END_OF_SMB + + return offset; +} + +static int +dissect_lock_and_read_response(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, int offset, proto_tree *smb_tree _U_, smb_info_t *si _U_) +{ + guint16 cnt, bc; + guint8 wc; + + WORD_COUNT; + + /* read count */ + cnt = tvb_get_letohs(tvb, offset); + proto_tree_add_uint(tree, hf_smb_count, tvb, offset, 2, cnt); + offset += 2; + + /* 8 reserved bytes */ + proto_tree_add_item(tree, hf_smb_reserved, tvb, offset, 8, ENC_NA); + offset += 8; + + BYTE_COUNT; + + /* buffer format */ + CHECK_BYTE_COUNT(1); + proto_tree_add_item(tree, hf_smb_buffer_format, tvb, offset, 1, ENC_LITTLE_ENDIAN); + COUNT_BYTES(1); + + /* data len */ + CHECK_BYTE_COUNT(2); + proto_tree_add_item(tree, hf_smb_data_len, tvb, offset, 2, ENC_LITTLE_ENDIAN); + COUNT_BYTES(2); + + END_OF_SMB + + return offset; +} + + + +static int +dissect_write_file_request(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int offset, proto_tree *smb_tree _U_, smb_info_t *si) +{ + guint32 ofs = 0; + guint16 cnt = 0, bc, fid = 0; + guint8 wc; + rw_info_t *rwi = NULL; + guint32 datalen = 0, dataoffset = 0; + guint32 tvblen; + + DISSECTOR_ASSERT(si); + + WORD_COUNT; + + /* fid */ + fid = tvb_get_letohs(tvb, offset); + dissect_smb_fid(tvb, pinfo, tree, offset, 2, fid, FALSE, FALSE, FALSE, si); + offset += 2; + + /* write count */ + cnt = tvb_get_letohs(tvb, offset); + datalen = cnt; + proto_tree_add_uint(tree, hf_smb_count, tvb, offset, 2, cnt); + offset += 2; + + /* offset */ + ofs = tvb_get_letohl(tvb, offset); + proto_tree_add_item(tree, hf_smb_offset, tvb, offset, 4, ENC_LITTLE_ENDIAN); + offset += 4; + + col_append_fstr(pinfo->cinfo, COL_INFO, + ", %u byte%s at offset %u", cnt, + (cnt == 1) ? "" : "s", ofs); + + /* save the offset/len for this transaction */ + if (si->sip && !pinfo->fd->visited) { + rwi = wmem_new(wmem_file_scope(), rw_info_t); + rwi->offset = ofs; + rwi->len = cnt; + rwi->fid = fid; + + si->sip->extra_info_type = SMB_EI_RWINFO; + si->sip->extra_info = rwi; + } + if (si->sip && (si->sip->extra_info_type == SMB_EI_RWINFO)) { + rwi = (rw_info_t *)si->sip->extra_info; + } + if (rwi) { + proto_item *it; + + it = proto_tree_add_uint64(tree, hf_smb_file_rw_offset, tvb, 0, 0, rwi->offset); + + proto_item_set_generated(it); + it = proto_tree_add_uint(tree, hf_smb_file_rw_length, tvb, 0, 0, rwi->len); + proto_item_set_generated(it); + } + + /* remaining */ + proto_tree_add_item(tree, hf_smb_remaining, tvb, offset, 2, ENC_LITTLE_ENDIAN); + offset += 2; + + BYTE_COUNT; + + /* buffer format */ + CHECK_BYTE_COUNT(1); + proto_tree_add_item(tree, hf_smb_buffer_format, tvb, offset, 1, ENC_LITTLE_ENDIAN); + COUNT_BYTES(1); + + /* data len */ + CHECK_BYTE_COUNT(2); + proto_tree_add_item(tree, hf_smb_data_len, tvb, offset, 2, ENC_LITTLE_ENDIAN); + COUNT_BYTES(2); + dataoffset = offset; + + /* file data, might be DCERPC on a pipe */ + if (bc != 0) { + offset = dissect_file_data_maybe_dcerpc(tvb, pinfo, tree, + top_tree_global, offset, bc, -1, bc, ofs, fid, si); + bc = 0; + } + + /* feed the export object tap listener */ + tvblen = tvb_reported_length_remaining(tvb, dataoffset); + if (have_tap_listener(smb_eo_tap) && (datalen == tvblen) && rwi) { + feed_eo_smb(SMB_COM_WRITE, fid, tvb, pinfo, dataoffset, datalen, rwi->len, rwi->offset, si); + } + + END_OF_SMB + + return offset; +} + +static int +dissect_write_file_response(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int offset, proto_tree *smb_tree _U_, smb_info_t *si) +{ + guint8 wc; + guint16 bc, cnt; + rw_info_t *rwi = NULL; + + DISSECTOR_ASSERT(si); + + WORD_COUNT; + + /* write count */ + cnt = tvb_get_letohs(tvb, offset); + proto_tree_add_item(tree, hf_smb_count, tvb, offset, 2, ENC_LITTLE_ENDIAN); + offset += 2; + + col_append_fstr(pinfo->cinfo, COL_INFO, + ", %u byte%s", cnt, (cnt == 1) ? "" : "s"); + + if (si->sip && (si->sip->extra_info_type == SMB_EI_RWINFO)) { + rwi = (rw_info_t *)si->sip->extra_info; + } + if (rwi) { + proto_item *it; + + it = proto_tree_add_uint64(tree, hf_smb_file_rw_offset, tvb, 0, 0, rwi->offset); + + proto_item_set_generated(it); + it = proto_tree_add_uint(tree, hf_smb_file_rw_length, tvb, 0, 0, rwi->len); + proto_item_set_generated(it); + } + + BYTE_COUNT; + + END_OF_SMB + + return offset; +} + +static int +dissect_lock_request(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int offset, proto_tree *smb_tree _U_, smb_info_t *si) +{ + guint8 wc; + guint16 bc, fid; + + WORD_COUNT; + + /* fid */ + fid = tvb_get_letohs(tvb, offset); + dissect_smb_fid(tvb, pinfo, tree, offset, 2, fid, FALSE, FALSE, FALSE, si); + offset += 2; + + /* lock count */ + proto_tree_add_item(tree, hf_smb_count, tvb, offset, 4, ENC_LITTLE_ENDIAN); + offset += 4; + + /* offset */ + proto_tree_add_item(tree, hf_smb_offset, tvb, offset, 4, ENC_LITTLE_ENDIAN); + offset += 4; + + BYTE_COUNT; + + END_OF_SMB + + return offset; +} + +static int +dissect_create_temporary_request(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int offset, proto_tree *smb_tree _U_, smb_info_t *si) +{ + int fn_len; + const char *fn; + guint8 wc; + guint16 bc; + + DISSECTOR_ASSERT(si); + + WORD_COUNT; + + /* 2 reserved bytes */ + proto_tree_add_item(tree, hf_smb_reserved, tvb, offset, 2, ENC_NA); + offset += 2; + + /* Creation time */ + offset = dissect_smb_UTIME(tvb, tree, offset, hf_smb_create_time); + + BYTE_COUNT; + + /* buffer format */ + CHECK_BYTE_COUNT(1); + proto_tree_add_item(tree, hf_smb_buffer_format, tvb, offset, 1, ENC_LITTLE_ENDIAN); + COUNT_BYTES(1); + + /* + * Directory name. + * + * MS-CIFS says this is a "null-terminated string", without saying + * it's always ASCII, so we honor the "Unicode strings" flag. + */ + fn = get_unicode_or_ascii_string(tvb, &offset, si->unicode, &fn_len, + FALSE, FALSE, &bc); + if (fn == NULL) + goto endofcommand; + proto_tree_add_string(tree, hf_smb_dir_name, tvb, offset, fn_len, + fn); + COUNT_BYTES(fn_len); + + col_append_fstr(pinfo->cinfo, COL_INFO, ", Path: %s", + format_text(wmem_packet_scope(), (const guchar*)fn, strlen(fn))); + + END_OF_SMB + + return offset; +} + +static int +dissect_create_temporary_response(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int offset, proto_tree *smb_tree _U_, smb_info_t *si) +{ + int fn_len; + const char *fn; + guint8 wc; + guint16 bc, fid; + + DISSECTOR_ASSERT(si); + + WORD_COUNT; + + /* fid */ + fid = tvb_get_letohs(tvb, offset); + dissect_smb_fid(tvb, pinfo, tree, offset, 2, fid, TRUE, FALSE, FALSE, si); + offset += 2; + + BYTE_COUNT; + + /* + * File name. + * + * MS-CIFS says "The string SHOULD be a null-terminated array of + * ASCII characters.", so we ignore the "Unicode strings" flag. + */ + fn = get_unicode_or_ascii_string(tvb, &offset, FALSE, &fn_len, + TRUE, 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); + + END_OF_SMB + + return offset; +} + +static const value_string seek_mode_vals[] = { + {0, "From Start Of File"}, + {1, "From Current Position"}, + {2, "From End Of File"}, + {0, NULL} +}; + +static int +dissect_seek_file_request(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int offset, proto_tree *smb_tree _U_, smb_info_t *si) +{ + guint8 wc; + guint16 bc, fid; + + WORD_COUNT; + + /* fid */ + fid = tvb_get_letohs(tvb, offset); + dissect_smb_fid(tvb, pinfo, tree, offset, 2, fid, FALSE, FALSE, FALSE, si); + offset += 2; + + /* Seek Mode */ + proto_tree_add_item(tree, hf_smb_seek_mode, tvb, offset, 2, ENC_LITTLE_ENDIAN); + offset += 2; + + /* offset */ + proto_tree_add_item(tree, hf_smb_offset, tvb, offset, 4, ENC_LITTLE_ENDIAN); + offset += 4; + + BYTE_COUNT; + + END_OF_SMB + + return offset; +} + +static int +dissect_seek_file_response(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, int offset, proto_tree *smb_tree _U_, smb_info_t *si _U_) +{ + guint8 wc; + guint16 bc; + + WORD_COUNT; + + /* offset */ + proto_tree_add_item(tree, hf_smb_offset, tvb, offset, 4, ENC_LITTLE_ENDIAN); + offset += 4; + + BYTE_COUNT; + + END_OF_SMB + + return offset; +} + +static int +dissect_set_information2_request(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int offset, proto_tree *smb_tree _U_, smb_info_t *si) +{ + guint8 wc; + guint16 bc, fid; + + WORD_COUNT; + + /* fid */ + fid = tvb_get_letohs(tvb, offset); + dissect_smb_fid(tvb, pinfo, tree, offset, 2, fid, FALSE, FALSE, FALSE, si); + offset += 2; + + /* create time */ + offset = dissect_smb_datetime(tvb, tree, offset, + hf_smb_create_time, + hf_smb_create_dos_date, hf_smb_create_dos_time, FALSE); + + /* access time */ + offset = dissect_smb_datetime(tvb, tree, offset, + hf_smb_access_time, + hf_smb_access_dos_date, hf_smb_access_dos_time, FALSE); + + /* last write time */ + offset = dissect_smb_datetime(tvb, tree, offset, + hf_smb_last_write_time, + hf_smb_last_write_dos_date, hf_smb_last_write_dos_time, FALSE); + + BYTE_COUNT; + + END_OF_SMB + + return offset; +} + +static int +dissect_query_information2_response(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, int offset, proto_tree *smb_tree _U_, smb_info_t *si _U_) +{ + guint8 wc; + guint16 bc; + + WORD_COUNT; + + /* create time */ + offset = dissect_smb_datetime(tvb, tree, offset, + hf_smb_create_time, + hf_smb_create_dos_date, hf_smb_create_dos_time, FALSE); + + /* access time */ + offset = dissect_smb_datetime(tvb, tree, offset, + hf_smb_access_time, + hf_smb_access_dos_date, hf_smb_access_dos_time, FALSE); + + /* last write time */ + offset = dissect_smb_datetime(tvb, tree, offset, + hf_smb_last_write_time, + hf_smb_last_write_dos_date, hf_smb_last_write_dos_time, FALSE); + + /* data size */ + proto_tree_add_item(tree, hf_smb_data_size, tvb, offset, 4, ENC_LITTLE_ENDIAN); + offset += 4; + + /* allocation size */ + proto_tree_add_item(tree, hf_smb_alloc_size, tvb, offset, 4, ENC_LITTLE_ENDIAN); + offset += 4; + + /* File Attributes */ + offset = dissect_file_attributes(tvb, tree, offset); + + BYTE_COUNT; + + END_OF_SMB + + return offset; +} + +static int +dissect_write_and_close_request(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int offset, proto_tree *smb_tree _U_, smb_info_t *si) +{ + guint8 wc; + guint16 cnt = 0; + guint16 bc, fid; + + WORD_COUNT; + + /* fid */ + fid = tvb_get_letohs(tvb, offset); + dissect_smb_fid(tvb, pinfo, tree, offset, 2, fid, FALSE, TRUE, FALSE, si); + offset += 2; + + /* write count */ + cnt = tvb_get_letohs(tvb, offset); + proto_tree_add_uint(tree, hf_smb_count, tvb, offset, 2, cnt); + offset += 2; + + /* offset */ + proto_tree_add_item(tree, hf_smb_offset, tvb, offset, 4, ENC_LITTLE_ENDIAN); + offset += 4; + + /* last write time */ + offset = dissect_smb_UTIME(tvb, tree, offset, hf_smb_last_write_time); + + if (wc == 12) { + /* 12 reserved bytes */ + proto_tree_add_item(tree, hf_smb_reserved, tvb, offset, 12, ENC_NA); + offset += 12; + } + + BYTE_COUNT; + + /* 1 pad byte */ + CHECK_BYTE_COUNT(1); + proto_tree_add_item(tree, hf_smb_padding, tvb, offset, 1, ENC_NA); + COUNT_BYTES(1); + + offset = dissect_file_data(tvb, tree, offset, cnt, -1, cnt); + bc = 0; /* XXX */ + + END_OF_SMB + + return offset; +} + +static int +dissect_write_and_close_response(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, int offset, proto_tree *smb_tree _U_, smb_info_t *si _U_) +{ + guint8 wc; + guint16 bc; + + WORD_COUNT; + + /* write count */ + proto_tree_add_item(tree, hf_smb_count, tvb, offset, 2, ENC_LITTLE_ENDIAN); + offset += 2; + + BYTE_COUNT; + + END_OF_SMB + + return offset; +} + +/* Timeout is defined on page 117 of SMB Protocol Extensions version 2.0 + available at http://us1.samba.org/samba/ftp/SMB-info/DOSEXTP.TXT +*/ +static gchar * +smbext20_timeout_msecs_to_str(gint32 timeout) +{ + gchar *buf; +#define SMBEXT20_TIMEOUT_MSECS_TO_STR_MAXLEN 60 + + if (timeout <= 0) { + buf = (gchar *)wmem_alloc(wmem_packet_scope(), SMBEXT20_TIMEOUT_MSECS_TO_STR_MAXLEN+1); + if (timeout == 0) { + snprintf(buf, SMBEXT20_TIMEOUT_MSECS_TO_STR_MAXLEN+1, "Return immediately (0)"); + } else if (timeout == -1) { + snprintf(buf, SMBEXT20_TIMEOUT_MSECS_TO_STR_MAXLEN+1, "Wait indefinitely (-1)"); + } else if (timeout == -2) { + snprintf(buf, SMBEXT20_TIMEOUT_MSECS_TO_STR_MAXLEN+1, "Use default timeout (-2)"); + } else { + snprintf(buf, SMBEXT20_TIMEOUT_MSECS_TO_STR_MAXLEN+1, "Unknown reserved value (%d)", timeout); + } + return buf; + } + + return signed_time_msecs_to_str(wmem_packet_scope(), timeout); +} + +static int +dissect_read_raw_request(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int offset, proto_tree *smb_tree _U_, smb_info_t *si) +{ + guint8 wc; + guint16 bc, fid; + guint32 to; + + WORD_COUNT; + + /* fid */ + fid = tvb_get_letohs(tvb, offset); + dissect_smb_fid(tvb, pinfo, tree, offset, 2, fid, FALSE, FALSE, FALSE, si); + offset += 2; + + /* offset */ + proto_tree_add_item(tree, hf_smb_offset, tvb, offset, 4, ENC_LITTLE_ENDIAN); + offset += 4; + + /* max count */ + proto_tree_add_item(tree, hf_smb_max_count, tvb, offset, 2, ENC_LITTLE_ENDIAN); + offset += 2; + + /* min count */ + proto_tree_add_item(tree, hf_smb_min_count, tvb, offset, 2, ENC_LITTLE_ENDIAN); + offset += 2; + + /* timeout */ + to = tvb_get_letohl(tvb, offset); + proto_tree_add_uint_format_value(tree, hf_smb_timeout, tvb, offset, 4, to, "%s", smbext20_timeout_msecs_to_str(to)); + offset += 4; + + /* 2 reserved bytes */ + proto_tree_add_item(tree, hf_smb_reserved, tvb, offset, 2, ENC_NA); + offset += 2; + + if (wc == 10) { + /* high offset */ + proto_tree_add_item(tree, hf_smb_high_offset, tvb, offset, 4, ENC_LITTLE_ENDIAN); + offset += 4; + } + + BYTE_COUNT; + + END_OF_SMB + + return offset; +} + +static int +dissect_query_information_disk_response(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, int offset, proto_tree *smb_tree _U_, smb_info_t *si _U_) +{ + guint8 wc; + guint16 bc; + + WORD_COUNT; + + /* units */ + proto_tree_add_item(tree, hf_smb_units, tvb, offset, 2, ENC_LITTLE_ENDIAN); + offset += 2; + + /* bpu */ + proto_tree_add_item(tree, hf_smb_bpu, tvb, offset, 2, ENC_LITTLE_ENDIAN); + offset += 2; + + /* block size */ + proto_tree_add_item(tree, hf_smb_blocksize, tvb, offset, 2, ENC_LITTLE_ENDIAN); + offset += 2; + + /* free units */ + proto_tree_add_item(tree, hf_smb_freeunits, tvb, offset, 2, ENC_LITTLE_ENDIAN); + offset += 2; + + /* 2 reserved bytes */ + proto_tree_add_item(tree, hf_smb_reserved, tvb, offset, 2, ENC_NA); + offset += 2; + + BYTE_COUNT; + + END_OF_SMB + + return offset; +} + +static int +dissect_read_mpx_request(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int offset, proto_tree *smb_tree _U_, smb_info_t *si) +{ + guint8 wc; + guint16 bc, fid; + + WORD_COUNT; + + /* fid */ + fid = tvb_get_letohs(tvb, offset); + dissect_smb_fid(tvb, pinfo, tree, offset, 2, fid, FALSE, FALSE, FALSE, si); + offset += 2; + + /* offset */ + proto_tree_add_item(tree, hf_smb_offset, tvb, offset, 4, ENC_LITTLE_ENDIAN); + offset += 4; + + /* max count */ + proto_tree_add_item(tree, hf_smb_max_count, tvb, offset, 2, ENC_LITTLE_ENDIAN); + offset += 2; + + /* min count */ + proto_tree_add_item(tree, hf_smb_min_count, tvb, offset, 2, ENC_LITTLE_ENDIAN); + offset += 2; + + /* 6 reserved bytes */ + proto_tree_add_item(tree, hf_smb_reserved, tvb, offset, 6, ENC_NA); + offset += 6; + + BYTE_COUNT; + + END_OF_SMB + + return offset; +} + +static int +dissect_read_mpx_response(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, int offset, proto_tree *smb_tree _U_, smb_info_t *si _U_) +{ + guint16 datalen = 0, bc; + guint8 wc; + + WORD_COUNT; + + /* offset */ + proto_tree_add_item(tree, hf_smb_offset, tvb, offset, 4, ENC_LITTLE_ENDIAN); + offset += 4; + + /* count */ + proto_tree_add_item(tree, hf_smb_count, tvb, offset, 2, ENC_LITTLE_ENDIAN); + offset += 2; + + /* 2 reserved bytes */ + proto_tree_add_item(tree, hf_smb_reserved, tvb, offset, 2, ENC_NA); + offset += 2; + + /* data compaction mode */ + proto_tree_add_item(tree, hf_smb_dcm, tvb, offset, 2, ENC_LITTLE_ENDIAN); + offset += 2; + + /* 2 reserved bytes */ + proto_tree_add_item(tree, hf_smb_reserved, tvb, offset, 2, ENC_NA); + offset += 2; + + /* data len */ + datalen = tvb_get_letohs(tvb, offset); + proto_tree_add_uint(tree, hf_smb_data_len, tvb, offset, 2, datalen); + offset += 2; + + /* data offset */ + proto_tree_add_item(tree, hf_smb_data_offset, tvb, offset, 2, ENC_LITTLE_ENDIAN); + offset += 2; + + BYTE_COUNT; + + /* file data */ + /* XXX - use the data offset to determine where the data starts? */ + offset = dissect_file_data(tvb, tree, offset, bc, -1, datalen); + bc = 0; + + END_OF_SMB + + return offset; +} + + +static const true_false_string tfs_write_mode_write_through = { + "WRITE THROUGH requested", + "Write through not requested" +}; +static const true_false_string tfs_write_mode_return_remaining = { + "RETURN REMAINING (pipe/dev) requested", + "DON'T return remaining (pipe/dev)" +}; +static const true_false_string tfs_write_mode_raw = { + "Use WriteRawNamedPipe (pipe)", + "DON'T use WriteRawNamedPipe (pipe)" +}; +static const true_false_string tfs_write_mode_message_start = { + "This is the START of a MESSAGE (pipe)", + "This is NOT the start of a message (pipe)" +}; +static const true_false_string tfs_write_mode_connectionless = { + "CONNECTIONLESS mode requested", + "Connectionless mode NOT requested" +}; + +#define WRITE_MODE_CONNECTIONLESS 0x0080 +#define WRITE_MODE_MESSAGE_START 0x0008 +#define WRITE_MODE_RAW 0x0004 +#define WRITE_MODE_RETURN_REMAINING 0x0002 +#define WRITE_MODE_WRITE_THROUGH 0x0001 + +static int +dissect_write_mode(tvbuff_t *tvb, proto_tree *parent_tree, int offset, int bm) +{ + guint16 mask; + proto_item *item; + proto_tree *tree; + + mask = tvb_get_letohs(tvb, offset); + + if (parent_tree) { + item = proto_tree_add_item(parent_tree, hf_smb_write_mode, tvb, offset, 2, ENC_LITTLE_ENDIAN); + tree = proto_item_add_subtree(item, ett_smb_rawmode); + + if (bm&WRITE_MODE_CONNECTIONLESS) { + proto_tree_add_boolean(tree, hf_smb_write_mode_connectionless, + tvb, offset, 2, mask); + } + if (bm&WRITE_MODE_MESSAGE_START) { + proto_tree_add_boolean(tree, hf_smb_write_mode_message_start, + tvb, offset, 2, mask); + } + if (bm&WRITE_MODE_RAW) { + proto_tree_add_boolean(tree, hf_smb_write_mode_raw, + tvb, offset, 2, mask); + } + if (bm&WRITE_MODE_RETURN_REMAINING) { + proto_tree_add_boolean(tree, hf_smb_write_mode_return_remaining, + tvb, offset, 2, mask); + } + if (bm&WRITE_MODE_WRITE_THROUGH) { + proto_tree_add_boolean(tree, hf_smb_write_mode_write_through, + tvb, offset, 2, mask); + } + } + + offset += 2; + return offset; +} + +static int +dissect_write_raw_request(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int offset, proto_tree *smb_tree _U_, smb_info_t *si) +{ + guint32 to; + guint16 datalen = 0, bc, fid; + guint8 wc; + + WORD_COUNT; + + /* fid */ + fid = tvb_get_letohs(tvb, offset); + dissect_smb_fid(tvb, pinfo, tree, offset, 2, fid, FALSE, FALSE, FALSE, si); + offset += 2; + + /* total data length */ + proto_tree_add_item(tree, hf_smb_total_data_len, tvb, offset, 2, ENC_LITTLE_ENDIAN); + offset += 2; + + /* 2 reserved bytes */ + proto_tree_add_item(tree, hf_smb_reserved, tvb, offset, 2, ENC_NA); + offset += 2; + + /* offset */ + proto_tree_add_item(tree, hf_smb_offset, tvb, offset, 4, ENC_LITTLE_ENDIAN); + offset += 4; + + /* timeout */ + to = tvb_get_letohl(tvb, offset); + proto_tree_add_uint_format_value(tree, hf_smb_timeout, tvb, offset, 4, to, "%s", smbext20_timeout_msecs_to_str(to)); + offset += 4; + + /* mode */ + offset = dissect_write_mode(tvb, tree, offset, 0x0003); + + /* 4 reserved bytes */ + proto_tree_add_item(tree, hf_smb_reserved, tvb, offset, 4, ENC_NA); + offset += 4; + + /* data len */ + datalen = tvb_get_letohs(tvb, offset); + proto_tree_add_uint(tree, hf_smb_data_len, tvb, offset, 2, datalen); + offset += 2; + + /* data offset */ + proto_tree_add_item(tree, hf_smb_data_offset, tvb, offset, 2, ENC_LITTLE_ENDIAN); + offset += 2; + + BYTE_COUNT; + + /* file data */ + /* XXX - use the data offset to determine where the data starts? */ + offset = dissect_file_data(tvb, tree, offset, bc, -1, datalen); + bc = 0; + + END_OF_SMB + + return offset; +} + +static int +dissect_write_raw_response(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, int offset, proto_tree *smb_tree _U_, smb_info_t *si _U_) +{ + guint8 wc; + guint16 bc; + + WORD_COUNT; + + /* remaining */ + proto_tree_add_item(tree, hf_smb_remaining, tvb, offset, 2, ENC_LITTLE_ENDIAN); + offset += 2; + + BYTE_COUNT; + + END_OF_SMB + + return offset; +} + +static int +dissect_write_mpx_request(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int offset, proto_tree *smb_tree _U_, smb_info_t *si) +{ + guint32 to; + guint16 datalen = 0, bc, fid; + guint8 wc; + + WORD_COUNT; + + /* fid */ + fid = tvb_get_letohs(tvb, offset); + dissect_smb_fid(tvb, pinfo, tree, offset, 2, fid, FALSE, FALSE, FALSE, si); + offset += 2; + + /* total data length */ + proto_tree_add_item(tree, hf_smb_total_data_len, tvb, offset, 2, ENC_LITTLE_ENDIAN); + offset += 2; + + /* 2 reserved bytes */ + proto_tree_add_item(tree, hf_smb_reserved, tvb, offset, 2, ENC_NA); + offset += 2; + + /* offset */ + proto_tree_add_item(tree, hf_smb_offset, tvb, offset, 4, ENC_LITTLE_ENDIAN); + offset += 4; + + /* timeout */ + to = tvb_get_letohl(tvb, offset); + proto_tree_add_uint_format_value(tree, hf_smb_timeout, tvb, offset, 4, to, "%s", smbext20_timeout_msecs_to_str(to)); + offset += 4; + + /* mode */ + offset = dissect_write_mode(tvb, tree, offset, 0x0083); + + /* request mask */ + proto_tree_add_item(tree, hf_smb_request_mask, tvb, offset, 4, ENC_LITTLE_ENDIAN); + offset += 4; + + /* data len */ + datalen = tvb_get_letohs(tvb, offset); + proto_tree_add_uint(tree, hf_smb_data_len, tvb, offset, 2, datalen); + offset += 2; + + /* data offset */ + proto_tree_add_item(tree, hf_smb_data_offset, tvb, offset, 2, ENC_LITTLE_ENDIAN); + offset += 2; + + BYTE_COUNT; + + /* file data */ + /* XXX - use the data offset to determine where the data starts? */ + offset = dissect_file_data(tvb, tree, offset, bc, -1,datalen); + bc = 0; + + END_OF_SMB + + return offset; +} + +static int +dissect_write_mpx_response(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, int offset, proto_tree *smb_tree _U_, smb_info_t *si _U_) +{ + guint8 wc; + guint16 bc; + + WORD_COUNT; + + /* response mask */ + proto_tree_add_item(tree, hf_smb_response_mask, tvb, offset, 4, ENC_LITTLE_ENDIAN); + offset += 4; + + BYTE_COUNT; + + END_OF_SMB + + return offset; +} + +static int +dissect_sid(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, int offset, proto_tree *smb_tree _U_, smb_info_t *si _U_) +{ + guint8 wc; + guint16 bc; + + WORD_COUNT; + + /* sid */ + proto_tree_add_item(tree, hf_smb_search_id, tvb, offset, 2, ENC_LITTLE_ENDIAN); + offset += 2; + + BYTE_COUNT; + + END_OF_SMB + + return offset; +} + +static int +dissect_search_resume_key(tvbuff_t *tvb, packet_info *pinfo _U_, + proto_tree *parent_tree, int offset, guint16 *bcp, gboolean *trunc, + gboolean has_find_id, smb_info_t *si) +{ + proto_tree *tree; + int fn_len; + const char *fn; + + DISSECTOR_ASSERT(si); + + tree = proto_tree_add_subtree(parent_tree, tvb, offset, 21, + ett_smb_search_resume_key, NULL, "Resume Key"); + + /* reserved byte */ + CHECK_BYTE_COUNT_SUBR(1); + proto_tree_add_item(tree, hf_smb_reserved, tvb, offset, 1, ENC_NA); + COUNT_BYTES_SUBR(1); + + /* file name */ + fn_len = 11; + fn = get_unicode_or_ascii_string(tvb, &offset, FALSE/*never Unicode*/, &fn_len, + TRUE, TRUE, bcp); + CHECK_STRING_SUBR(fn); + proto_tree_add_string(tree, hf_smb_file_name, tvb, offset, 11, fn); + COUNT_BYTES_SUBR(fn_len); + + if (has_find_id) { + CHECK_BYTE_COUNT_SUBR(1); + proto_tree_add_item(tree, hf_smb_resume_find_id, tvb, offset, 1, ENC_LITTLE_ENDIAN); + COUNT_BYTES_SUBR(1); + + /* server cookie */ + CHECK_BYTE_COUNT_SUBR(4); + proto_tree_add_item(tree, hf_smb_resume_server_cookie, tvb, offset, 4, ENC_NA); + COUNT_BYTES_SUBR(4); + } else { + /* server cookie */ + CHECK_BYTE_COUNT_SUBR(5); + proto_tree_add_item(tree, hf_smb_resume_server_cookie, tvb, offset, 5, ENC_NA); + COUNT_BYTES_SUBR(5); + } + + /* client cookie */ + CHECK_BYTE_COUNT_SUBR(4); + proto_tree_add_item(tree, hf_smb_resume_client_cookie, tvb, offset, 4, ENC_NA); + COUNT_BYTES_SUBR(4); + + *trunc = FALSE; + return offset; +} + +static int +dissect_search_dir_info(tvbuff_t *tvb, packet_info *pinfo, + proto_tree *parent_tree, int offset, guint16 *bcp, gboolean *trunc, + gboolean has_find_id, smb_info_t *si) +{ + proto_tree *tree; + int fn_len; + const char *fn; + + DISSECTOR_ASSERT(si); + + tree = proto_tree_add_subtree(parent_tree, tvb, offset, 43, + ett_smb_search_dir_info, NULL, "Directory Information"); + + /* resume key */ + offset = dissect_search_resume_key(tvb, pinfo, tree, offset, bcp, + trunc, has_find_id, si); + if (*trunc) + return offset; + + /* File Attributes */ + CHECK_BYTE_COUNT_SUBR(1); + offset = dissect_dir_info_file_attributes(tvb, tree, offset); + *bcp -= 1; + + /* last write time */ + CHECK_BYTE_COUNT_SUBR(4); + offset = dissect_smb_datetime(tvb, tree, offset, + hf_smb_last_write_time, + hf_smb_last_write_dos_date, hf_smb_last_write_dos_time, + TRUE); + *bcp -= 4; + + /* File Size */ + CHECK_BYTE_COUNT_SUBR(4); + proto_tree_add_item(tree, hf_smb_file_size, tvb, offset, 4, ENC_LITTLE_ENDIAN); + COUNT_BYTES_SUBR(4); + + /* file name */ + /* [MS-CIFS] says this is 13 *bytes*, and also says "Unicode is + not supported; names are returned in the extended ASCII + (OEM) character set only." */ + fn_len = 13; + fn = get_unicode_or_ascii_string(tvb, &offset, FALSE/*Never Unicode*/, &fn_len, + TRUE, TRUE, bcp); + CHECK_STRING_SUBR(fn); + proto_tree_add_string(tree, hf_smb_file_name, tvb, offset, fn_len, fn); + COUNT_BYTES_SUBR(fn_len); + + *trunc = FALSE; + return offset; +} + + +static int +dissect_search_find_request(tvbuff_t *tvb, packet_info *pinfo, + proto_tree *tree, int offset, proto_tree *smb_tree _U_, smb_info_t *si, + gboolean has_find_id) +{ + int fn_len; + const char *fn; + guint16 rkl; + guint8 wc; + guint16 bc; + gboolean trunc; + + DISSECTOR_ASSERT(si); + + WORD_COUNT; + + /* max count */ + proto_tree_add_item(tree, hf_smb_max_count, tvb, offset, 2, ENC_LITTLE_ENDIAN); + offset += 2; + + /* Search Attributes */ + offset = dissect_search_attributes(tvb, tree, offset); + + BYTE_COUNT; + + /* buffer format */ + CHECK_BYTE_COUNT(1); + proto_tree_add_item(tree, hf_smb_buffer_format, tvb, offset, 1, ENC_LITTLE_ENDIAN); + COUNT_BYTES(1); + + /* file name */ + fn = get_unicode_or_ascii_string(tvb, &offset, si->unicode, &fn_len, + TRUE, 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); + + col_append_fstr(pinfo->cinfo, COL_INFO, ", File: %s", + format_text(wmem_packet_scope(), (const guchar*)fn, strlen(fn))); + + /* buffer format */ + CHECK_BYTE_COUNT(1); + proto_tree_add_item(tree, hf_smb_buffer_format, tvb, offset, 1, ENC_LITTLE_ENDIAN); + COUNT_BYTES(1); + + /* resume key length */ + CHECK_BYTE_COUNT(2); + rkl = tvb_get_letohs(tvb, offset); + proto_tree_add_uint(tree, hf_smb_resume_key_len, tvb, offset, 2, rkl); + COUNT_BYTES(2); + + /* resume key */ + if (rkl) { + offset = dissect_search_resume_key(tvb, pinfo, tree, offset, + &bc, &trunc, has_find_id, si); + if (trunc) + goto endofcommand; + } + + END_OF_SMB + + return offset; +} + +static int +dissect_search_dir_request(tvbuff_t *tvb, packet_info *pinfo, + proto_tree *tree, int offset, proto_tree *smb_tree, smb_info_t *si) +{ + return dissect_search_find_request(tvb, pinfo, tree, offset, + smb_tree, si, FALSE); +} + +static int +dissect_find_request(tvbuff_t *tvb, packet_info *pinfo, + proto_tree *tree, int offset, proto_tree *smb_tree, smb_info_t *si) +{ + return dissect_search_find_request(tvb, pinfo, tree, offset, + smb_tree, si, TRUE); +} + +static int +dissect_find_close_request(tvbuff_t *tvb, packet_info *pinfo, + proto_tree *tree, int offset, proto_tree *smb_tree, smb_info_t *si) +{ + return dissect_search_find_request(tvb, pinfo, tree, offset, + smb_tree, si, TRUE); +} + +static int +dissect_search_find_response(tvbuff_t *tvb, packet_info *pinfo, + proto_tree *tree, int offset, proto_tree *smb_tree _U_, + gboolean has_find_id, smb_info_t *si) +{ + guint16 count = 0; + guint8 wc; + guint16 bc; + gboolean trunc; + + WORD_COUNT; + + /* count */ + count = tvb_get_letohs(tvb, offset); + proto_tree_add_uint(tree, hf_smb_count, tvb, offset, 2, count); + offset += 2; + + BYTE_COUNT; + + /* buffer format */ + CHECK_BYTE_COUNT(1); + proto_tree_add_item(tree, hf_smb_buffer_format, tvb, offset, 1, ENC_LITTLE_ENDIAN); + COUNT_BYTES(1); + + /* data len */ + CHECK_BYTE_COUNT(2); + proto_tree_add_item(tree, hf_smb_data_len, tvb, offset, 2, ENC_LITTLE_ENDIAN); + COUNT_BYTES(2); + + while (count--) { + offset = dissect_search_dir_info(tvb, pinfo, tree, offset, + &bc, &trunc, has_find_id, si); + if (trunc) + goto endofcommand; + } + + END_OF_SMB + + return offset; +} + +static int +dissect_search_dir_response(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int offset, proto_tree *smb_tree, smb_info_t *si) +{ + return dissect_search_find_response(tvb, pinfo, tree, offset, smb_tree, + FALSE, si); +} + +static int +dissect_find_response(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int offset, proto_tree *smb_tree, smb_info_t *si) +{ + return dissect_search_find_response(tvb, pinfo, tree, offset, smb_tree, + TRUE, si); +} + +static int +dissect_find_close_response(tvbuff_t *tvb, packet_info *pinfo _U_, + proto_tree *tree, int offset, proto_tree *smb_tree _U_, smb_info_t *si _U_) +{ + guint8 wc; + guint16 bc; + guint16 data_len; + + WORD_COUNT; + + /* reserved */ + proto_tree_add_item(tree, hf_smb_reserved, tvb, offset, 2, ENC_NA); + offset += 2; + + BYTE_COUNT; + + /* buffer format */ + CHECK_BYTE_COUNT(1); + proto_tree_add_item(tree, hf_smb_buffer_format, tvb, offset, 1, ENC_LITTLE_ENDIAN); + COUNT_BYTES(1); + + /* data len */ + CHECK_BYTE_COUNT(2); + data_len = tvb_get_ntohs(tvb, offset); + proto_tree_add_uint(tree, hf_smb_data_len, tvb, offset, 2, data_len); + COUNT_BYTES(2); + + if (data_len != 0) { + CHECK_BYTE_COUNT(data_len); + proto_tree_add_item(tree, hf_smb_reserved, tvb, offset, + data_len, ENC_NA); + COUNT_BYTES(data_len); + } + + END_OF_SMB + + return offset; +} + +static const value_string locking_ol_vals[] = { + {0, "Client is not holding oplock on this file"}, + {1, "Level 2 oplock currently held by client"}, + {0, NULL} +}; + +static const true_false_string tfs_lock_type_large = { + "Large file locking format requested", + "Large file locking format not requested" +}; +static const true_false_string tfs_lock_type_cancel = { + "Cancel outstanding lock request", + "Don't cancel outstanding lock request" +}; +static const true_false_string tfs_lock_type_change = { + "Change lock type", + "Don't change lock type" +}; +static const true_false_string tfs_lock_type_oplock = { + "This is an oplock break notification/response", + "This is not an oplock break notification/response" +}; +static const true_false_string tfs_lock_type_shared = { + "This is a shared lock", + "This is an exclusive lock" +}; +static int +dissect_locking_andx_request(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int offset, proto_tree *smb_tree, smb_info_t *si) +{ + guint8 wc, cmd = 0xff, lt = 0, ol = 0; + guint16 andxoffset = 0, un = 0, ln = 0, bc, fid, num_lock = 0, num_unlock = 0; + guint32 to; + proto_item *it = NULL; + proto_tree *tr = NULL; + int old_offset = offset; + smb_locking_saved_info_t *ld = NULL; + static int * const locks[] = { + &hf_smb_lock_type_large, + &hf_smb_lock_type_cancel, + &hf_smb_lock_type_change, + &hf_smb_lock_type_oplock, + &hf_smb_lock_type_shared, + NULL + }; + + DISSECTOR_ASSERT(si); + + WORD_COUNT; + + /* next smb command */ + cmd = tvb_get_guint8(tvb, offset); + if (cmd != 0xff) { + proto_tree_add_uint(tree, hf_smb_andxcmd, tvb, offset, 1, cmd); + } else { + proto_tree_add_uint_format_value(tree, hf_smb_andxcmd, tvb, offset, 1, cmd, "No further commands (0xff)"); + } + offset += 1; + + /* reserved byte */ + proto_tree_add_item(tree, hf_smb_reserved, tvb, offset, 1, ENC_NA); + offset += 1; + + /* andxoffset */ + andxoffset = tvb_get_letohs(tvb, offset); + proto_tree_add_uint(tree, hf_smb_andxoffset, tvb, offset, 2, andxoffset); + offset += 2; + + /* fid */ + fid = tvb_get_letohs(tvb, offset); + dissect_smb_fid(tvb, pinfo, tree, offset, 2, fid, FALSE, FALSE, FALSE, si); + offset += 2; + + /* lock type */ + lt = tvb_get_guint8(tvb, offset); + proto_tree_add_bitmask(tree, tvb, offset, hf_smb_lock_type, ett_smb_lock_type, locks, ENC_NA); + offset += 1; + + /* oplock level */ + ol = tvb_get_guint8(tvb, offset); + proto_tree_add_item(tree, hf_smb_locking_ol, tvb, offset, 1, ENC_LITTLE_ENDIAN); + offset += 1; + + /* timeout */ + to = tvb_get_letohl(tvb, offset); + proto_tree_add_uint_format_value(tree, hf_smb_timeout, tvb, offset, 4, to, "%s", smbext20_timeout_msecs_to_str(to)); + offset += 4; + + /* number of unlocks */ + un = tvb_get_letohs(tvb, offset); + num_unlock = un; + proto_tree_add_uint(tree, hf_smb_number_of_unlocks, tvb, offset, 2, un); + offset += 2; + + /* number of locks */ + ln = tvb_get_letohs(tvb, offset); + num_lock = ln; + proto_tree_add_uint(tree, hf_smb_number_of_locks, tvb, offset, 2, ln); + offset += 2; + + BYTE_COUNT; + + /* store the locking data for the response */ + if ((!pinfo->fd->visited) && si->sip) { + ld = wmem_new(wmem_file_scope(), smb_locking_saved_info_t); + ld->type = lt; + ld->oplock_level = ol; + ld->num_lock = num_lock; + ld->num_unlock = num_unlock; + ld->locks = NULL; + ld->unlocks = NULL; + si->sip->extra_info_type = SMB_EI_LOCKDATA; + si->sip->extra_info = ld; + } + + /* unlocks */ + if (un) { + old_offset = offset; + + tr = proto_tree_add_subtree(tree, tvb, offset, -1, ett_smb_unlocks, &it, "Unlocks"); + while (un--) { + proto_tree *ltree_2; + if (lt&0x10) { + guint64 val; + guint16 lock_pid; + guint64 lock_offset; + guint64 lock_length; + + /* large lock format */ + ltree_2 = proto_tree_add_subtree(tr, tvb, offset, 20, ett_smb_unlock, NULL, "Unlock"); + + /* PID */ + CHECK_BYTE_COUNT(2); + lock_pid = tvb_get_letohs(tvb, offset); + proto_tree_add_item(ltree_2, hf_smb_pid, tvb, offset, 2, ENC_LITTLE_ENDIAN); + COUNT_BYTES(2); + + /* 2 reserved bytes */ + CHECK_BYTE_COUNT(2); + proto_tree_add_item(ltree_2, hf_smb_reserved, tvb, offset, 2, ENC_NA); + COUNT_BYTES(2); + + /* offset */ + CHECK_BYTE_COUNT(8); + val = ((guint64)tvb_get_letohl(tvb, offset)) << 32 + | tvb_get_letohl(tvb, offset+4); + lock_offset = val; + proto_tree_add_uint64(ltree_2, hf_smb_lock_long_offset, tvb, offset, 8, val); + COUNT_BYTES(8); + + /* length */ + CHECK_BYTE_COUNT(8); + val = ((guint64)tvb_get_letohl(tvb, offset)) << 32 + | tvb_get_letohl(tvb, offset+4); + lock_length = val; + proto_tree_add_uint64(ltree_2, hf_smb_lock_long_length, tvb, offset, 8, val); + COUNT_BYTES(8); + + /* remember the unlock for the reply */ + if (ld) { + smb_lock_info_t *li; + li = wmem_new(wmem_file_scope(), smb_lock_info_t); + li->next = ld->unlocks; + ld->unlocks = li; + li->pid = lock_pid; + li->offset = lock_offset; + li->length = lock_length; + } + } else { + /* normal lock format */ + ltree_2 = proto_tree_add_subtree(tr, tvb, offset, 10, ett_smb_unlock, NULL, "Unlock"); + + /* PID */ + CHECK_BYTE_COUNT(2); + proto_tree_add_item(ltree_2, hf_smb_pid, tvb, offset, 2, ENC_LITTLE_ENDIAN); + COUNT_BYTES(2); + + /* offset */ + CHECK_BYTE_COUNT(4); + proto_tree_add_item(ltree_2, hf_smb_offset, tvb, offset, 4, ENC_LITTLE_ENDIAN); + COUNT_BYTES(4); + + /* lock count */ + CHECK_BYTE_COUNT(4); + proto_tree_add_item(ltree_2, hf_smb_count, tvb, offset, 4, ENC_LITTLE_ENDIAN); + COUNT_BYTES(4); + } + } + proto_item_set_len(it, offset-old_offset); + it = NULL; + } + + /* locks */ + if (ln) { + old_offset = offset; + + tr = proto_tree_add_subtree(tree, tvb, offset, -1, ett_smb_locks, &it, "Locks"); + while (ln--) { + proto_tree *ltree_2; + if (lt&0x10) { + guint64 val; + guint16 lock_pid; + guint64 lock_offset; + guint64 lock_length; + + /* large lock format */ + ltree_2 = proto_tree_add_subtree(tr, tvb, offset, 20, ett_smb_lock, NULL, "Lock"); + + /* PID */ + CHECK_BYTE_COUNT(2); + lock_pid = tvb_get_letohs(tvb, offset); + proto_tree_add_item(ltree_2, hf_smb_pid, tvb, offset, 2, ENC_LITTLE_ENDIAN); + COUNT_BYTES(2); + + /* 2 reserved bytes */ + CHECK_BYTE_COUNT(2); + proto_tree_add_item(ltree_2, hf_smb_reserved, tvb, offset, 2, ENC_NA); + COUNT_BYTES(2); + + /* offset */ + CHECK_BYTE_COUNT(8); + val = ((guint64)tvb_get_letohl(tvb, offset)) << 32 + | tvb_get_letohl(tvb, offset+4); + lock_offset = val; + proto_tree_add_uint64(ltree_2, hf_smb_lock_long_offset, tvb, offset, 8, val); + COUNT_BYTES(8); + + /* length */ + CHECK_BYTE_COUNT(8); + val = ((guint64)tvb_get_letohl(tvb, offset)) << 32 + | tvb_get_letohl(tvb, offset+4); + lock_length = val; + proto_tree_add_uint64(ltree_2, hf_smb_lock_long_length, tvb, offset, 8, val); + COUNT_BYTES(8); + + /* remember the lock for the reply */ + if (ld) { + smb_lock_info_t *li; + li = wmem_new(wmem_file_scope(), smb_lock_info_t); + li->next = ld->locks; + ld->locks = li; + li->pid = lock_pid; + li->offset = lock_offset; + li->length = lock_length; + } + } else { + /* normal lock format */ + ltree_2 = proto_tree_add_subtree(tr, tvb, offset, 10, ett_smb_lock, NULL, "Lock"); + + /* PID */ + CHECK_BYTE_COUNT(2); + proto_tree_add_item(ltree_2, hf_smb_pid, tvb, offset, 2, ENC_LITTLE_ENDIAN); + COUNT_BYTES(2); + + /* offset */ + CHECK_BYTE_COUNT(4); + proto_tree_add_item(ltree_2, hf_smb_offset, tvb, offset, 4, ENC_LITTLE_ENDIAN); + COUNT_BYTES(4); + + /* lock count */ + CHECK_BYTE_COUNT(4); + proto_tree_add_item(ltree_2, hf_smb_count, tvb, offset, 4, ENC_LITTLE_ENDIAN); + COUNT_BYTES(4); + } + } + proto_item_set_len(it, offset-old_offset); + it = NULL; + } + + END_OF_SMB + + if (it != NULL) { + /* + * We ran out of byte count in the middle of dissecting + * the locks or the unlocks; set the site of the item + * we were dissecting. + */ + proto_item_set_len(it, offset-old_offset); + } + + if (cmd != 0xff) { /* there is an andX command */ + if (andxoffset < offset) { + THROW(ReportedBoundsError); + } + dissect_smb_command(tvb, pinfo, andxoffset, smb_tree, cmd, FALSE, si); + } + + return offset; +} + +static int +dissect_locking_andx_response(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int offset, proto_tree *smb_tree, smb_info_t *si) +{ + guint8 wc, cmd = 0xff; + guint16 andxoffset = 0; + guint16 bc; + + DISSECTOR_ASSERT(si); + + /* print the lock info from the request */ + if ((si->sip != NULL) && (si->sip->extra_info_type == SMB_EI_LOCKDATA)) { + smb_locking_saved_info_t *ld; + proto_item *litem = NULL; + proto_tree *ltree = NULL; + + ld = (smb_locking_saved_info_t *)si->sip->extra_info; + if (ld != NULL) { + proto_tree *ltr; + smb_lock_info_t *li; + if (tree) { + litem = proto_tree_add_uint(tree, hf_smb_lock_type, tvb, 0, 0, ld->type); + proto_item_set_generated(litem); + ltree = proto_item_add_subtree(litem, ett_smb_lock_type); + + proto_tree_add_boolean(ltree, hf_smb_lock_type_large, tvb, 0, 0, ld->type); + proto_tree_add_boolean(ltree, hf_smb_lock_type_cancel, tvb, 0, 0, ld->type); + proto_tree_add_boolean(ltree, hf_smb_lock_type_change, tvb, 0, 0, ld->type); + proto_tree_add_boolean(ltree, hf_smb_lock_type_oplock, tvb, 0, 0, ld->type); + proto_tree_add_boolean(ltree, hf_smb_lock_type_shared, tvb, 0, 0, ld->type); + proto_tree_add_uint(ltree, hf_smb_locking_ol, tvb, 0, 0, ld->oplock_level); + proto_tree_add_uint(ltree, hf_smb_number_of_unlocks, tvb, 0, 0, ld->num_unlock); + proto_tree_add_uint(ltree, hf_smb_number_of_locks, tvb, 0, 0, ld->num_lock); + + ltr = proto_tree_add_subtree(ltree, tvb, 0, 0, ett_smb_lock, NULL, "Locks"); + li = ld->locks; + while (li) { + proto_tree_add_uint(ltr, hf_smb_pid, tvb, 0, 0, li->pid); + proto_tree_add_uint64(ltr, hf_smb_lock_long_offset, tvb, 0, 0, li->offset); + proto_tree_add_uint64(ltr, hf_smb_lock_long_length, tvb, 0, 0, li->length); + li = li->next; + } + ltr = proto_tree_add_subtree(ltree, tvb, 0, 0, ett_smb_unlock, NULL, "Unlocks"); + li = ld->unlocks; + while (li) { + proto_tree_add_uint(ltr, hf_smb_pid, tvb, 0, 0, li->pid); + proto_tree_add_uint64(ltr, hf_smb_lock_long_offset, tvb, 0, 0, li->offset); + proto_tree_add_uint64(ltr, hf_smb_lock_long_length, tvb, 0, 0, li->length); + li = li->next; + } + } + } + } + + WORD_COUNT; + + /* next smb command */ + cmd = tvb_get_guint8(tvb, offset); + if (cmd != 0xff) { + proto_tree_add_uint(tree, hf_smb_andxcmd, tvb, offset, 1, cmd); + } else { + proto_tree_add_uint_format_value(tree, hf_smb_andxcmd, tvb, offset, 1, cmd, "No further commands (0xff)"); + } + offset += 1; + + /* reserved byte */ + proto_tree_add_item(tree, hf_smb_reserved, tvb, offset, 1, ENC_NA); + offset += 1; + + /* andxoffset */ + andxoffset = tvb_get_letohs(tvb, offset); + proto_tree_add_uint(tree, hf_smb_andxoffset, tvb, offset, 2, andxoffset); + offset += 2; + + BYTE_COUNT; + + END_OF_SMB + + if (cmd != 0xff) { /* there is an andX command */ + if (andxoffset < offset) { + THROW(ReportedBoundsError); + } + dissect_smb_command(tvb, pinfo, andxoffset, smb_tree, cmd, FALSE, si); + } + + return offset; +} + + +const value_string oa_open_vals[] = { + { 0, "No action taken?"}, + { 1, "The file existed and was opened"}, + { 2, "The file did not exist but was created"}, + { 3, "The file existed and was truncated"}, + { 0x8001, "The file existed and was opened, and an OpLock was granted"}, + { 0x8002, "The file did not exist but was created, and an OpLock was granted"}, + { 0x8003, "The file existed and was truncated, and an OpLock was granted"}, + {0, NULL} +}; +static const true_false_string tfs_oa_lock = { + "File is currently opened only by this user", + "File is opened by another user (or mode not supported by server)" +}; +static int +dissect_open_action(tvbuff_t *tvb, proto_tree *parent_tree, int offset) +{ + static int * const flags[] = { + &hf_smb_open_action_lock, + &hf_smb_open_action_open, + NULL + }; + + proto_tree_add_bitmask(parent_tree, tvb, offset, hf_smb_open_action, ett_smb_open_action, flags, ENC_LITTLE_ENDIAN); + offset += 2; + + return offset; +} + +static const true_false_string tfs_open_flags_add_info = { + "Additional information requested", + "Additional information not requested" +}; +static const true_false_string tfs_open_flags_ex_oplock = { + "Exclusive oplock requested", + "Exclusive oplock not requested" +}; +static const true_false_string tfs_open_flags_batch_oplock = { + "Batch oplock requested", + "Batch oplock not requested" +}; +static const true_false_string tfs_open_flags_ealen = { + "Total length of EAs requested", + "Total length of EAs not requested" +}; +static int +dissect_open_flags(tvbuff_t *tvb, proto_tree *parent_tree, int offset, int bm) +{ + guint16 mask; + proto_item *item; + proto_tree *tree; + + mask = tvb_get_letohs(tvb, offset); + + if (parent_tree) { + item = proto_tree_add_item(parent_tree, hf_smb_open_flags, tvb, offset, 2, ENC_LITTLE_ENDIAN); + tree = proto_item_add_subtree(item, ett_smb_open_flags); + + if (bm&0x0001) { + proto_tree_add_boolean(tree, hf_smb_open_flags_add_info, + tvb, offset, 2, mask); + } + if (bm&0x0002) { + proto_tree_add_boolean(tree, hf_smb_open_flags_ex_oplock, + tvb, offset, 2, mask); + } + if (bm&0x0004) { + proto_tree_add_boolean(tree, hf_smb_open_flags_batch_oplock, + tvb, offset, 2, mask); + } + if (bm&0x0008) { + proto_tree_add_boolean(tree, hf_smb_open_flags_ealen, + tvb, offset, 2, mask); + } + } + + offset += 2; + + return offset; +} + +/* [MS-CIFS].pdf 2.2.4.64.2 provides the last two file types, however + [MS-SMB].PDF 2.2.4.9.2 elides value 4, Character mode device. */ +static const value_string filetype_vals[] = { + { 0, "Disk file or directory"}, + { 1, "Named pipe in byte mode"}, + { 2, "Named pipe in message mode"}, + { 3, "Spooled printer"}, + { 4, "Character mode device"}, + { 0xFFFF, "Unknown file type"}, + {0, NULL} +}; +static int +dissect_open_andx_request(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int offset, proto_tree *smb_tree, smb_info_t *si) +{ + guint8 wc, cmd = 0xff; + guint16 andxoffset = 0, bc; + guint32 to; + int fn_len; + const char *fn; + + DISSECTOR_ASSERT(si); + + WORD_COUNT; + + /* next smb command */ + cmd = tvb_get_guint8(tvb, offset); + if (cmd != 0xff) { + proto_tree_add_uint(tree, hf_smb_andxcmd, tvb, offset, 1, cmd); + } else { + proto_tree_add_uint_format_value(tree, hf_smb_andxcmd, tvb, offset, 1, cmd, "No further commands (0xff)"); + } + offset += 1; + + /* reserved byte */ + proto_tree_add_item(tree, hf_smb_reserved, tvb, offset, 1, ENC_NA); + offset += 1; + + /* andxoffset */ + andxoffset = tvb_get_letohs(tvb, offset); + proto_tree_add_uint(tree, hf_smb_andxoffset, tvb, offset, 2, andxoffset); + offset += 2; + + /* open flags */ + offset = dissect_open_flags(tvb, tree, offset, 0x0007); + + /* desired access */ + offset = dissect_access(tvb, tree, offset, hf_smb_desired_access); + + /* Search Attributes */ + offset = dissect_search_attributes(tvb, tree, offset); + + /* File Attributes */ + offset = dissect_file_attributes(tvb, tree, offset); + + /* creation time */ + offset = dissect_smb_UTIME(tvb, tree, offset, hf_smb_create_time); + + /* open function */ + offset = dissect_open_function(tvb, tree, offset); + + /* allocation size */ + proto_tree_add_item(tree, hf_smb_alloc_size, tvb, offset, 4, ENC_LITTLE_ENDIAN); + offset += 4; + + /* timeout, described at http://us1.samba.org/samba/ftp/SMB-info/DOSEXTP.TXT */ + to = tvb_get_letohl(tvb, offset); + proto_tree_add_uint_format_value(tree, hf_smb_timeout, tvb, offset, 4, to, "%s", smbext20_timeout_msecs_to_str(to)); + offset += 4; + + /* 4 reserved bytes */ + proto_tree_add_item(tree, hf_smb_reserved, tvb, offset, 4, ENC_NA); + offset += 4; + + BYTE_COUNT; + + /* file name */ + fn = get_unicode_or_ascii_string(tvb, &offset, si->unicode, &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); + + /* Copied this portion of code from create_andx_request + to guarantee that fsi and si->sip are always correctly filled out */ + if ((!pinfo->fd->visited) && si->sip && fn) { + smb_fid_saved_info_t *fsi; + + fsi = wmem_new0(wmem_file_scope(), smb_fid_saved_info_t); + fsi->filename = wmem_strdup(wmem_file_scope(), fn); + + si->sip->extra_info_type = SMB_EI_FILEDATA; + si->sip->extra_info = fsi; + } + + col_append_fstr(pinfo->cinfo, COL_INFO, ", Path: %s", + format_text(wmem_packet_scope(), (const guchar*)fn, strlen(fn))); + + END_OF_SMB + + if (cmd != 0xff) { /* there is an andX command */ + if (andxoffset < offset) { + THROW(ReportedBoundsError); + } + dissect_smb_command(tvb, pinfo, andxoffset, smb_tree, cmd, FALSE, si); + } + + return offset; +} + +static const true_false_string tfs_ipc_state_nonblocking = { + "Reads/writes return immediately if no data available", + "Reads/writes block if no data available" +}; +static const value_string ipc_state_endpoint_vals[] = { + { 0, "Consumer end of pipe"}, + { 1, "Server end of pipe"}, + {0, NULL} +}; +static const value_string ipc_state_pipe_type_vals[] = { + { 0, "Byte stream pipe"}, + { 1, "Message pipe"}, + {0, NULL} +}; +static const value_string ipc_state_read_mode_vals[] = { + { 0, "Read pipe as a byte stream"}, + { 1, "Read messages from pipe"}, + {0, NULL} +}; + +int +dissect_ipc_state(tvbuff_t *tvb, proto_tree *parent_tree, int offset, gboolean setstate_flag) +{ + static int * const setstate_flags[] = { + &hf_smb_ipc_state_nonblocking, + &hf_smb_ipc_state_read_mode, + NULL + }; + static int * const not_setstate_flags[] = { + &hf_smb_ipc_state_nonblocking, + &hf_smb_ipc_state_endpoint, + &hf_smb_ipc_state_pipe_type, + &hf_smb_ipc_state_read_mode, + &hf_smb_ipc_state_icount, + NULL + }; + + if (!setstate_flag) { + proto_tree_add_bitmask(parent_tree, tvb, offset, hf_smb_ipc_state, ett_smb_ipc_state, not_setstate_flags, ENC_LITTLE_ENDIAN); + } else { + proto_tree_add_bitmask(parent_tree, tvb, offset, hf_smb_ipc_state, ett_smb_ipc_state, setstate_flags, ENC_LITTLE_ENDIAN); + } + offset += 2; + + return offset; +} + +static int +dissect_open_andx_response(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int offset, proto_tree *smb_tree, smb_info_t *si) +{ + guint8 wc, cmd = 0xff; + guint16 andxoffset = 0, bc; + guint16 fid; + guint16 ftype; + guint16 fattr; + smb_fid_info_t *fid_info = NULL; + gboolean isdir = FALSE; + + WORD_COUNT; + + /* next smb command */ + cmd = tvb_get_guint8(tvb, offset); + if (cmd != 0xff) { + proto_tree_add_uint(tree, hf_smb_andxcmd, tvb, offset, 1, cmd); + } else { + proto_tree_add_uint_format_value(tree, hf_smb_andxcmd, tvb, offset, 1, cmd, "No further commands (0xff)"); + } + offset += 1; + + /* reserved byte */ + proto_tree_add_item(tree, hf_smb_reserved, tvb, offset, 1, ENC_NA); + offset += 1; + + /* andxoffset */ + andxoffset = tvb_get_letohs(tvb, offset); + proto_tree_add_uint(tree, hf_smb_andxoffset, tvb, offset, 2, andxoffset); + offset += 2; + + /* fid */ + fid = tvb_get_letohs(tvb, offset); + /* we add fid_info= to this call so that we save the result */ + fid_info = dissect_smb_fid(tvb, pinfo, tree, offset, 2, fid, TRUE, FALSE, FALSE, si); + + offset += 2; + + /* File Attributes */ + fattr = tvb_get_letohs(tvb, offset); + isdir = fattr & SMB_FILE_ATTRIBUTE_DIRECTORY; + offset = dissect_file_attributes(tvb, tree, offset); + + /* last write time */ + offset = dissect_smb_UTIME(tvb, tree, offset, hf_smb_last_write_time); + + /* File Size */ + /* We store the file_size in the fid_info */ + if (fid_info) { + fid_info->end_of_file = (guint64) tvb_get_letohl(tvb, offset); + } + proto_tree_add_item(tree, hf_smb_file_size, tvb, offset, 4, ENC_LITTLE_ENDIAN); + offset += 4; + + /* granted access */ + offset = dissect_access(tvb, tree, offset, hf_smb_granted_access); + + /* File Type */ + ftype = tvb_get_letohs(tvb, offset); + proto_tree_add_item(tree, hf_smb_file_type, tvb, offset, 2, ENC_LITTLE_ENDIAN); + offset += 2; + /* Copied from dissect_nt_create_andx_response + Try to remember the type of this fid so that we can dissect + any future security descriptor (access mask) properly + */ + if (fid_info) { + fid_info->type = SMB_FID_TYPE_UNKNOWN; + } + if (ftype == 0) { + if (isdir == 0) { + if (fid_info) { + fid_info->type = SMB_FID_TYPE_FILE; + } + } else { + if (fid_info) { + fid_info->type = SMB_FID_TYPE_DIR; + } + } + } + if ((ftype == 2) || (ftype == 1)) { + if (fid_info) { + fid_info->type = SMB_FID_TYPE_PIPE; + } + } + + /* IPC State */ + offset = dissect_ipc_state(tvb, tree, offset, FALSE); + + /* open_action */ + offset = dissect_open_action(tvb, tree, offset); + + /* server fid */ + proto_tree_add_item(tree, hf_smb_server_fid, tvb, offset, 4, ENC_LITTLE_ENDIAN); + offset += 4; + + /* 2 reserved bytes */ + proto_tree_add_item(tree, hf_smb_reserved, tvb, offset, 2, ENC_NA); + offset += 2; + + /* [MS-SMB] 2.2.4.1.2 Server Response Extensions */ + if (wc == 19) { + proto_tree *tr = NULL; + + tr = proto_tree_add_subtree(tree, tvb, offset, 4, + ett_smb_nt_access_mask, NULL, "Maximal Access Rights"); + offset = dissect_smb_access_mask(tvb, tr, offset); + + tr = proto_tree_add_subtree(tree, tvb, offset, 4, + ett_smb_nt_access_mask, NULL, "Guest Maximal Access Rights"); + offset = dissect_smb_access_mask(tvb, tr, offset); + } + + BYTE_COUNT; + + END_OF_SMB + + if (cmd != 0xff) { /* there is an andX command */ + if (andxoffset < offset) { + THROW(ReportedBoundsError); + } + dissect_smb_command(tvb, pinfo, andxoffset, smb_tree, cmd, FALSE, si); + } + + return offset; +} + +static int +dissect_read_andx_request(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int offset, proto_tree *smb_tree, smb_info_t *si) +{ + guint8 wc, cmd = 0xff; + guint16 andxoffset = 0, bc, maxcnt_low; + guint32 maxcnt_high; + guint32 maxcnt = 0; + guint32 offsetlow, offsethigh = 0; + guint64 ofs; + unsigned int fid; + rw_info_t *rwi = NULL; + + + DISSECTOR_ASSERT(si); + + WORD_COUNT; + + /* next smb command */ + cmd = tvb_get_guint8(tvb, offset); + if (cmd != 0xff) { + proto_tree_add_uint(tree, hf_smb_andxcmd, tvb, offset, 1, cmd); + } else { + proto_tree_add_uint_format_value(tree, hf_smb_andxcmd, tvb, offset, 1, cmd, "No further commands (0xff)"); + } + offset += 1; + + /* reserved byte */ + proto_tree_add_item(tree, hf_smb_reserved, tvb, offset, 1, ENC_NA); + offset += 1; + + /* andxoffset */ + andxoffset = tvb_get_letohs(tvb, offset); + proto_tree_add_uint(tree, hf_smb_andxoffset, tvb, offset, 2, andxoffset); + offset += 2; + + /* fid */ + fid = tvb_get_letohs(tvb, offset); + dissect_smb_fid(tvb, pinfo, tree, offset, 2, (guint16) fid, FALSE, FALSE, FALSE, si); + offset += 2; + + /* offset */ + offsetlow = tvb_get_letohl(tvb, offset); + proto_tree_add_item(tree, hf_smb_offset, tvb, offset, 4, ENC_LITTLE_ENDIAN); + offset += 4; + + /* max count low */ + maxcnt_low = tvb_get_letohs(tvb, offset); + proto_tree_add_uint(tree, hf_smb_max_count_low, tvb, offset, 2, maxcnt_low); + offset += 2; + + /* min count */ + proto_tree_add_item(tree, hf_smb_min_count, tvb, offset, 2, ENC_LITTLE_ENDIAN); + offset += 2; + + /* + * max count high + * + * XXX - we should really only do this in case we have seen + * LARGE FILE being negotiated. Unfortunately, we might not + * have seen the negotiation phase in the capture.... + * + * XXX - this is shown as a ULONG in the SNIA SMB spec, i.e. + * it's 32 bits, but the description says "High 16 bits of + * MaxCount if CAP_LARGE_READX". + * + * The SMB File Sharing Protocol Extensions Version 2.0, + * Document Version 3.3 spec doesn't speak of an extra 16 + * bits in max count, but it does show a 32-bit timeout + * after the min count field. + * + * The Microsoft [MS-SMB] spec shows it as a ULONG named + * Timeout_or_MaxCountHigh, which is + * + * ...extended to be treated as a union of a 32-bit + * Timeout field and a 16-bit MaxCountHigh field. + * When reading from a regular file, the field + * MUST be interpreted as MaxCountHigh and the + * two unused bytes MUST be zero. When reading from + * a name[sic] pipe or I/O device, the field MUST + * be interpreted as Timeout. + * + * Timeout is a timeout in milliseconds, with 0xffffffff + * and 0xfffffffe having special meaning. + * + * MaxCountHigh is 16 bits of the MaxCountHigh value + * followed by 16 bits of Reserved. + * + * We fetch and display it as 32 bits for now. + * + * XXX if maxcount high is 0xFFFFFFFF we assume it is just padding + * bytes and we just ignore it. + */ + maxcnt_high = tvb_get_letohl(tvb, offset); + if (maxcnt_high == 0xffffffff) { + maxcnt_high = 0; + } else { + proto_tree_add_uint(tree, hf_smb_max_count_high, tvb, offset, 4, maxcnt_high); + } + + offset += 4; + + maxcnt = maxcnt_high; + maxcnt = (maxcnt<<16) | maxcnt_low; + + /* remaining */ + proto_tree_add_item(tree, hf_smb_remaining, tvb, offset, 2, ENC_LITTLE_ENDIAN); + offset += 2; + + if (wc == 12) { + /* high offset */ + offsethigh = tvb_get_letohl(tvb, offset); + proto_tree_add_item(tree, hf_smb_high_offset, tvb, offset, 4, ENC_LITTLE_ENDIAN); + offset += 4; + } + + ofs = offsethigh; + ofs = (ofs<<32) | offsetlow; + + col_append_fstr(pinfo->cinfo, COL_INFO, + ", %u byte%s at offset %" PRIu64, + maxcnt, (maxcnt == 1) ? "" : "s", ofs); + + /* save the offset/len for this transaction */ + if (si->sip && !pinfo->fd->visited) { + rwi = wmem_new(wmem_file_scope(), rw_info_t); + rwi->offset = ofs; + rwi->len = maxcnt; + rwi->fid = fid; + + si->sip->extra_info_type = SMB_EI_RWINFO; + si->sip->extra_info = rwi; + } + if (si->sip && (si->sip->extra_info_type == SMB_EI_RWINFO)) { + rwi = (rw_info_t *)si->sip->extra_info; + } + if (rwi) { + proto_item *it; + + it = proto_tree_add_uint64(tree, hf_smb_file_rw_offset, tvb, 0, 0, rwi->offset); + + proto_item_set_generated(it); + it = proto_tree_add_uint(tree, hf_smb_file_rw_length, tvb, 0, 0, rwi->len); + proto_item_set_generated(it); + } + + BYTE_COUNT; + + END_OF_SMB + + if (cmd != 0xff) { /* there is an andX command */ + if (andxoffset < offset) { + THROW(ReportedBoundsError); + } + dissect_smb_command(tvb, pinfo, andxoffset, smb_tree, cmd, FALSE, si); + } + + return offset; +} + +static int +dissect_read_andx_response(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int offset, proto_tree *smb_tree, smb_info_t *si) +{ + guint8 wc, cmd = 0xff; + guint16 andxoffset = 0, bc, datalen_low, dataoffset = 0; + guint32 datalen = 0, datalen_high; + rw_info_t *rwi = NULL; + guint16 fid = 0; /* was int fid = 0; */ + + guint32 tvblen; + + DISSECTOR_ASSERT(si); + + WORD_COUNT; + + /* next smb command */ + cmd = tvb_get_guint8(tvb, offset); + if (cmd != 0xff) { + proto_tree_add_uint(tree, hf_smb_andxcmd, tvb, offset, 1, cmd); + } else { + proto_tree_add_uint_format_value(tree, hf_smb_andxcmd, tvb, offset, 1, cmd, "No further commands (0xff)"); + } + offset += 1; + + /* reserved byte */ + proto_tree_add_item(tree, hf_smb_reserved, tvb, offset, 1, ENC_NA); + offset += 1; + + /* andxoffset */ + andxoffset = tvb_get_letohs(tvb, offset); + proto_tree_add_uint(tree, hf_smb_andxoffset, tvb, offset, 2, andxoffset); + offset += 2; + + /* 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) && (si->sip->extra_info_type == SMB_EI_FID)) { + fid = GPOINTER_TO_INT(si->sip->extra_info); + dissect_smb_fid(tvb, pinfo, tree, 0, 0, (guint16) fid, FALSE, FALSE, FALSE, si); + } + + if (si->sip && (si->sip->extra_info_type == SMB_EI_RWINFO)) { + rwi = (rw_info_t *)si->sip->extra_info; + } + if (rwi) { + proto_item *it; + + it = proto_tree_add_uint64(tree, hf_smb_file_rw_offset, tvb, 0, 0, rwi->offset); + + proto_item_set_generated(it); + it = proto_tree_add_uint(tree, hf_smb_file_rw_length, tvb, 0, 0, rwi->len); + proto_item_set_generated(it); + + /* we need the fid for the call to dcerpc below */ + fid = rwi->fid; + } + + /* remaining */ + proto_tree_add_item(tree, hf_smb_remaining, tvb, offset, 2, ENC_LITTLE_ENDIAN); + offset += 2; + + /* data compaction mode */ + proto_tree_add_item(tree, hf_smb_dcm, tvb, offset, 2, ENC_LITTLE_ENDIAN); + offset += 2; + + /* 2 reserved bytes */ + proto_tree_add_item(tree, hf_smb_reserved, tvb, offset, 2, ENC_NA); + offset += 2; + + /* data len low */ + datalen_low = tvb_get_letohs(tvb, offset); + proto_tree_add_uint(tree, hf_smb_data_len_low, tvb, offset, 2, datalen_low); + offset += 2; + + /* data offset */ + dataoffset = tvb_get_letohs(tvb, offset); + proto_tree_add_uint(tree, hf_smb_data_offset, tvb, offset, 2, dataoffset); + offset += 2; + + /* + * XXX - the SNIA SMB spec says this is a USHORT, not a + * ULONG. + * + * XXX - we should really only do this in case we have seen + * LARGE FILE being negotiated. Unfortunately, we might not + * have seen the negotiation phase in the capture.... + */ + /* data length high */ + datalen_high = tvb_get_letohl(tvb, offset); + if (datalen_high == 0xffffffff) { + datalen_high = 0; + } else { + proto_tree_add_uint(tree, hf_smb_data_len_high, tvb, offset, 4, datalen_high); + } + offset += 4; + + datalen = datalen_high; + datalen = (datalen<<16) | datalen_low; + + + col_append_fstr(pinfo->cinfo, COL_INFO, + ", %u byte%s", datalen, + (datalen == 1) ? "" : "s"); + + + /* 6 reserved bytes */ + proto_tree_add_item(tree, hf_smb_reserved, tvb, offset, 6, ENC_NA); + offset += 6; + + BYTE_COUNT; + + /* file data, might be DCERPC on a pipe */ + if (bc) { + offset = dissect_file_data_maybe_dcerpc(tvb, pinfo, tree, + top_tree_global, offset, bc, -1, (guint16) datalen, 0, (guint16) fid, si); + bc = 0; + } + + /* feed the export object tap listener */ + tvblen = tvb_reported_length_remaining(tvb, dataoffset); + if (have_tap_listener(smb_eo_tap) && (datalen == tvblen) && rwi) { + feed_eo_smb(SMB_COM_READ_ANDX, fid, tvb, pinfo, dataoffset, datalen, rwi->len, rwi->offset, si); + } + + END_OF_SMB + + if (cmd != 0xff) { /* there is an andX command */ + if (andxoffset < offset) { + THROW(ReportedBoundsError); + } + dissect_smb_command(tvb, pinfo, andxoffset, smb_tree, cmd, FALSE, si); + } + + return offset; +} + +/* SMB_COM_WRITE_ANDX(0x2F) + https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-cifs/a66126d2-a1db-446b-8736-b9f5559c49bd +*/ +static int +dissect_write_andx_request(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int offset, proto_tree *smb_tree, smb_info_t *si) +{ + guint8 wc, cmd = 0xff; + guint16 andxoffset = 0, bc, dataoffset = 0, datalen_low, datalen_high; + guint32 offsetlow, offsethigh = 0; + guint64 ofs; + guint32 datalen = 0; + guint16 fid = 0; /* was unsigned int fid = 0; */ + guint16 mode = 0; + rw_info_t *rwi = NULL; + + guint32 tvblen; + + DISSECTOR_ASSERT(si); + + WORD_COUNT; + + /* next smb command */ + cmd = tvb_get_guint8(tvb, offset); + if (cmd != 0xff) { + proto_tree_add_uint(tree, hf_smb_andxcmd, tvb, offset, 1, cmd); + } else { + proto_tree_add_uint_format_value(tree, hf_smb_andxcmd, tvb, offset, 1, cmd, "No further commands (0xff)"); + } + offset += 1; + + /* reserved byte */ + proto_tree_add_item(tree, hf_smb_reserved, tvb, offset, 1, ENC_NA); + offset += 1; + + /* andxoffset */ + andxoffset = tvb_get_letohs(tvb, offset); + proto_tree_add_uint(tree, hf_smb_andxoffset, tvb, offset, 2, andxoffset); + offset += 2; + + /* fid */ + fid = tvb_get_letohs(tvb, offset); + dissect_smb_fid(tvb, pinfo, tree, offset, 2, (guint16) fid, FALSE, FALSE, FALSE, si); + offset += 2; + + /* offset */ + offsetlow = tvb_get_letohl(tvb, offset); + proto_tree_add_item(tree, hf_smb_offset, tvb, offset, 4, ENC_LITTLE_ENDIAN); + offset += 4; + + /* reserved */ + proto_tree_add_item(tree, hf_smb_reserved, tvb, offset, 4, ENC_NA); + offset += 4; + + /* mode */ + mode = tvb_get_letohs(tvb, offset); + offset = dissect_write_mode(tvb, tree, offset, 0x000f); + + /* remaining */ + proto_tree_add_item(tree, hf_smb_remaining, tvb, offset, 2, ENC_LITTLE_ENDIAN); + offset += 2; + + /* + * XXX - we should really only do this in case we have seen + * LARGE FILE being negotiated. Unfortunately, we might not + * have seen the negotiation phase in the capture.... + */ + /* data length high */ + datalen_high = tvb_get_letohs(tvb, offset); + proto_tree_add_uint(tree, hf_smb_data_len_high, tvb, offset, 2, datalen_high); + offset += 2; + + /* data len low */ + datalen_low = tvb_get_letohs(tvb, offset); + proto_tree_add_uint(tree, hf_smb_data_len_low, tvb, offset, 2, datalen_low); + offset += 2; + + datalen = datalen_high; + datalen = (datalen<<16) | datalen_low; + + /* data offset */ + dataoffset = tvb_get_letohs(tvb, offset); + proto_tree_add_uint(tree, hf_smb_data_offset, tvb, offset, 2, dataoffset); + offset += 2; + + if (wc == 14) { + /* high offset */ + offsethigh = tvb_get_letohl(tvb, offset); + proto_tree_add_item(tree, hf_smb_high_offset, tvb, offset, 4, ENC_LITTLE_ENDIAN); + offset += 4; + } + + ofs = offsethigh; + ofs = (ofs<<32) | offsetlow; + + col_append_fstr(pinfo->cinfo, COL_INFO, + ", %u byte%s at offset %" PRIu64, + datalen, (datalen == 1) ? "" : "s", ofs); + + /* save the offset/len for this transaction */ + if (si->sip && !pinfo->fd->visited) { + rwi = wmem_new(wmem_file_scope(), rw_info_t); + rwi->offset = ofs; + rwi->len = datalen; + rwi->fid = fid; + + si->sip->extra_info_type = SMB_EI_RWINFO; + si->sip->extra_info = rwi; + } + if (si->sip && (si->sip->extra_info_type == SMB_EI_RWINFO)) { + rwi = (rw_info_t *)si->sip->extra_info; + } + if (rwi) { + proto_item *it; + + it = proto_tree_add_uint64(tree, hf_smb_file_rw_offset, tvb, 0, 0, rwi->offset); + + proto_item_set_generated(it); + it = proto_tree_add_uint(tree, hf_smb_file_rw_length, tvb, 0, 0, rwi->len); + proto_item_set_generated(it); + } + + + BYTE_COUNT; + + /* if both the MessageStart and the WriteRawNamedPipe flags are set + the first two bytes of the payload is the length of the data. + Assume that all WriteAndX PDUs that have MESSAGE_START set to + be over the IPC$ share and thus they all transport DCERPC. + (if we didn't already know that from the TreeConnect call) + */ + if (mode&WRITE_MODE_MESSAGE_START) { + if (mode&WRITE_MODE_RAW) { + proto_tree_add_item(tree, hf_smb_pipe_write_len, tvb, offset, 2, ENC_LITTLE_ENDIAN); + offset += 2; + dataoffset += 2; + bc -= 2; + datalen -= 2; + } + if (!pinfo->fd->visited) { + /* In case we did not see the TreeConnect call, + store this TID here as well as a IPC TID + so we know that future Read/Writes to this + TID is (probably) DCERPC. + */ + if (g_hash_table_lookup(si->ct->tid_service, GUINT_TO_POINTER(si->tid))) { + g_hash_table_remove(si->ct->tid_service, GUINT_TO_POINTER(si->tid)); + } + g_hash_table_insert(si->ct->tid_service, GUINT_TO_POINTER(si->tid), (void *)TID_IPC); + } + if (si->sip) { + si->sip->flags |= SMB_SIF_TID_IS_IPC; + } + } + + /* file data, might be DCERPC on a pipe */ + if (bc != 0) { + /* https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-cifs/a66126d2-a1db-446b-8736-b9f5559c49bd + The DataOffset field can be used to relocate the SMB_Data.Bytes.Data + block to the end of the message,even if the message is a multi-part AndX + chain. If the SMB_Data.Bytes.Data block is relocated, the contents of + SMB_Data.Bytes will not be contiguous. + */ + offset = dissect_file_data_maybe_dcerpc(tvb, pinfo, tree, + top_tree_global, offset, bc, dataoffset, (guint16) datalen, 0, (guint16) fid, si); + bc = 0; + } + + /* feed the export object tap listener */ + tvblen = tvb_reported_length_remaining(tvb, dataoffset); + if (have_tap_listener(smb_eo_tap) && (datalen == tvblen) && rwi) { + feed_eo_smb(SMB_COM_WRITE_ANDX, fid, tvb, pinfo, dataoffset, datalen, rwi->len, rwi->offset, si); + } + + END_OF_SMB + + if (cmd != 0xff) { /* there is an andX command */ + if (andxoffset < offset) { + THROW(ReportedBoundsError); + } + dissect_smb_command(tvb, pinfo, andxoffset, smb_tree, cmd, FALSE, si); + } + + return offset; +} + +static int +dissect_write_andx_response(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int offset, proto_tree *smb_tree, smb_info_t *si) +{ + guint8 wc, cmd = 0xff; + guint16 andxoffset = 0, bc, count_low, count_high; + guint32 count = 0; + rw_info_t *rwi = NULL; + + DISSECTOR_ASSERT(si); + + WORD_COUNT; + + /* next smb command */ + cmd = tvb_get_guint8(tvb, offset); + if (cmd != 0xff) { + proto_tree_add_uint(tree, hf_smb_andxcmd, tvb, offset, 1, cmd); + } else { + proto_tree_add_uint_format_value(tree, hf_smb_andxcmd, tvb, offset, 1, cmd, "No further commands (0xff)"); + } + offset += 1; + + /* reserved byte */ + proto_tree_add_item(tree, hf_smb_reserved, tvb, offset, 1, ENC_NA); + offset += 1; + + /* andxoffset */ + andxoffset = tvb_get_letohs(tvb, offset); + proto_tree_add_uint(tree, hf_smb_andxoffset, tvb, offset, 2, andxoffset); + offset += 2; + + + if (si->sip && (si->sip->extra_info_type == SMB_EI_RWINFO)) { + rwi = (rw_info_t *)si->sip->extra_info; + } + if (rwi) { + proto_item *it; + + it = proto_tree_add_uint64(tree, hf_smb_file_rw_offset, tvb, 0, 0, rwi->offset); + + proto_item_set_generated(it); + it = proto_tree_add_uint(tree, hf_smb_file_rw_length, tvb, 0, 0, rwi->len); + proto_item_set_generated(it); + } + + + /* write count low */ + count_low = tvb_get_letohs(tvb, offset); + proto_tree_add_uint(tree, hf_smb_count_low, tvb, offset, 2, count_low); + offset += 2; + + /* remaining */ + proto_tree_add_item(tree, hf_smb_remaining, tvb, offset, 2, ENC_LITTLE_ENDIAN); + offset += 2; + + /* XXX we should really only do this in case we have seen LARGE FILE being negotiated */ + /* write count high */ + count_high = tvb_get_letohs(tvb, offset); + proto_tree_add_uint(tree, hf_smb_count_high, tvb, offset, 2, count_high); + offset += 2; + + count = count_high; + count = (count<<16) | count_low; + + col_append_fstr(pinfo->cinfo, COL_INFO, + ", %u byte%s", count, + (count == 1) ? "" : "s"); + + /* 2 reserved bytes */ + proto_tree_add_item(tree, hf_smb_reserved, tvb, offset, 2, ENC_NA); + offset += 2; + + BYTE_COUNT; + + END_OF_SMB + + if (cmd != 0xff) { /* there is an andX command */ + if (andxoffset < offset) { + THROW(ReportedBoundsError); + } + dissect_smb_command(tvb, pinfo, andxoffset, smb_tree, cmd, FALSE, si); + } + + return offset; +} + + +static const true_false_string tfs_setup_action_guest = { + "Logged in as GUEST", + "Not logged in as GUEST" +}; +static int +dissect_setup_action(tvbuff_t *tvb, proto_tree *parent_tree, int offset) +{ + static int * const flags[] = { + &hf_smb_setup_action_guest, + NULL + }; + + proto_tree_add_bitmask(parent_tree, tvb, offset, hf_smb_setup_action, ett_smb_setup_action, flags, ENC_LITTLE_ENDIAN); + offset += 2; + + return offset; +} + + +static int +dissect_session_setup_andx_request(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int offset, proto_tree *smb_tree, smb_info_t *si) +{ + guint8 wc, cmd = 0xff; + guint16 bc; + guint16 andxoffset = 0; + int an_len; + const char *an; + int dn_len; + const char *dn; + guint16 pwlen = 0; + guint16 sbloblen = 0, sbloblen_short; + guint16 apwlen = 0, upwlen = 0; + gboolean unicodeflag; + static int ntlmssp_tap_id = 0; + const ntlmssp_header_t *ntlmssph; + + if (!ntlmssp_tap_id) { + GString *error_string; + /* We don't specify any callbacks at all. + * Instead we manually fetch the tapped data after the + * security blob has been fully dissected and before + * we exit from this dissector. + */ + error_string = register_tap_listener("ntlmssp", NULL, NULL, + TL_IS_DISSECTOR_HELPER, NULL, NULL, NULL, NULL); + if (!error_string) { + ntlmssp_tap_id = find_tap_id("ntlmssp"); + } else { + g_string_free(error_string, TRUE); + } + } + + DISSECTOR_ASSERT(si); + + WORD_COUNT; + + /* next smb command */ + cmd = tvb_get_guint8(tvb, offset); + if (cmd != 0xff) { + proto_tree_add_uint(tree, hf_smb_andxcmd, tvb, offset, 1, cmd); + } else { + proto_tree_add_uint_format_value(tree, hf_smb_andxcmd, tvb, offset, 1, cmd, "No further commands (0xff)"); + } + offset += 1; + + /* reserved byte */ + proto_tree_add_item(tree, hf_smb_reserved, tvb, offset, 1, ENC_NA); + offset += 1; + + /* andxoffset */ + andxoffset = tvb_get_letohs(tvb, offset); + proto_tree_add_uint(tree, hf_smb_andxoffset, tvb, offset, 2, andxoffset); + offset += 2; + + /* Maximum Buffer Size */ + proto_tree_add_item(tree, hf_smb_max_buf_size, tvb, offset, 2, ENC_LITTLE_ENDIAN); + offset += 2; + + /* Maximum Multiplex Count */ + proto_tree_add_item(tree, hf_smb_max_mpx_count, tvb, offset, 2, ENC_LITTLE_ENDIAN); + offset += 2; + + /* VC Number */ + proto_tree_add_item(tree, hf_smb_vc_num, tvb, offset, 2, ENC_LITTLE_ENDIAN); + offset += 2; + + /* session key */ + proto_tree_add_item(tree, hf_smb_session_key, tvb, offset, 4, ENC_LITTLE_ENDIAN); + offset += 4; + + switch (wc) { + case 10: + /* password length, ASCII*/ + pwlen = tvb_get_letohs(tvb, offset); + proto_tree_add_uint(tree, hf_smb_password_len, + tvb, offset, 2, pwlen); + offset += 2; + + /* 4 reserved bytes */ + proto_tree_add_item(tree, hf_smb_reserved, tvb, offset, 4, ENC_NA); + offset += 4; + + break; + + case 12: + /* security blob length */ + sbloblen = tvb_get_letohs(tvb, offset); + proto_tree_add_uint(tree, hf_smb_security_blob_len, tvb, offset, 2, sbloblen); + offset += 2; + + /* 4 reserved bytes */ + proto_tree_add_item(tree, hf_smb_reserved, tvb, offset, 4, ENC_NA); + offset += 4; + + /* capabilities */ + dissect_negprot_capabilities(tvb, tree, offset); + offset += 4; + + break; + + case 13: + /* password length, ANSI*/ + apwlen = tvb_get_letohs(tvb, offset); + proto_tree_add_uint(tree, hf_smb_ansi_password_len, + tvb, offset, 2, apwlen); + offset += 2; + + /* password length, Unicode*/ + upwlen = tvb_get_letohs(tvb, offset); + proto_tree_add_uint(tree, hf_smb_unicode_password_len, + tvb, offset, 2, upwlen); + offset += 2; + + /* 4 reserved bytes */ + proto_tree_add_item(tree, hf_smb_reserved, tvb, offset, 4, ENC_NA); + offset += 4; + + /* capabilities */ + dissect_negprot_capabilities(tvb, tree, offset); + offset += 4; + + break; + } + + BYTE_COUNT; + + if (wc == 12) { + proto_item *blob_item; + + /* security blob */ + /* If it runs past the end of the captured data, don't + * try to put all of it into the protocol tree as the + * raw security blob; we might get an exception on + * short frames and then we will not see anything at all + * of the security blob. + */ + sbloblen_short = sbloblen; + if (sbloblen_short > tvb_reported_length_remaining(tvb, offset)) { + sbloblen_short = tvb_reported_length_remaining(tvb, offset); + } + blob_item = proto_tree_add_item(tree, hf_smb_security_blob, + tvb, offset, sbloblen_short, + ENC_NA); + + /* As an optimization, because Windows is perverse, + we check to see if NTLMSSP is the first part of the + blob, and if so, call the NTLMSSP dissector, + otherwise we call the GSS-API dissector. This is because + Windows can request RAW NTLMSSP, but will happily handle + a client that wraps NTLMSSP in SPNEGO + */ + + if (sbloblen) { + tvbuff_t *blob_tvb; + proto_tree *blob_tree; + + blob_tree = proto_item_add_subtree(blob_item, + ett_smb_secblob); + CHECK_BYTE_COUNT(sbloblen); + + /* + * Set the reported length of this to the reported + * length of the blob, rather than the amount of + * data available from the blob, so that we'll + * throw the right exception if it's too short. + */ + blob_tvb = tvb_new_subset_length_caplen(tvb, offset, sbloblen_short, + sbloblen); + + if (si && si->ct && si->ct->raw_ntlmssp && + (tvb_strneql(tvb, offset, "NTLMSSP", 7) == 0)) { + call_dissector(ntlmssp_handle, blob_tvb, pinfo, + blob_tree); + + } + else { + call_dissector(gssapi_handle, blob_tvb, + pinfo, blob_tree); + } + + /* If we have found a uid->acct_name mapping, store it */ + if (!pinfo->fd->visited && si->sip) { + int idx = 0; + if ((ntlmssph = (const ntlmssp_header_t *)fetch_tapped_data(ntlmssp_tap_id, idx + 1 )) != NULL) { + if (ntlmssph && (ntlmssph->type == 3)) { + smb_uid_t *smb_uid; + + smb_uid = wmem_new(wmem_file_scope(), smb_uid_t); + smb_uid->logged_in = -1; + smb_uid->logged_out = -1; + smb_uid->domain = wmem_strdup(wmem_file_scope(), ntlmssph->domain_name); + smb_uid->account = wmem_strdup(wmem_file_scope(), ntlmssph->acct_name); + + si->sip->extra_info = smb_uid; + si->sip->extra_info_type = SMB_EI_UID; + } + } + } + + COUNT_BYTES(sbloblen); + } + + /* OS + * Eventhough this field should honour the unicode flag + * some ms clients gets this wrong. + * At least XP SP1 sends this in ASCII + * even when the unicode flag is on. + * Test if the first three bytes are "Win" + * and if so just override the flag. + */ + unicodeflag = si->unicode; + if ( tvb_strneql(tvb, offset, "Win", 3) == 0 ) { + unicodeflag = FALSE; + } + an = get_unicode_or_ascii_string(tvb, &offset, + unicodeflag, &an_len, FALSE, FALSE, &bc); + if (an == NULL) + goto endofcommand; + proto_tree_add_string(tree, hf_smb_os, tvb, + offset, an_len, an); + COUNT_BYTES(an_len); + + /* LANMAN */ + /* XXX - pre-W2K NT systems appear to stick an extra 2 bytes of + * padding/null string/whatever in front of this. W2K doesn't + * appear to. I suspect that's a bug that got fixed; I also + * suspect that, in practice, nobody ever looks at that field + * because the bug didn't appear to get fixed until NT 5.0.... + * + * Eventhough this field should honour the unicode flag + * some ms clients gets this wrong. + * At least XP SP1 sends this in ASCII + * even when the unicode flag is on. + * Test if the first three bytes are "Win" + * and if so just override the flag. + */ + unicodeflag = si->unicode; + if ( tvb_strneql(tvb, offset, "Win", 3) == 0 ) { + unicodeflag = FALSE; + } + an = get_unicode_or_ascii_string(tvb, &offset, + unicodeflag, &an_len, FALSE, FALSE, &bc); + if (an == NULL) + goto endofcommand; + proto_tree_add_string(tree, hf_smb_lanman, tvb, + offset, an_len, an); + COUNT_BYTES(an_len); + + /* Primary domain */ + /* XXX - pre-W2K NT systems sometimes appear to stick an extra + * byte in front of this, at least if all the strings are + * ASCII and the account name is empty. Another bug? + */ + dn = get_unicode_or_ascii_string(tvb, &offset, + si->unicode, &dn_len, FALSE, FALSE, &bc); + if (dn == NULL) + goto endofcommand; + proto_tree_add_string(tree, hf_smb_primary_domain, tvb, + offset, dn_len, dn); + COUNT_BYTES(dn_len); + } else { + switch (wc) { + + case 10: + if (pwlen) { + /* password, ASCII */ + CHECK_BYTE_COUNT(pwlen); + proto_tree_add_item(tree, hf_smb_password, + tvb, offset, pwlen, ENC_NA); + COUNT_BYTES(pwlen); + } + + break; + + case 13: + if (apwlen) { + /* password, ANSI */ + CHECK_BYTE_COUNT(apwlen); + proto_tree_add_item(tree, hf_smb_ansi_password, + tvb, offset, apwlen, ENC_NA); + COUNT_BYTES(apwlen); + } + + if (upwlen) { + proto_item *item; + + /* password, Unicode */ + CHECK_BYTE_COUNT(upwlen); + item = proto_tree_add_item(tree, hf_smb_unicode_password, + tvb, offset, upwlen, ENC_NA); + + if (upwlen > 24) { + proto_tree *subtree; + subtree = proto_item_add_subtree(item, ett_smb_unicode_password); + dissect_ntlmv2_response(tvb, pinfo, subtree, offset, upwlen); + } + + COUNT_BYTES(upwlen); + } + + break; + } + + /* Account Name */ + an = get_unicode_or_ascii_string(tvb, &offset, + si->unicode, &an_len, FALSE, FALSE, &bc); + if (an == NULL) + goto endofcommand; + proto_tree_add_string(tree, hf_smb_account, tvb, offset, an_len, + an); + COUNT_BYTES(an_len); + + /* Primary domain */ + /* XXX - pre-W2K NT systems sometimes appear to stick an extra + * byte in front of this, at least if all the strings are + * ASCII and the account name is empty. Another bug? + */ + dn = get_unicode_or_ascii_string(tvb, &offset, + si->unicode, &dn_len, FALSE, FALSE, &bc); + if (dn == NULL) + goto endofcommand; + proto_tree_add_string(tree, hf_smb_primary_domain, tvb, + offset, dn_len, dn); + COUNT_BYTES(dn_len); + + col_append_str(pinfo->cinfo, COL_INFO, ", User: "); + + if (!dn[0] && !an[0]) + col_append_str(pinfo->cinfo, COL_INFO, "anonymous"); + else + col_append_fstr(pinfo->cinfo, COL_INFO, + "%s\\%s", + format_text(wmem_packet_scope(), (const guchar*)dn, strlen(dn)), + format_text(wmem_packet_scope(), (const guchar*)an, strlen(an))); + + /* OS */ + an = get_unicode_or_ascii_string(tvb, &offset, + si->unicode, &an_len, FALSE, FALSE, &bc); + if (an == NULL) + goto endofcommand; + proto_tree_add_string(tree, hf_smb_os, tvb, + offset, an_len, an); + COUNT_BYTES(an_len); + + /* LANMAN */ + /* XXX - pre-W2K NT systems appear to stick an extra 2 bytes of + * padding/null string/whatever in front of this. W2K doesn't + * appear to. I suspect that's a bug that got fixed; I also + * suspect that, in practice, nobody ever looks at that field + * because the bug didn't appear to get fixed until NT 5.0.... + */ + an = get_unicode_or_ascii_string(tvb, &offset, + si->unicode, &an_len, FALSE, FALSE, &bc); + if (an == NULL) + goto endofcommand; + proto_tree_add_string(tree, hf_smb_lanman, tvb, + offset, an_len, an); + COUNT_BYTES(an_len); + } + + END_OF_SMB + + if (cmd != 0xff) { /* there is an andX command */ + if (andxoffset < offset) { + THROW(ReportedBoundsError); + } + dissect_smb_command(tvb, pinfo, andxoffset, smb_tree, cmd, FALSE, si); + } + + return offset; +} + +static int +dissect_session_setup_andx_response(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int offset, proto_tree *smb_tree, smb_info_t *si) +{ + guint8 wc, cmd = 0xff; + guint16 andxoffset = 0, bc; + guint16 sbloblen = 0; + int an_len; + const char *an; + + DISSECTOR_ASSERT(si); + + WORD_COUNT; + + if (!pinfo->fd->visited && si->sip && si->sip->extra_info && + (si->sip->extra_info_type == SMB_EI_UID)) { + smb_uid_t *smb_uid; + + smb_uid = (smb_uid_t *)si->sip->extra_info; + smb_uid->logged_in = pinfo->num; + wmem_tree_insert32(si->ct->uid_tree, si->uid, smb_uid); + } + + /* next smb command */ + cmd = tvb_get_guint8(tvb, offset); + if (cmd != 0xff) { + proto_tree_add_uint(tree, hf_smb_andxcmd, tvb, offset, 1, cmd); + } else { + proto_tree_add_uint_format_value(tree, hf_smb_andxcmd, tvb, offset, 1, cmd, "No further commands (0xff)"); + } + offset += 1; + + /* reserved byte */ + proto_tree_add_item(tree, hf_smb_reserved, tvb, offset, 1, ENC_NA); + offset += 1; + + /* andxoffset */ + andxoffset = tvb_get_letohs(tvb, offset); + proto_tree_add_uint(tree, hf_smb_andxoffset, tvb, offset, 2, andxoffset); + offset += 2; + + /* flags */ + offset = dissect_setup_action(tvb, tree, offset); + + if (wc == 4) { + /* security blob length */ + sbloblen = tvb_get_letohs(tvb, offset); + proto_tree_add_uint(tree, hf_smb_security_blob_len, tvb, offset, 2, sbloblen); + offset += 2; + } + + BYTE_COUNT; + + if (wc == 4) { + proto_item *blob_item; + + /* security blob */ + /* don't try to eat too much of we might get an exception on + * short frames and then we will not see anything at all + * of the security blob. + */ + if (sbloblen > tvb_reported_length_remaining(tvb, offset)) { + sbloblen = tvb_reported_length_remaining(tvb, offset); + } + blob_item = proto_tree_add_item(tree, hf_smb_security_blob, + tvb, offset, sbloblen, ENC_NA); + + if (sbloblen) { + tvbuff_t *blob_tvb; + proto_tree *blob_tree; + + blob_tree = proto_item_add_subtree(blob_item, + ett_smb_secblob); + CHECK_BYTE_COUNT(sbloblen); + + blob_tvb = tvb_new_subset_length(tvb, offset, sbloblen); + + if (si && si->ct && si->ct->raw_ntlmssp && + (tvb_strneql(tvb, offset, "NTLMSSP", 7) == 0)) { + call_dissector(ntlmssp_handle, blob_tvb, pinfo, + blob_tree); + + } + else { + call_dissector(gssapi_handle, blob_tvb, pinfo, + blob_tree); + + } + + COUNT_BYTES(sbloblen); + } + } + + /* OS */ + an = get_unicode_or_ascii_string(tvb, &offset, + si->unicode, &an_len, FALSE, FALSE, &bc); + if (an == NULL) + goto endofcommand; + proto_tree_add_string(tree, hf_smb_os, tvb, + offset, an_len, an); + COUNT_BYTES(an_len); + + /* LANMAN */ + an = get_unicode_or_ascii_string(tvb, &offset, + si->unicode, &an_len, FALSE, FALSE, &bc); + if (an == NULL) + goto endofcommand; + proto_tree_add_string(tree, hf_smb_lanman, tvb, + offset, an_len, an); + COUNT_BYTES(an_len); + + if ((wc == 3) || (wc == 4)) { + /* Primary domain */ + an = get_unicode_or_ascii_string(tvb, &offset, + si->unicode, &an_len, FALSE, FALSE, &bc); + if (an == NULL) + goto endofcommand; + proto_tree_add_string(tree, hf_smb_primary_domain, tvb, + offset, an_len, an); + COUNT_BYTES(an_len); + } + + END_OF_SMB + + if (cmd != 0xff) { /* there is an andX command */ + if (andxoffset < offset) { + THROW(ReportedBoundsError); + } + dissect_smb_command(tvb, pinfo, andxoffset, smb_tree, cmd, FALSE, si); + } + + return offset; +} + + +static int +dissect_empty_andx(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int offset, proto_tree *smb_tree, smb_info_t *si _U_) +{ + guint8 wc, cmd = 0xff; + guint16 andxoffset = 0; + guint16 bc; + + WORD_COUNT; + + /* next smb command */ + cmd = tvb_get_guint8(tvb, offset); + if (cmd != 0xff) { + proto_tree_add_uint(tree, hf_smb_andxcmd, tvb, offset, 1, cmd); + } else { + proto_tree_add_uint_format_value(tree, hf_smb_andxcmd, tvb, offset, 1, cmd, "No further commands (0xff)"); + } + offset += 1; + + /* reserved byte */ + proto_tree_add_item(tree, hf_smb_reserved, tvb, offset, 1, ENC_NA); + offset += 1; + + /* andxoffset */ + andxoffset = tvb_get_letohs(tvb, offset); + proto_tree_add_uint(tree, hf_smb_andxoffset, tvb, offset, 2, andxoffset); + offset += 2; + + BYTE_COUNT; + + END_OF_SMB + + if (cmd != 0xff) { /* there is an andX command */ + if (andxoffset < offset) { + THROW(ReportedBoundsError); + } + dissect_smb_command(tvb, pinfo, andxoffset, smb_tree, cmd, FALSE, si); + } + + return offset; +} + + /* + * From [MS-SMB] - v20100711 Server Message Block (SMB) Protocol Specification + * http://download.microsoft.com/download/a/e/6/ae6e4142-aa58-45c6-8dcf-a657e5900cd3/%5BMS-SMB%5D.pdf + * 2.2.4.7 SMB_COM_TREE_CONNECT_ANDX (0x75) + */ + +static const true_false_string tfs_connect_support_search = { + "Exclusive search bits supported", + "Exclusive search bits not supported" +}; +static const true_false_string tfs_connect_support_in_dfs = { + "Share is in Dfs", + "Share isn't in Dfs" +}; +static const value_string connect_support_csc_mask_vals[] = { + { 0, "Automatic file-to-file reintegration NOT permitted"}, + { 1, "Automatic file-to-file reintegration permitted"}, + { 2, "Offline caching allow for the share"}, + { 3, "Offline caching NOT allow for the share"}, + {0, NULL} +}; +static const true_false_string tfs_connect_support_uniquefilename = { + "Client allowed to cache share namespaces", + "Client NOT allowed to cache share namespaces" +}; +static const true_false_string tfs_connect_support_extended_signature = { + "Extended signature", + "NOT extended signature" +}; + +static int +dissect_connect_support_bits(tvbuff_t *tvb, proto_tree *parent_tree, int offset) +{ + static int * const flags[] = { + &hf_smb_connect_support_search, + &hf_smb_connect_support_in_dfs, + &hf_smb_connect_support_csc_mask_vals, + &hf_smb_connect_support_uniquefilename, + &hf_smb_connect_support_extended_signature, + NULL + }; + + proto_tree_add_bitmask(parent_tree, tvb, offset, hf_smb_connect_support, ett_smb_connect_support_bits, flags, ENC_LITTLE_ENDIAN); + offset += 2; + + return offset; +} + +static const true_false_string tfs_disconnect_tid = { + "DISCONNECT TID", + "Do NOT disconnect TID" +}; + +static const true_false_string tfs_extended_signature = { + "Extended Signature", + "NOT Extended Signature" +}; + +static const true_false_string tfs_extended_response = { + "Extended Response", + "NOT Extended Response" +}; + +static int +dissect_connect_flags(tvbuff_t *tvb, proto_tree *parent_tree, int offset) +{ + static int * const flags[] = { + &hf_smb_connect_flags_dtid, + &hf_smb_connect_flags_ext_sig, + &hf_smb_connect_flags_ext_resp, + NULL + }; + + proto_tree_add_bitmask(parent_tree, tvb, offset, hf_smb_connect_flags, ett_smb_connect_flags, flags, ENC_LITTLE_ENDIAN); + offset += 2; + + return offset; +} + +static int +dissect_tree_connect_andx_request(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int offset, proto_tree *smb_tree, smb_info_t *si) +{ + guint8 wc, cmd = 0xff; + guint16 bc; + guint16 andxoffset = 0, pwlen = 0; + int an_len; + const guint8 *an; + + DISSECTOR_ASSERT(si); + + WORD_COUNT; + + /* next smb command */ + cmd = tvb_get_guint8(tvb, offset); + if (cmd != 0xff) { + proto_tree_add_uint(tree, hf_smb_andxcmd, tvb, offset, 1, cmd); + } else { + proto_tree_add_uint_format_value(tree, hf_smb_andxcmd, tvb, offset, 1, cmd, "No further commands (0xff)"); + } + offset += 1; + + /* reserved byte */ + proto_tree_add_item(tree, hf_smb_reserved, tvb, offset, 1, ENC_NA); + offset += 1; + + /* andxoffset */ + andxoffset = tvb_get_letohs(tvb, offset); + proto_tree_add_uint(tree, hf_smb_andxoffset, tvb, offset, 2, andxoffset); + offset += 2; + + /* flags */ + offset = dissect_connect_flags(tvb, tree, offset); + + /* password length*/ + pwlen = tvb_get_letohs(tvb, offset); + proto_tree_add_uint(tree, hf_smb_password_len, tvb, offset, 2, pwlen); + offset += 2; + + BYTE_COUNT; + + /* password */ + CHECK_BYTE_COUNT(pwlen); + proto_tree_add_item(tree, hf_smb_password, + tvb, offset, pwlen, ENC_NA); + COUNT_BYTES(pwlen); + + /* Path */ + an = get_unicode_or_ascii_string(tvb, &offset, + si->unicode, &an_len, FALSE, FALSE, &bc); + if (an == NULL) + goto endofcommand; + proto_tree_add_string(tree, hf_smb_path, tvb, + offset, an_len, an); + COUNT_BYTES(an_len); + + /* store it for the tid->name/openframe/closeframe matching in + * dissect_smb_tid() called from the response. + */ + if ((!pinfo->fd->visited) && si->sip && an) { + si->sip->extra_info_type = SMB_EI_TIDNAME; + si->sip->extra_info = wmem_strdup(wmem_file_scope(), an); + } + + col_append_fstr(pinfo->cinfo, COL_INFO, ", Path: %s", + format_text(wmem_packet_scope(), (const guchar*)an, strlen(an))); + + /* + * NOTE: the Service string is always ASCII, even if the + * "strings are Unicode" bit is set in the flags2 field + * of the SMB. + */ + + /* Service */ + /* XXX - what if this runs past bc? */ + an_len = tvb_strsize(tvb, offset); + CHECK_BYTE_COUNT(an_len); + proto_tree_add_item_ret_string(tree, hf_smb_service, tvb, + offset, an_len, ENC_ASCII|ENC_NA, wmem_packet_scope(), &an); + COUNT_BYTES(an_len); + + END_OF_SMB + + if (cmd != 0xff) { /* there is an andX command */ + if (andxoffset < offset) { + THROW(ReportedBoundsError); + } + dissect_smb_command(tvb, pinfo, andxoffset, smb_tree, cmd, FALSE, si); + } + + return offset; +} + + +static int +dissect_tree_connect_andx_response(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int offset, proto_tree *smb_tree, smb_info_t *si) +{ + guint8 wc, cmd = 0xff; + guint16 andxoffset = 0; + guint16 bc; + int an_len; + const guint8 *an; + + DISSECTOR_ASSERT(si); + + WORD_COUNT; + + /* next smb command */ + cmd = tvb_get_guint8(tvb, offset); + if (cmd != 0xff) { + proto_tree_add_uint(tree, hf_smb_andxcmd, tvb, offset, 1, cmd); + } else { + proto_tree_add_uint_format_value(tree, hf_smb_andxcmd, tvb, offset, 1, cmd, "No further commands (0xff)"); + } + offset += 1; + + /* reserved byte */ + proto_tree_add_item(tree, hf_smb_reserved, tvb, offset, 1, ENC_NA); + offset += 1; + + /* andxoffset */ + andxoffset = tvb_get_letohs(tvb, offset); + proto_tree_add_uint(tree, hf_smb_andxoffset, tvb, offset, 2, andxoffset); + offset += 2; + + /* There are three valid formats of tree connect response. + All have the first two words: andx_cmd, andx_off, + and then have additional words as follows: + wc=2: (ancient LanMan -- no more words) + wc=3: (NT, non-ext) opt_support + wc=7: (NT, extended) opt_support, + tree_access(2w), guest_access(2w) + byte_count follows those words as usual */ + + if (wc >= 3) { + /* flags */ + offset = dissect_connect_support_bits(tvb, tree, offset); + } + + if (wc == 7) { + /* + * Refer to [MS-SMB] - v20100711 + * When a server returns extended information, the response + * takes the following format, with WordCount = 7. + * MaximalShareAccessRights, and GuestMaximalShareAccessRights fields + * has added. + */ + proto_tree *tr; + tr = proto_tree_add_subtree(tree, tvb, offset, 4, + ett_smb_nt_access_mask, NULL, "Maximal Share Access Rights"); + offset = dissect_smb_access_mask(tvb, tr, offset); + + tr = proto_tree_add_subtree(tree, tvb, offset, 4, + ett_smb_nt_access_mask, NULL, "Guest Maximal Share Access Rights"); + offset = dissect_smb_access_mask(tvb, tr, offset); + } + + BYTE_COUNT; + + /* + * NOTE: even though the SNIA CIFS spec doesn't say there's + * a "Service" string if there's a word count of 2, the + * document at + * + * ftp://ftp.microsoft.com/developr/drg/CIFS/dosextp.txt + * + * (it's in an ugly format - text intended to be sent to a + * printer, with backspaces and overstrikes used for boldfacing + * and underlining; UNIX "col -b" can be used to strip the + * overstrikes out) says there's a "Service" string there, and + * some network traffic has it. + */ + + /* + * NOTE: the Service string is always ASCII, even if the + * "strings are Unicode" bit is set in the flags2 field + * of the SMB. + */ + + /* Service */ + /* XXX - what if this runs past bc? */ + an_len = tvb_strsize(tvb, offset); + CHECK_BYTE_COUNT(an_len); + proto_tree_add_item_ret_string(tree, hf_smb_service, tvb, + offset, an_len, ENC_ASCII|ENC_NA, wmem_packet_scope(), &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->visited) { + /* Remove any previous entry for this TID */ + if (g_hash_table_lookup(si->ct->tid_service, GUINT_TO_POINTER(si->tid))) { + g_hash_table_remove(si->ct->tid_service, GUINT_TO_POINTER(si->tid)); + } + if (strcmp(an, "IPC") == 0) { + g_hash_table_insert(si->ct->tid_service, GUINT_TO_POINTER(si->tid), (void *)TID_IPC); + } else { + g_hash_table_insert(si->ct->tid_service, GUINT_TO_POINTER(si->tid), (void *)TID_NORMAL); + } + } + + if (bc != 0) { + /* + * Sometimes this isn't present. + */ + + /* Native FS */ + an = get_unicode_or_ascii_string(tvb, &offset, + si->unicode, &an_len, /*TRUE*/FALSE, FALSE, + &bc); + if (an == NULL) + goto endofcommand; + proto_tree_add_string(tree, hf_smb_fs, tvb, + offset, an_len, an); + COUNT_BYTES(an_len); + } + + END_OF_SMB + + if (cmd != 0xff) { /* there is an andX command */ + if (andxoffset < offset) { + THROW(ReportedBoundsError); + } + dissect_smb_command(tvb, pinfo, andxoffset, smb_tree, cmd, FALSE, si); + } + + return offset; +} + + + +/* XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX + NT Transaction command begins here + XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX */ +#define NT_TRANS_CREATE 1 +#define NT_TRANS_IOCTL 2 +#define NT_TRANS_SSD 3 +#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_GET_USER_QUOTA, "NT GET USER QUOTA"}, + {NT_TRANS_SET_USER_QUOTA, "NT SET USER QUOTA"}, + {0, NULL} +}; +value_string_ext nt_cmd_vals_ext = VALUE_STRING_EXT_INIT(nt_cmd_vals); + +static const value_string nt_ioctl_isfsctl_vals[] = { + {0, "Device IOCTL"}, + {1, "FS control : FSCTL"}, + {0, NULL} +}; + +#define NT_IOCTL_FLAGS_ROOT_HANDLE 0x01 +static const true_false_string tfs_nt_ioctl_flags_root_handle = { + "Apply the command to share root handle (MUST BE Dfs)", + "Apply to this share", +}; + +static const value_string nt_notify_action_vals[] = { + {1, "ADDED (object was added"}, + {2, "REMOVED (object was removed)"}, + {3, "MODIFIED (object was modified)"}, + {4, "RENAMED_OLD_NAME (this is the old name of object)"}, + {5, "RENAMED_NEW_NAME (this is the new name of object)"}, + {6, "ADDED_STREAM (a stream was added)"}, + {7, "REMOVED_STREAM (a stream was removed)"}, + {8, "MODIFIED_STREAM (a stream was modified)"}, + {0, NULL} +}; + +static const value_string watch_tree_vals[] = { + {0, "Current directory only"}, + {1, "Subdirectories also"}, + {0, NULL} +}; + +#define NT_NOTIFY_STREAM_WRITE 0x00000800 +#define NT_NOTIFY_STREAM_SIZE 0x00000400 +#define NT_NOTIFY_STREAM_NAME 0x00000200 +#define NT_NOTIFY_SECURITY 0x00000100 +#define NT_NOTIFY_EA 0x00000080 +#define NT_NOTIFY_CREATION 0x00000040 +#define NT_NOTIFY_LAST_ACCESS 0x00000020 +#define NT_NOTIFY_LAST_WRITE 0x00000010 +#define NT_NOTIFY_SIZE 0x00000008 +#define NT_NOTIFY_ATTRIBUTES 0x00000004 +#define NT_NOTIFY_DIR_NAME 0x00000002 +#define NT_NOTIFY_FILE_NAME 0x00000001 +static const true_false_string tfs_nt_notify_stream_write = { + "Notify on changes to STREAM WRITE", + "Do NOT notify on changes to stream write", +}; +static const true_false_string tfs_nt_notify_stream_size = { + "Notify on changes to STREAM SIZE", + "Do NOT notify on changes to stream size", +}; +static const true_false_string tfs_nt_notify_stream_name = { + "Notify on changes to STREAM NAME", + "Do NOT notify on changes to stream name", +}; +static const true_false_string tfs_nt_notify_security = { + "Notify on changes to SECURITY", + "Do NOT notify on changes to security", +}; +static const true_false_string tfs_nt_notify_ea = { + "Notify on changes to EA", + "Do NOT notify on changes to EA", +}; +static const true_false_string tfs_nt_notify_creation = { + "Notify on changes to CREATION TIME", + "Do NOT notify on changes to creation time", +}; +static const true_false_string tfs_nt_notify_last_access = { + "Notify on changes to LAST ACCESS TIME", + "Do NOT notify on changes to last access time", +}; +static const true_false_string tfs_nt_notify_last_write = { + "Notify on changes to LAST WRITE TIME", + "Do NOT notify on changes to last write time", +}; +static const true_false_string tfs_nt_notify_size = { + "Notify on changes to SIZE", + "Do NOT notify on changes to size", +}; +static const true_false_string tfs_nt_notify_attributes = { + "Notify on changes to ATTRIBUTES", + "Do NOT notify on changes to attributes", +}; +static const true_false_string tfs_nt_notify_dir_name = { + "Notify on changes to DIR NAME", + "Do NOT notify on changes to dir name", +}; +static const true_false_string tfs_nt_notify_file_name = { + "Notify on changes to FILE NAME", + "Do NOT notify on changes to file name", +}; + +const value_string create_disposition_vals[] = { + {0, "Supersede (supersede existing file (if it exists))"}, + {1, "Open (if file exists open it, else fail)"}, + {2, "Create (if file exists fail, else create it)"}, + {3, "Open If (if file exists open it, else create it)"}, + {4, "Overwrite (if file exists overwrite, else fail)"}, + {5, "Overwrite If (if file exists overwrite, else create it)"}, + {0, NULL} +}; + +const value_string impersonation_level_vals[] = { + {0, "Anonymous"}, + {1, "Identification"}, + {2, "Impersonation"}, + {3, "Delegation"}, + {0, NULL} +}; + +static const true_false_string tfs_nt_security_flags_context_tracking = { + "Security tracking mode is DYNAMIC", + "Security tracking mode is STATIC", +}; + +static const true_false_string tfs_nt_security_flags_effective_only = { + "ONLY ENABLED aspects of the client's security context are available", + "ALL aspects of the client's security context are available", +}; + +static const true_false_string tfs_nt_create_bits_oplock = { + "Requesting OPLOCK", + "Does NOT request oplock" +}; + +static const true_false_string tfs_nt_create_bits_boplock = { + "Requesting BATCH OPLOCK", + "Does NOT request batch oplock" +}; + +/* + * XXX - must be a directory, and can be a file, or can be a directory, + * and must be a file? + */ +static const true_false_string tfs_nt_create_bits_dir = { + "Target of open MUST be a DIRECTORY", + "Target of open can be a file" +}; + +static const true_false_string tfs_nt_create_bits_ext_resp = { + "Extended responses required", + "Extended responses NOT required" +}; + +static const true_false_string tfs_nt_access_mask_generic_read = { + "GENERIC READ is set", + "Generic read is NOT set" +}; +static const true_false_string tfs_nt_access_mask_generic_write = { + "GENERIC WRITE is set", + "Generic write is NOT set" +}; +static const true_false_string tfs_nt_access_mask_generic_execute = { + "GENERIC EXECUTE is set", + "Generic execute is NOT set" +}; +static const true_false_string tfs_nt_access_mask_generic_all = { + "GENERIC ALL is set", + "Generic all is NOT set" +}; +static const true_false_string tfs_nt_access_mask_maximum_allowed = { + "MAXIMUM ALLOWED is set", + "Maximum allowed is NOT set" +}; +static const true_false_string tfs_nt_access_mask_system_security = { + "SYSTEM SECURITY is set", + "System security is NOT set" +}; +static const true_false_string tfs_nt_access_mask_synchronize = { + "Can wait on handle to SYNCHRONIZE on completion of I/O", + "Can NOT wait on handle to synchronize on completion of I/O" +}; +static const true_false_string tfs_nt_access_mask_write_owner = { + "Can WRITE OWNER (take ownership)", + "Can NOT write owner (take ownership)" +}; +static const true_false_string tfs_nt_access_mask_write_dac = { + "OWNER may WRITE the DAC", + "Owner may NOT write to the DAC" +}; +static const true_false_string tfs_nt_access_mask_read_control = { + "READ ACCESS to owner, group and ACL of the SID", + "Read access is NOT granted to owner, group and ACL of the SID" +}; +static const true_false_string tfs_nt_access_mask_delete = { + "DELETE access", + "NO delete access" +}; +static const true_false_string tfs_nt_access_mask_write_attributes = { + "WRITE ATTRIBUTES access", + "NO write attributes access" +}; +static const true_false_string tfs_nt_access_mask_read_attributes = { + "READ ATTRIBUTES access", + "NO read attributes access" +}; +static const true_false_string tfs_nt_access_mask_delete_child = { + "DELETE CHILD access", + "NO delete child access" +}; +static const true_false_string tfs_nt_access_mask_execute = { + "EXECUTE access", + "NO execute access" +}; +static const true_false_string tfs_nt_access_mask_write_ea = { + "WRITE EXTENDED ATTRIBUTES access", + "NO write extended attributes access" +}; +static const true_false_string tfs_nt_access_mask_read_ea = { + "READ EXTENDED ATTRIBUTES access", + "NO read extended attributes access" +}; +static const true_false_string tfs_nt_access_mask_append = { + "APPEND access", + "NO append access" +}; +static const true_false_string tfs_nt_access_mask_write = { + "WRITE access", + "NO write access" +}; +static const true_false_string tfs_nt_access_mask_read = { + "READ access", + "NO read access" +}; + +static const true_false_string tfs_nt_share_access_delete = { + "Object can be shared for DELETE", + "Object can NOT be shared for delete" +}; +static const true_false_string tfs_nt_share_access_write = { + "Object can be shared for WRITE", + "Object can NOT be shared for write" +}; +static const true_false_string tfs_nt_share_access_read = { + "Object can be shared for READ", + "Object can NOT be shared for read" +}; + +static const value_string oplock_level_vals[] = { + {0, "No oplock granted"}, + {1, "Exclusive oplock granted"}, + {2, "Batch oplock granted"}, + {3, "Level II oplock granted"}, + {0, NULL} +}; + +static const value_string response_type_vals[] = { + {0x00, "Non-extended response"}, + {0x01, "Extended response"}, + {0, NULL} +}; + +static const value_string device_type_vals[] = { + {0x00000001, "Beep"}, + {0x00000002, "CDROM"}, + {0x00000003, "CDROM Filesystem"}, + {0x00000004, "Controller"}, + {0x00000005, "Datalink"}, + {0x00000006, "Dfs"}, + {0x00000007, "Disk"}, + {0x00000008, "Disk Filesystem"}, + {0x00000009, "Filesystem"}, + {0x0000000a, "Inport Port"}, + {0x0000000b, "Keyboard"}, + {0x0000000c, "Mailslot"}, + {0x0000000d, "MIDI-In"}, + {0x0000000e, "MIDI-Out"}, + {0x0000000f, "Mouse"}, + {0x00000010, "Multi UNC Provider"}, + {0x00000011, "Named Pipe"}, + {0x00000012, "Network"}, + {0x00000013, "Network Browser"}, + {0x00000014, "Network Filesystem"}, + {0x00000015, "NULL"}, + {0x00000016, "Parallel Port"}, + {0x00000017, "Physical card"}, + {0x00000018, "Printer"}, + {0x00000019, "Scanner"}, + {0x0000001a, "Serial Mouse port"}, + {0x0000001b, "Serial port"}, + {0x0000001c, "Screen"}, + {0x0000001d, "Sound"}, + {0x0000001e, "Streams"}, + {0x0000001f, "Tape"}, + {0x00000020, "Tape Filesystem"}, + {0x00000021, "Transport"}, + {0x00000022, "Unknown"}, + {0x00000023, "Video"}, + {0x00000024, "Virtual Disk"}, + {0x00000025, "WAVE-In"}, + {0x00000026, "WAVE-Out"}, + {0x00000027, "8042 Port"}, + {0x00000028, "Network Redirector"}, + {0x00000029, "Battery"}, + {0x0000002a, "Bus Extender"}, + {0x0000002b, "Modem"}, + {0x0000002c, "VDM"}, + {0, NULL} +}; +static value_string_ext device_type_vals_ext = VALUE_STRING_EXT_INIT(device_type_vals); + +static const value_string is_directory_vals[] = { + {0, "This is NOT a directory"}, + {1, "This is a DIRECTORY"}, + {0, NULL} +}; + +static int +dissect_nt_security_flags(tvbuff_t *tvb, proto_tree *parent_tree, int offset) +{ + static int * const flags[] = { + &hf_smb_nt_security_flags_context_tracking, + &hf_smb_nt_security_flags_effective_only, + NULL + }; + + proto_tree_add_bitmask(parent_tree, tvb, offset, hf_smb_nt_security_flags, ett_smb_nt_security_flags, flags, ENC_NA); + offset += 1; + + return offset; +} + +/* + * XXX - there are some more flags in the description of "ZwOpenFile()" + * in "Windows(R) NT(R)/2000 Native API Reference"; do those go over + * the wire as well? (The spec at + * + * http://www.samba.org/samba/ftp/specs/smb-nt01.doc + * + * says that "the FILE_NO_INTERMEDIATE_BUFFERING option is not exported + * via the SMB protocol. The NT redirector should convert this option + * to FILE_WRITE_THROUGH." + * + * The "Sync I/O Alert" and "Sync I/O Nonalert" are given the bit + * values one would infer from their position in the list of flags for + * "ZwOpenFile()". Most of the others probably have those values + * as well, although "8.3 only" would collide with FILE_OPEN_FOR_RECOVERY, + * which might go over the wire (for the benefit of backup/restore software). + */ +static const true_false_string tfs_nt_create_options_directory = { + "File being created/opened must be a directory", + "File being created/opened must not be a directory" +}; +static const true_false_string tfs_nt_create_options_write_through = { + "Writes should flush buffered data before completing", + "Writes need not flush buffered data before completing" +}; +static const true_false_string tfs_nt_create_options_sequential_only = { + "The file will only be accessed sequentially", + "The file might not only be accessed sequentially" +}; +static const true_false_string tfs_nt_create_options_no_intermediate_buffering = { + "NO intermediate buffering is allowed", + "Intermediate buffering is allowed" +}; +static const true_false_string tfs_nt_create_options_sync_io_alert = { + "All operations SYNCHRONOUS, waits subject to termination from alert", + "Operations NOT necessarily synchronous" +}; +static const true_false_string tfs_nt_create_options_sync_io_nonalert = { + "All operations SYNCHRONOUS, waits not subject to alert", + "Operations NOT necessarily synchronous" +}; +static const true_false_string tfs_nt_create_options_non_directory = { + "File being created/opened must not be a directory", + "File being created/opened must be a directory" +}; +static const true_false_string tfs_nt_create_options_create_tree_connection = { + "Create Tree Connections is SET", + "Create Tree Connections is NOT set" +}; +static const true_false_string tfs_nt_create_options_complete_if_oplocked = { + "Complete if oplocked is SET", + "Complete if oplocked is NOT set" +}; +static const true_false_string tfs_nt_create_options_no_ea_knowledge = { + "The client does not understand extended attributes", + "The client understands extended attributes" +}; +static const true_false_string tfs_nt_create_options_eight_dot_three_only = { + "The client understands only 8.3 file names", + "The client understands long file names" +}; +static const true_false_string tfs_nt_create_options_random_access = { + "The file will be accessed randomly", + "The file will not be accessed randomly" +}; +static const true_false_string tfs_nt_create_options_delete_on_close = { + "The file should be deleted when it is closed", + "The file should not be deleted when it is closed" +}; +static const true_false_string tfs_nt_create_options_open_by_fileid = { + "OpenByFileID bit is SET", + "OpenByFileID is NOT set" +}; +static const true_false_string tfs_nt_create_options_backup_intent = { + "This is a create with BACKUP INTENT", + "This is a normal create" +}; +static const true_false_string tfs_nt_create_options_no_compression = { + "Open/Create with NO Compression", + "Compression is allowed for Open/Create" +}; +static const true_false_string tfs_nt_create_options_reserve_opfilter = { + "Reserve Opfilter is SET", + "Reserve Opfilter is NOT set" +}; +static const true_false_string tfs_nt_create_options_open_reparse_point = { + "Open a Reparse Point", + "Normal open" +}; +static const true_false_string tfs_nt_create_options_open_no_recall = { + "Open No Recall is SET", + "Open no recall is NOT set" +}; +static const true_false_string tfs_nt_create_options_open_for_free_space_query = { + "This is an OPEN FOR FREE SPACE QUERY", + "This is NOT an open for free space query" +}; + +int +dissect_nt_notify_completion_filter(tvbuff_t *tvb, proto_tree *parent_tree, int offset) +{ + static int * const flags[] = { + &hf_smb_nt_notify_file_name, + &hf_smb_nt_notify_dir_name, + &hf_smb_nt_notify_attributes, + &hf_smb_nt_notify_size, + &hf_smb_nt_notify_last_write, + &hf_smb_nt_notify_last_access, + &hf_smb_nt_notify_creation, + &hf_smb_nt_notify_ea, + &hf_smb_nt_notify_security, + &hf_smb_nt_notify_stream_name, + &hf_smb_nt_notify_stream_size, + &hf_smb_nt_notify_stream_write, + NULL + }; + + proto_tree_add_bitmask(parent_tree, tvb, offset, hf_smb_nt_notify_completion_filter, ett_smb_nt_notify_completion_filter, flags, ENC_LITTLE_ENDIAN); + offset += 4; + + return offset; +} + +static int +dissect_nt_ioctl_flags(tvbuff_t *tvb, proto_tree *parent_tree, int offset) +{ + static int * const flags[] = { + &hf_smb_nt_ioctl_flags_root_handle, + NULL + }; + + proto_tree_add_bitmask(parent_tree, tvb, offset, hf_smb_nt_ioctl_flags_completion_filter, ett_smb_nt_ioctl_flags, flags, ENC_NA); + offset += 1; + + return offset; +} + +/* + * From the section on ZwQuerySecurityObject in "Windows(R) NT(R)/2000 + * Native API Reference". + */ +static const true_false_string tfs_nt_qsd_owner = { + "Requesting OWNER security information", + "NOT requesting owner security information", +}; + +static const true_false_string tfs_nt_qsd_group = { + "Requesting GROUP security information", + "NOT requesting group security information", +}; + +static const true_false_string tfs_nt_qsd_dacl = { + "Requesting DACL security information", + "NOT requesting DACL security information", +}; + +static const true_false_string tfs_nt_qsd_sacl = { + "Requesting SACL security information", + "NOT requesting SACL security information", +}; + +#define NT_QSD_OWNER 0x00000001 +#define NT_QSD_GROUP 0x00000002 +#define NT_QSD_DACL 0x00000004 +#define NT_QSD_SACL 0x00000008 + +int +dissect_security_information_mask(tvbuff_t *tvb, proto_tree *parent_tree, int offset) +{ + static int * const flags[] = { + &hf_smb_nt_qsd_owner, + &hf_smb_nt_qsd_group, + &hf_smb_nt_qsd_dacl, + &hf_smb_nt_qsd_sacl, + NULL + }; + + proto_tree_add_bitmask(parent_tree, tvb, offset, hf_smb_nt_qsd, ett_smb_security_information_mask, flags, ENC_LITTLE_ENDIAN); + offset += 4; + + return offset; +} + +int +dissect_nt_user_quota(tvbuff_t *tvb, 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_item(tree, hf_smb_length_of_sid, tvb, offset, 4, ENC_LITTLE_ENDIAN); + COUNT_BYTES_TRANS_SUBR(4); + + /* change time */ + CHECK_BYTE_COUNT_TRANS_SUBR(8); + offset = dissect_nt_64bit_time(tvb, tree, offset, + hf_smb_user_quota_change_time); + + /* 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, ENC_LITTLE_ENDIAN); + 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, ENC_LITTLE_ENDIAN); + 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, ENC_LITTLE_ENDIAN); + COUNT_BYTES_TRANS_SUBR(8); + + /* SID of the user */ + old_sid_offset = offset; + offset = dissect_nt_sid(tvb, offset, tree, "Quota", NULL, -1); + *bcp -= (offset-old_sid_offset); + + if (qsize) { + offset = old_offset+qsize; + } + }while (qsize); + + + return offset; +} + + +int +dissect_nt_get_user_quota(tvbuff_t *tvb, proto_tree *tree, int offset, guint32 *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_item(tree, hf_smb_length_of_sid, tvb, offset, 4, ENC_LITTLE_ENDIAN); + COUNT_BYTES_TRANS_SUBR(4); + + /* SID of the user */ + old_sid_offset = offset; + offset = dissect_nt_sid(tvb, offset, tree, "SID", NULL, -1); + *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, smb_nt_transact_info_t *nti, smb_info_t *si, int subcmd, guint32 sd_len, guint32 ea_len) +{ + proto_tree *tree; + int old_offset = offset; + guint16 bcp = bc; /* XXX fixme */ + struct access_mask_info *ami = NULL; + tvbuff_t *ioctl_tvb; + + DISSECTOR_ASSERT(si); + + tree = proto_tree_add_subtree_format(parent_tree, tvb, offset, -1, + ett_smb_nt_trans_data, NULL, "%s Data", + val_to_str_ext(subcmd, &nt_cmd_vals_ext, "Unknown NT transaction (%u)")); + + switch(subcmd) { + case NT_TRANS_CREATE: + /* security descriptor */ + if (sd_len) { + offset = dissect_nt_sec_desc( + tvb, offset, pinfo, tree, NULL, TRUE, + sd_len, NULL); + } + + /* extended attributes */ + if (ea_len) { + proto_tree_add_item(tree, hf_smb_extended_attributes, tvb, offset, ea_len, ENC_NA); + offset += ea_len; + } + + break; + case NT_TRANS_IOCTL: + /* ioctl data */ + ioctl_tvb = tvb_new_subset_length_caplen(tvb, offset, MIN((int)bc, tvb_reported_length_remaining(tvb, offset)), bc); + if (nti) { + dissect_smb2_ioctl_data(ioctl_tvb, pinfo, tree, top_tree_global, nti->ioctl_function, TRUE, NULL); + } + + offset += bc; + + break; + case NT_TRANS_SSD: + if (nti) { + switch(nti->fid_type) { + case SMB_FID_TYPE_FILE: + ami = &smb_file_access_mask_info; + break; + case SMB_FID_TYPE_DIR: + ami = &smb_dir_access_mask_info; + break; + } + } + + offset = dissect_nt_sec_desc( + tvb, offset, pinfo, tree, NULL, TRUE, bc, ami); + + if (offset < (old_offset + bc)) { + offset = old_offset + bc; + } + + break; + case NT_TRANS_NOTIFY: + break; + case NT_TRANS_RENAME: + /* XXX not documented */ + 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, ENC_NA); + offset += 4; + + /* length of SID */ + proto_tree_add_item(tree, hf_smb_length_of_sid, tvb, offset, 4, ENC_LITTLE_ENDIAN); + offset +=4; + + offset = dissect_nt_sid(tvb, offset, tree, "Quota", NULL, -1); + break; + case NT_TRANS_SET_USER_QUOTA: + offset = dissect_nt_user_quota(tvb, tree, offset, &bcp); + break; + } + + /* ooops there were data we didn't know how to process */ + if ((offset-old_offset) < bc) { + proto_tree_add_item(tree, hf_smb_unknown, tvb, offset, + bc - (offset-old_offset), ENC_NA); + offset += bc - (offset-old_offset); + } + + return offset; +} + +static int +dissect_nt_trans_param_request(tvbuff_t *tvb, packet_info *pinfo, int offset, proto_tree *parent_tree, int len, guint16 bc, smb_nt_transact_info_t *nti, smb_info_t *si, int subcmd, guint32 *sd_len, guint32 *ea_len) +{ + proto_tree *tree; + guint32 fn_len, create_flags, access_mask, share_access, create_options; + const char *fn; + + DISSECTOR_ASSERT(si); + + tree = proto_tree_add_subtree_format(parent_tree, tvb, offset, len, + ett_smb_nt_trans_param, NULL, "%s Parameters", + val_to_str_ext(subcmd, &nt_cmd_vals_ext, "Unknown NT transaction (%u)")); + + switch(subcmd) { + case NT_TRANS_CREATE: + /* Create flags */ + create_flags = tvb_get_letohl(tvb, offset); + offset = dissect_nt_create_bits(tvb, tree, offset, 4, create_flags); + bc -= 4; + + /* root directory fid */ + proto_tree_add_item(tree, hf_smb_root_dir_fid, tvb, offset, 4, ENC_LITTLE_ENDIAN); + COUNT_BYTES(4); + + /* nt access mask */ + access_mask = tvb_get_letohl(tvb, offset); + offset = dissect_smb_access_mask_bits(tvb, tree, offset, 4, access_mask); + bc -= 4; + + /* allocation size */ + proto_tree_add_item(tree, hf_smb_alloc_size64, tvb, offset, 8, ENC_LITTLE_ENDIAN); + COUNT_BYTES(8); + + /* Extended File Attributes */ + offset = dissect_file_ext_attr(tvb, tree, offset); + bc -= 4; + + /* share access */ + share_access = tvb_get_letohl(tvb, offset); + offset = dissect_nt_share_access_bits(tvb, tree, offset, 4, share_access); + bc -= 4; + + /* create disposition */ + proto_tree_add_item(tree, hf_smb_nt_create_disposition, tvb, offset, 4, ENC_LITTLE_ENDIAN); + COUNT_BYTES(4); + + /* create options */ + create_options = tvb_get_letohl(tvb, offset); + offset = dissect_nt_create_options_bits(tvb, tree, offset, 4, create_options); + bc -= 4; + + /* sd length */ + proto_tree_add_item_ret_uint(tree, hf_smb_sd_length, tvb, offset, 4, ENC_LITTLE_ENDIAN, sd_len); + COUNT_BYTES(4); + + /* ea length */ + proto_tree_add_item_ret_uint(tree, hf_smb_ea_list_length, tvb, offset, 4, ENC_LITTLE_ENDIAN, ea_len); + COUNT_BYTES(4); + + /* file name len */ + fn_len = (guint32)tvb_get_letohl(tvb, offset); + proto_tree_add_uint(tree, hf_smb_file_name_len, tvb, offset, 4, fn_len); + COUNT_BYTES(4); + + /* impersonation level */ + proto_tree_add_item(tree, hf_smb_nt_impersonation_level, tvb, offset, 4, ENC_LITTLE_ENDIAN); + COUNT_BYTES(4); + + /* security flags */ + offset = dissect_nt_security_flags(tvb, tree, offset); + bc -= 1; + + /* May need to skip alignment padding. */ + if (offset&1) { + /* pad byte */ + proto_tree_add_item(tree, hf_smb_padding, tvb, offset, 1, ENC_NA); + offset += 1; + } + + /* file name */ + fn = get_unicode_or_ascii_string(tvb, &offset, si->unicode, &fn_len, TRUE, TRUE, &bc); + if (fn != NULL) { + proto_tree_add_string(tree, hf_smb_file_name, tvb, offset, fn_len, + fn); + COUNT_BYTES(fn_len); + } + + break; + case NT_TRANS_IOCTL: + break; + case NT_TRANS_SSD: { + guint16 fid; + smb_fid_info_t *fid_info; + + /* fid */ + fid = tvb_get_letohs(tvb, offset); + fid_info = dissect_smb_fid(tvb, pinfo, tree, offset, 2, fid, FALSE, FALSE, FALSE, si); + offset += 2; + if (nti) { + if (fid_info) { + nti->fid_type = fid_info->type; + } else { + nti->fid_type = SMB_FID_TYPE_UNKNOWN; + } + } + + /* 2 reserved bytes */ + proto_tree_add_item(tree, hf_smb_reserved, tvb, offset, 2, ENC_NA); + offset += 2; + + /* security information */ + offset = dissect_security_information_mask(tvb, tree, offset); + break; + } + case NT_TRANS_NOTIFY: + break; + case NT_TRANS_RENAME: + /* XXX not documented */ + break; + case NT_TRANS_QSD: { + guint16 fid; + smb_fid_info_t *fid_info; + + /* fid */ + fid = tvb_get_letohs(tvb, offset); + fid_info = dissect_smb_fid(tvb, pinfo, tree, offset, 2, fid, FALSE, FALSE, FALSE, si); + offset += 2; + if (nti) { + if (fid_info) { + nti->fid_type = fid_info->type; + } else { + nti->fid_type = SMB_FID_TYPE_UNKNOWN; + } + } + + /* 2 reserved bytes */ + proto_tree_add_item(tree, hf_smb_reserved, tvb, offset, 2, ENC_NA); + offset += 2; + + /* security information */ + offset = dissect_security_information_mask(tvb, 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; +} + +static int +dissect_nt_trans_setup_request(tvbuff_t *tvb, packet_info *pinfo, int offset, proto_tree *parent_tree, int len, smb_info_t *si, int subcmd) +{ + proto_tree *tree; + smb_nt_transact_info_t *nti = NULL; + smb_saved_info_t *sip; + + DISSECTOR_ASSERT(si); + sip = si->sip; + if (sip && (sip->extra_info_type == SMB_EI_NTI)) { + nti = (smb_nt_transact_info_t *)sip->extra_info; + } + + tree = proto_tree_add_subtree_format(parent_tree, tvb, offset, len, + ett_smb_nt_trans_setup, NULL, "%s Setup", + val_to_str_ext(subcmd, &nt_cmd_vals_ext, "Unknown NT transaction (%u)")); + + switch(subcmd) { + case NT_TRANS_CREATE: + offset += len; + break; + case NT_TRANS_IOCTL: { + guint16 fid; + + /* function code */ + offset = dissect_smb2_ioctl_function(tvb, pinfo, tree, offset, nti ? &nti->ioctl_function : NULL); + + /* fid */ + fid = tvb_get_letohs(tvb, offset); + dissect_smb_fid(tvb, pinfo, tree, offset, 2, fid, FALSE, FALSE, FALSE, si); + offset += 2; + + /* isfsctl */ + proto_tree_add_item(tree, hf_smb_nt_ioctl_isfsctl, tvb, offset, 1, ENC_LITTLE_ENDIAN); + offset += 1; + + /* isflags */ + offset = dissect_nt_ioctl_flags(tvb, tree, offset); + + break; + } + case NT_TRANS_SSD: + offset += len; + break; + case NT_TRANS_NOTIFY: { + guint16 fid; + + /* completion filter */ + offset = dissect_nt_notify_completion_filter(tvb, tree, offset); + + /* fid */ + fid = tvb_get_letohs(tvb, offset); + dissect_smb_fid(tvb, pinfo, tree, offset, 2, fid, FALSE, FALSE, FALSE, si); + offset += 2; + + /* watch tree */ + proto_tree_add_item(tree, hf_smb_nt_notify_watch_tree, tvb, offset, 1, ENC_LITTLE_ENDIAN); + offset += 1; + + /* reserved byte */ + proto_tree_add_item(tree, hf_smb_reserved, tvb, offset, 1, ENC_NA); + offset += 1; + + break; + } + case NT_TRANS_RENAME: + /* XXX not documented */ + offset += len; + break; + case NT_TRANS_QSD: + break; + case NT_TRANS_GET_USER_QUOTA: + /* not decoded yet */ + offset += len; + break; + case NT_TRANS_SET_USER_QUOTA: + /* not decoded yet */ + offset += len; + break; + } + + return offset; +} + + +static int +dissect_nt_transaction_request(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int offset, proto_tree *smb_tree _U_, smb_info_t *si) +{ + guint8 wc, sc; + guint32 pc = 0, pd = 0, po = 0, dc = 0, od = 0, dd = 0; + guint32 td = 0, tp = 0; + smb_saved_info_t *sip; + int subcmd; + guint32 sd_len, ea_len; + guint16 bc; + guint32 padcnt; + smb_nt_transact_info_t *nti = NULL; + fragment_head *r_fd = NULL; + tvbuff_t *pd_tvb = NULL; + gboolean save_fragmented; + + save_fragmented = pinfo->fragmented; + + subcmd = 0; + sd_len = 0; + ea_len = 0; + + DISSECTOR_ASSERT(si); + sip = si->sip; + + WORD_COUNT; + + if (wc >= 19) { + /* primary request */ + /* max setup count */ + proto_tree_add_item(tree, hf_smb_max_setup_count, tvb, offset, 1, ENC_LITTLE_ENDIAN); + offset += 1; + + /* 2 reserved bytes */ + proto_tree_add_item(tree, hf_smb_reserved, tvb, offset, 2, ENC_NA); + offset += 2; + } else { + /* secondary request */ + /* 3 reserved bytes */ + proto_tree_add_item(tree, hf_smb_reserved, tvb, offset, 3, ENC_NA); + offset += 3; + } + + + /* total param count */ + tp = tvb_get_letohl(tvb, offset); + proto_tree_add_uint(tree, hf_smb_total_param_count, tvb, offset, 4, tp); + offset += 4; + + /* total data count */ + td = tvb_get_letohl(tvb, offset); + proto_tree_add_uint(tree, hf_smb_total_data_count, tvb, offset, 4, td); + offset += 4; + + if (wc >= 19) { + /* primary request */ + /* max param count */ + proto_tree_add_item(tree, hf_smb_max_param_count, tvb, offset, 4, ENC_LITTLE_ENDIAN); + offset += 4; + + /* max data count */ + proto_tree_add_item(tree, hf_smb_max_data_count, tvb, offset, 4, ENC_LITTLE_ENDIAN); + offset += 4; + } + + /* param count */ + pc = tvb_get_letohl(tvb, offset); + proto_tree_add_uint(tree, hf_smb_param_count32, tvb, offset, 4, pc); + offset += 4; + + /* param offset */ + po = tvb_get_letohl(tvb, offset); + proto_tree_add_uint(tree, hf_smb_param_offset32, tvb, offset, 4, po); + offset += 4; + + /* param displacement */ + if (wc >= 19) { + /* primary request*/ + } else { + /* secondary request */ + + proto_tree_add_item(tree, hf_smb_param_disp32, tvb, offset, 4, ENC_LITTLE_ENDIAN); + offset += 4; + } + + /* data count */ + dc = tvb_get_letohl(tvb, offset); + proto_tree_add_uint(tree, hf_smb_data_count32, tvb, offset, 4, dc); + offset += 4; + + /* data offset */ + od = tvb_get_letohl(tvb, offset); + proto_tree_add_uint(tree, hf_smb_data_offset32, tvb, offset, 4, od); + offset += 4; + + /* data displacement */ + if (wc >= 19) { + /* primary request */ + } else { + /* secondary request */ + dd = tvb_get_letohl(tvb, offset); + proto_tree_add_uint(tree, hf_smb_data_disp32, tvb, offset, 4, dd); + offset += 4; + } + + /* setup count */ + if (wc >= 19) { + /* primary request */ + sc = tvb_get_guint8(tvb, offset); + proto_tree_add_uint(tree, hf_smb_setup_count, tvb, offset, 1, sc); + offset += 1; + } else { + /* secondary request */ + sc = 0; + } + + /* function */ + if (wc >= 19) { + /* primary request */ + subcmd = tvb_get_letohs(tvb, offset); + proto_tree_add_uint(tree, hf_smb_nt_trans_subcmd, tvb, offset, 2, subcmd); + col_append_fstr(pinfo->cinfo, COL_INFO, ", %s", + val_to_str_ext_const(subcmd, &nt_cmd_vals_ext, "<unknown>")); + + if (!si->unidir && sip) { + if (!pinfo->fd->visited) { + /* + * Allocate a new smb_nt_transact_info_t + * structure. + */ + nti = wmem_new(wmem_file_scope(), smb_nt_transact_info_t); + nti->subcmd = subcmd; + nti->fid_type = SMB_FID_TYPE_UNKNOWN; + nti->ioctl_function = 0; + sip->extra_info = nti; + sip->extra_info_type = SMB_EI_NTI; + } else { + if (sip->extra_info_type == SMB_EI_NTI) { + nti = (smb_nt_transact_info_t *)sip->extra_info; + } + } + } + } else { + /* secondary request */ + col_append_str(pinfo->cinfo, COL_INFO, " (secondary request)"); + } + offset += 2; + +#if 0 /* XXX this is a padding byte? I don't think so. -gwr */ + if (offset&1) { + /* pad byte */ + proto_tree_add_item(tree, hf_smb_padding, tvb, offset, 1, ENC_NA); + offset += 1; + } +#endif + + /* if there were any setup bytes, decode them */ + if (sc) { + dissect_nt_trans_setup_request(tvb, pinfo, offset, tree, sc*2, si, subcmd); + offset += sc*2; + } + + /* + * Do we really need to even look at the byte count here? + * Servers normally use byte_count only when assembling the + * setup, parameters, and data segments. Once we know + * how long each of those are, we should dissect them + * using the lengths determined during assembly. + */ + BYTE_COUNT; + + /* reassembly of SMB NT Transaction data payload. + In this section we do reassembly of both the data and parameters + blocks of the SMB transaction command. + */ + /* do we need reassembly? */ + if ( (td && (td != dc)) || (tp && (tp != pc)) ) { + /* oh yeah, either data or parameter section needs + reassembly... + */ + pinfo->fragmented = TRUE; + if (smb_trans_reassembly) { + /* ...and we were told to do reassembly */ + if (pc) { + r_fd = smb_trans_defragment(tree, pinfo, tvb, + po, pc, pd, td+tp, si); + } + if ((r_fd == NULL) && dc) { + r_fd = smb_trans_defragment(tree, pinfo, tvb, + od, dc, dd+tp, td+tp, si); + } + } + } + + /* if we got a reassembled fd structure from the reassembly routine we + must create pd_tvb from it + */ + if (r_fd) { + proto_item *frag_tree_item; + + pd_tvb = tvb_new_chain(tvb, r_fd->tvb_data); + add_new_data_source(pinfo, pd_tvb, "Reassembled SMB"); + + show_fragment_tree(r_fd, &smb_frag_items, tree, pinfo, pd_tvb, &frag_tree_item); + } + + if (pd_tvb) { + /* we have reassembled data, grab param and data from there */ + dissect_nt_trans_param_request(pd_tvb, pinfo, 0, tree, tp, + (guint16) tvb_reported_length(pd_tvb), + nti, si, subcmd, &sd_len, &ea_len); + dissect_nt_trans_data_request(pd_tvb, pinfo, tp, tree, td, nti, si, + subcmd, sd_len, ea_len); + COUNT_BYTES(bc); /* We are done */ + } else { + /* we do not have reassembled data, just use what we have in the + packet as well as we can */ + /* parameters */ + if (po > (guint32)offset) { + /* We have some initial padding bytes. + */ + padcnt = po-offset; + if (padcnt > bc) + padcnt = bc; + CHECK_BYTE_COUNT(padcnt); + proto_tree_add_item(tree, hf_smb_padding, tvb, offset, padcnt, ENC_NA); + COUNT_BYTES(padcnt); + } + if (pc) { + CHECK_BYTE_COUNT(pc); + dissect_nt_trans_param_request(tvb, pinfo, offset, tree, pc, bc, + nti, si, subcmd, &sd_len, &ea_len); + COUNT_BYTES(pc); + } + + /* data */ + if (od > (guint32)offset) { + /* We have some initial padding bytes. + */ + padcnt = od-offset; + if (padcnt > bc) + padcnt = bc; + proto_tree_add_item(tree, hf_smb_padding, tvb, offset, padcnt, ENC_NA); + COUNT_BYTES(padcnt); + } + if (dc) { + CHECK_BYTE_COUNT(dc); + dissect_nt_trans_data_request(tvb, pinfo, offset, tree, dc, + nti, si, subcmd, sd_len, ea_len); + COUNT_BYTES(dc); + } + } + + END_OF_SMB + + pinfo->fragmented = save_fragmented; + return offset; +} + + + +static int +dissect_nt_trans_data_response(tvbuff_t *tvb, packet_info *pinfo, + int offset, proto_tree *parent_tree, int len, + smb_nt_transact_info_t *nti, smb_info_t *si) +{ + proto_tree *tree = NULL; + guint16 bcp; + struct access_mask_info *ami = NULL; + tvbuff_t *ioctl_tvb; + + DISSECTOR_ASSERT(si); + + if (parent_tree) { + if (nti != NULL) { + tree = proto_tree_add_subtree_format(parent_tree, tvb, offset, len, + ett_smb_nt_trans_data, NULL, "%s Data", + val_to_str_ext(nti->subcmd, &nt_cmd_vals_ext, "Unknown NT Transaction (%u)")); + } else { + /* + * We never saw the request to which this is a + * response. + */ + tree = proto_tree_add_subtree(parent_tree, tvb, offset, len, + ett_smb_nt_trans_data, NULL, "Unknown NT Transaction Data (matching request not seen)"); + } + } + + if (nti == NULL) { + offset += len; + return offset; + } + switch(nti->subcmd) { + case NT_TRANS_CREATE: + break; + case NT_TRANS_IOCTL: + /* ioctl data */ + ioctl_tvb = tvb_new_subset_length_caplen(tvb, offset, MIN((int)len, tvb_reported_length_remaining(tvb, offset)), len); + dissect_smb2_ioctl_data(ioctl_tvb, pinfo, tree, top_tree_global, nti->ioctl_function, FALSE, NULL); + + offset += len; + + break; + case NT_TRANS_SSD: + break; + case NT_TRANS_NOTIFY: + break; + case NT_TRANS_RENAME: + /* XXX not documented */ + break; + case NT_TRANS_QSD: + if (nti) { + switch(nti->fid_type) { + case SMB_FID_TYPE_FILE: + ami = &smb_file_access_mask_info; + break; + case SMB_FID_TYPE_DIR: + ami = &smb_dir_access_mask_info; + break; + } + } + offset = dissect_nt_sec_desc( + tvb, offset, pinfo, tree, NULL, TRUE, len, ami); + break; + case NT_TRANS_GET_USER_QUOTA: + bcp = len; + offset = dissect_nt_user_quota(tvb, tree, offset, &bcp); + break; + case NT_TRANS_SET_USER_QUOTA: + /* not decoded yet */ + break; + } + + return offset; +} + +static int +dissect_nt_trans_param_response(tvbuff_t *tvb, packet_info *pinfo, + int offset, proto_tree *parent_tree, + int len, guint16 bc, smb_info_t *si) +{ + proto_tree *tree = NULL; + guint32 fn_len; + const char *fn; + smb_nt_transact_info_t *nti; + guint16 fid; + int old_offset; + guint32 neo; + int padcnt; + smb_fid_info_t *fid_info = NULL; + guint16 ftype; + guint8 isdir; + guint8 ext_resp = 0; + + DISSECTOR_ASSERT(si); + + if ((si->sip != NULL) && (si->sip->extra_info_type == SMB_EI_NTI)) + nti = (smb_nt_transact_info_t *)si->sip->extra_info; + else + nti = NULL; + + if (parent_tree) { + if (nti != NULL) { + tree = proto_tree_add_subtree_format(parent_tree, tvb, offset, len, + ett_smb_nt_trans_param, NULL, "%s Parameters", + val_to_str_ext(nti->subcmd, &nt_cmd_vals_ext, "Unknown NT Transaction (%u)")); + } else { + /* + * We never saw the request to which this is a + * response. + */ + tree = proto_tree_add_subtree(parent_tree, tvb, offset, len, + ett_smb_nt_trans_param, NULL, "Unknown NT Transaction Parameters (matching request not seen)"); + } + } + + if (nti == NULL) { + offset += len; + return offset; + } + switch(nti->subcmd) { + case NT_TRANS_CREATE: + /* oplock level */ + proto_tree_add_item(tree, hf_smb_oplock_level, tvb, offset, 1, ENC_LITTLE_ENDIAN); + offset += 1; + + /* response type, as per MS-SMB 2.2.7.1.2 */ + ext_resp = tvb_get_guint8(tvb, offset); + proto_tree_add_item(tree, hf_smb_response_type, tvb, offset, 1, ENC_NA); + offset += 1; + + /* fid */ + fid = tvb_get_letohs(tvb, offset); + fid_info = dissect_smb_fid(tvb, pinfo, tree, offset, 2, fid, TRUE, FALSE, FALSE, si); + offset += 2; + + /* create action */ + proto_tree_add_item(tree, hf_smb_create_action, tvb, offset, 4, ENC_LITTLE_ENDIAN); + offset += 4; + + /* ea error offset */ + proto_tree_add_item(tree, hf_smb_ea_error_offset, tvb, offset, 4, ENC_LITTLE_ENDIAN); + offset += 4; + + /* create time */ + offset = dissect_nt_64bit_time(tvb, tree, offset, + hf_smb_create_time); + + /* access time */ + offset = dissect_nt_64bit_time(tvb, tree, offset, + hf_smb_access_time); + + /* last write time */ + offset = dissect_nt_64bit_time(tvb, tree, offset, + hf_smb_last_write_time); + + /* last change time */ + offset = dissect_nt_64bit_time(tvb, tree, offset, + hf_smb_change_time); + + /* Extended File Attributes */ + offset = dissect_file_ext_attr(tvb, tree, offset); + + /* allocation size */ + proto_tree_add_item(tree, hf_smb_alloc_size64, tvb, offset, 8, ENC_LITTLE_ENDIAN); + offset += 8; + + /* end of file */ + proto_tree_add_item(tree, hf_smb_end_of_file, tvb, offset, 8, ENC_LITTLE_ENDIAN); + offset += 8; + + /* File Type */ + ftype = tvb_get_letohs(tvb, offset); + proto_tree_add_item(tree, hf_smb_file_type, tvb, offset, 2, ENC_LITTLE_ENDIAN); + offset += 2; + + /* device state */ + offset = dissect_ipc_state(tvb, tree, offset, FALSE); + + /* is directory */ + isdir = tvb_get_guint8(tvb, offset); + proto_tree_add_item(tree, hf_smb_is_directory, tvb, offset, 1, ENC_LITTLE_ENDIAN); + offset += 1; + + /* decode extended response per [MS-SMB] 2.2.7.1.2 + (volume_guid, file_id, max_acc, guest_acc) + Just like dissect_nt_create_andx_response */ + if (ext_resp != 0) { + proto_tree *tr = NULL; + + /* The first field is a Volume GUID ... */ + proto_tree_add_item(tree, hf_smb_volume_guid, + tvb, offset, 16, ENC_NA); + offset += 16; + + /* The file ID comes next */ + proto_tree_add_item(tree, hf_smb_file_id_64bit, + tvb, offset, 8, ENC_LITTLE_ENDIAN); + offset += 8; + + tr = proto_tree_add_subtree(tree, tvb, offset, 4, + ett_smb_nt_access_mask, NULL, "Maximal Access Rights"); + offset = dissect_smb_access_mask(tvb, tr, offset); + + tr = proto_tree_add_subtree(tree, tvb, offset, 4, + ett_smb_nt_access_mask, NULL, "Guest Maximal Access Rights"); + offset = dissect_smb_access_mask(tvb, tr, offset); + } + + /* Try to remember the type of this fid so that we can dissect + * any future security descriptor (access mask) properly + */ + if (ftype == 0) { + if (isdir == 0) { + if (fid_info) { + fid_info->type = SMB_FID_TYPE_FILE; + } + } else { + if (fid_info) { + fid_info->type = SMB_FID_TYPE_DIR; + } + } + } + if (ftype == 2) { + if (fid_info) { + fid_info->type = SMB_FID_TYPE_PIPE; + } + } + break; + case NT_TRANS_IOCTL: + break; + case NT_TRANS_SSD: + break; + case NT_TRANS_NOTIFY: + while (len) { + old_offset = offset; + + /* next entry offset */ + 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 */ + if (len < 0) break; + + /* action */ + proto_tree_add_item(tree, hf_smb_nt_notify_action, tvb, offset, 4, ENC_LITTLE_ENDIAN); + COUNT_BYTES(4); + len -= 4; + /* broken implementations */ + if (len < 0) break; + + /* file name len */ + fn_len = (guint32)tvb_get_letohl(tvb, offset); + proto_tree_add_uint(tree, hf_smb_file_name_len, tvb, offset, 4, fn_len); + COUNT_BYTES(4); + len -= 4; + /* broken implementations */ + if (len < 0) break; + + /* file name */ + fn = get_unicode_or_ascii_string(tvb, &offset, si->unicode, &fn_len, TRUE, TRUE, &bc); + if (fn == NULL) + break; + proto_tree_add_string(tree, hf_smb_file_name, tvb, offset, fn_len, + fn); + COUNT_BYTES(fn_len); + len -= fn_len; + /* 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: + /* XXX not documented */ + break; + case NT_TRANS_QSD: + /* + * This appears to be the size of the security + * descriptor; the calling sequence of + * "ZwQuerySecurityObject()" suggests that it would + * be. The actual security descriptor wouldn't + * follow if the max data count in the request + * was smaller; this lets the client know how + * big a buffer it needs to provide. + */ + proto_tree_add_item(tree, hf_smb_sec_desc_len, tvb, offset, 4, ENC_LITTLE_ENDIAN); + offset += 4; + break; + case NT_TRANS_GET_USER_QUOTA: + proto_tree_add_item(tree, hf_smb_size_returned_quota_data, tvb, offset, 4, ENC_LITTLE_ENDIAN); + offset += 4; + break; + case NT_TRANS_SET_USER_QUOTA: + /* not decoded yet */ + break; + } + + return offset; +} + +static int +dissect_nt_trans_setup_response(tvbuff_t *tvb, packet_info *pinfo, + int offset, proto_tree *parent_tree, + int len, smb_info_t *si) +{ + smb_nt_transact_info_t *nti; + + DISSECTOR_ASSERT(si); + + if ((si->sip != NULL) && (si->sip->extra_info_type == SMB_EI_NTI)) + nti = (smb_nt_transact_info_t *)si->sip->extra_info; + else + nti = NULL; + + if (parent_tree) { + if (nti != NULL) { + proto_tree_add_bytes_format(parent_tree, hf_smb_nt_transaction_setup, tvb, offset, len, + NULL, "%s Setup", + val_to_str_ext(nti->subcmd, &nt_cmd_vals_ext, "Unknown NT Transaction (%u)")); + } else { + /* + * We never saw the request to which this is a + * response. + */ + proto_tree_add_expert(parent_tree, pinfo, &ei_smb_nt_transaction_setup, tvb, offset, len); + } + } + + if (nti == NULL) { + offset += len; + return offset; + } + switch(nti->subcmd) { + case NT_TRANS_CREATE: + break; + case NT_TRANS_IOCTL: + break; + case NT_TRANS_SSD: + break; + case NT_TRANS_NOTIFY: + break; + case NT_TRANS_RENAME: + /* XXX not documented */ + 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; +} + +static int +dissect_nt_transaction_response(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int offset, proto_tree *smb_tree _U_, smb_info_t *si) +{ + guint8 wc, sc; + guint32 pc = 0, po = 0, pd = 0, dc = 0, od = 0, dd = 0; + guint32 td = 0, tp = 0; + smb_nt_transact_info_t *nti = NULL; + guint16 bc; + gint32 padcnt; + fragment_head *r_fd = NULL; + tvbuff_t *pd_tvb = NULL; + gboolean save_fragmented; + + DISSECTOR_ASSERT(si); + + if ((si->sip != NULL) && (si->sip->extra_info_type == SMB_EI_NTI)) + nti = (smb_nt_transact_info_t *)si->sip->extra_info; + else + nti = NULL; + + /* primary request */ + if (nti != NULL) { + proto_tree_add_uint(tree, hf_smb_nt_trans_subcmd, tvb, 0, 0, nti->subcmd); + col_append_fstr(pinfo->cinfo, COL_INFO, ", %s", + val_to_str_ext(nti->subcmd, &nt_cmd_vals_ext, "<unknown (%u)>")); + } else { + proto_tree_add_uint_format_value(tree, hf_smb_nt_trans_subcmd, tvb, offset, 0, -1, + "<unknown function - could not find matching request>"); + col_append_str(pinfo->cinfo, COL_INFO, ", <unknown>"); + } + + WORD_COUNT; + + /* 3 reserved bytes */ + proto_tree_add_item(tree, hf_smb_reserved, tvb, offset, 3, ENC_NA); + offset += 3; + + /* total param count */ + tp = tvb_get_letohl(tvb, offset); + proto_tree_add_uint(tree, hf_smb_total_param_count, tvb, offset, 4, tp); + offset += 4; + + /* total data count */ + td = tvb_get_letohl(tvb, offset); + proto_tree_add_uint(tree, hf_smb_total_data_count, tvb, offset, 4, td); + offset += 4; + + /* param count */ + pc = tvb_get_letohl(tvb, offset); + proto_tree_add_uint(tree, hf_smb_param_count32, tvb, offset, 4, pc); + offset += 4; + + /* param offset */ + po = tvb_get_letohl(tvb, offset); + proto_tree_add_uint(tree, hf_smb_param_offset32, tvb, offset, 4, po); + offset += 4; + + /* param displacement */ + pd = tvb_get_letohl(tvb, offset); + proto_tree_add_uint(tree, hf_smb_param_disp32, tvb, offset, 4, pd); + offset += 4; + + /* data count */ + dc = tvb_get_letohl(tvb, offset); + proto_tree_add_uint(tree, hf_smb_data_count32, tvb, offset, 4, dc); + offset += 4; + + /* data offset */ + od = tvb_get_letohl(tvb, offset); + proto_tree_add_uint(tree, hf_smb_data_offset32, tvb, offset, 4, od); + offset += 4; + + /* data displacement */ + dd = tvb_get_letohl(tvb, offset); + proto_tree_add_uint(tree, hf_smb_data_disp32, tvb, offset, 4, dd); + offset += 4; + + /* setup count */ + sc = tvb_get_guint8(tvb, offset); + proto_tree_add_uint(tree, hf_smb_setup_count, tvb, offset, 1, sc); + offset += 1; + + /* setup data */ + if (sc) { + dissect_nt_trans_setup_response(tvb, pinfo, offset, tree, sc*2, si); + offset += sc*2; + } + + BYTE_COUNT; + + /* reassembly of SMB NT Transaction data payload. + In this section we do reassembly of both the data and parameters + blocks of the SMB transaction command. + */ + save_fragmented = pinfo->fragmented; + /* do we need reassembly? */ + if ( (td && (td != dc)) || (tp && (tp != pc)) ) { + /* oh yeah, either data or parameter section needs + reassembly... + */ + pinfo->fragmented = TRUE; + if (smb_trans_reassembly) { + /* ...and we were told to do reassembly */ + if (pc) { + r_fd = smb_trans_defragment(tree, pinfo, tvb, + po, pc, pd, td+tp, si); + + } + if ((r_fd == NULL) && dc) { + r_fd = smb_trans_defragment(tree, pinfo, tvb, + od, dc, dd+tp, td+tp, si); + } + } + } + + /* if we got a reassembled fd structure from the reassembly routine we + must create pd_tvb from it + */ + if (r_fd) { + proto_item *frag_tree_item; + + pd_tvb = tvb_new_chain(tvb, r_fd->tvb_data); + add_new_data_source(pinfo, pd_tvb, "Reassembled SMB"); + + show_fragment_tree(r_fd, &smb_frag_items, tree, pinfo, pd_tvb, &frag_tree_item); + } + + + if (pd_tvb) { + /* we have reassembled data, grab param and data from there */ + dissect_nt_trans_param_response(pd_tvb, pinfo, 0, tree, tp, + (guint16) tvb_reported_length(pd_tvb), si); + dissect_nt_trans_data_response(pd_tvb, pinfo, tp, tree, td, nti, si); + COUNT_BYTES(bc); /* We are done */ + } else { + /* we do not have reassembled data, just use what we have in the + packet as well as we can */ + /* parameters */ + if (po > (guint32)offset) { + /* We have some initial padding bytes. + */ + padcnt = po-offset; + if (padcnt > bc) + padcnt = bc; + CHECK_BYTE_COUNT(padcnt); + proto_tree_add_item(tree, hf_smb_padding, tvb, offset, padcnt, ENC_NA); + COUNT_BYTES(padcnt); + } + if (pc) { + CHECK_BYTE_COUNT(pc); + dissect_nt_trans_param_response(tvb, pinfo, offset, tree, pc, bc, si); + COUNT_BYTES(pc); + } + + /* data */ + if (od > (guint32)offset) { + /* We have some initial padding bytes. + */ + padcnt = od-offset; + if (padcnt > bc) + padcnt = bc; + proto_tree_add_item(tree, hf_smb_padding, tvb, offset, padcnt, ENC_NA); + COUNT_BYTES(padcnt); + } + if (dc) { + CHECK_BYTE_COUNT(dc); + dissect_nt_trans_data_response(tvb, pinfo, offset, tree, dc, nti, si); + COUNT_BYTES(dc); + } + } + pinfo->fragmented = save_fragmented; + + END_OF_SMB + + return offset; +} + +/* XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX + NT Transaction command ends here + XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX */ + +static const value_string print_mode_vals[] = { + {0, "Text Mode"}, + {1, "Graphics Mode"}, + {0, NULL} +}; + +static int +dissect_open_print_file_request(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, int offset, proto_tree *smb_tree _U_, smb_info_t *si) +{ + int fn_len; + const char *fn; + guint8 wc; + guint16 bc; + + DISSECTOR_ASSERT(si); + + WORD_COUNT; + + /* setup len */ + proto_tree_add_item(tree, hf_smb_setup_len, tvb, offset, 2, ENC_LITTLE_ENDIAN); + offset += 2; + + /* print mode */ + proto_tree_add_item(tree, hf_smb_print_mode, tvb, offset, 2, ENC_LITTLE_ENDIAN); + offset += 2; + + BYTE_COUNT; + + /* buffer format */ + CHECK_BYTE_COUNT(1); + proto_tree_add_item(tree, hf_smb_buffer_format, tvb, offset, 1, ENC_LITTLE_ENDIAN); + COUNT_BYTES(1); + + /* print identifier */ + fn = get_unicode_or_ascii_string(tvb, &offset, si->unicode, &fn_len, TRUE, FALSE, &bc); + if (fn == NULL) + goto endofcommand; + proto_tree_add_string(tree, hf_smb_print_identifier, tvb, offset, fn_len, + fn); + COUNT_BYTES(fn_len); + + END_OF_SMB + + return offset; +} + + +static int +dissect_write_print_file_request(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int offset, proto_tree *smb_tree _U_, smb_info_t *si) +{ + int cnt; + guint8 wc; + guint16 bc, fid; + + WORD_COUNT; + + /* fid */ + fid = tvb_get_letohs(tvb, offset); + dissect_smb_fid(tvb, pinfo, tree, offset, 2, fid, FALSE, FALSE, FALSE, si); + offset += 2; + + BYTE_COUNT; + + /* buffer format */ + CHECK_BYTE_COUNT(1); + proto_tree_add_item(tree, hf_smb_buffer_format, tvb, offset, 1, ENC_LITTLE_ENDIAN); + COUNT_BYTES(1); + + /* data len */ + CHECK_BYTE_COUNT(2); + cnt = tvb_get_letohs(tvb, offset); + proto_tree_add_uint(tree, hf_smb_data_len, tvb, offset, 2, cnt); + COUNT_BYTES(2); + + /* file data */ + offset = dissect_file_data(tvb, tree, offset, (guint16) cnt, -1, (guint16) cnt); + + END_OF_SMB + + return offset; +} + + +static const value_string print_status_vals[] = { + {1, "Held or Stopped"}, + {2, "Printing"}, + {3, "Awaiting print"}, + {4, "In intercept"}, + {5, "File had error"}, + {6, "Printer error"}, + {0, NULL} +}; + +static int +dissect_get_print_queue_request(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, int offset, proto_tree *smb_tree _U_, smb_info_t *si _U_) +{ + guint8 wc; + guint16 bc; + + WORD_COUNT; + + /* max count */ + proto_tree_add_item(tree, hf_smb_max_count, tvb, offset, 2, ENC_LITTLE_ENDIAN); + offset += 2; + + /* start index */ + proto_tree_add_item(tree, hf_smb_start_index, tvb, offset, 2, ENC_LITTLE_ENDIAN); + offset += 2; + + BYTE_COUNT; + + END_OF_SMB + + return offset; +} + +static int +dissect_print_queue_element(tvbuff_t *tvb, packet_info *pinfo _U_, + proto_tree *parent_tree, int offset, guint16 *bcp, gboolean *trunc, smb_info_t *si) +{ + proto_tree *tree; + int fn_len; + const char *fn; + + DISSECTOR_ASSERT(si); + + tree = proto_tree_add_subtree(parent_tree, tvb, offset, 28, + ett_smb_print_queue_entry, NULL, "Queue entry"); + + /* queued time */ + CHECK_BYTE_COUNT_SUBR(4); + offset = dissect_smb_datetime(tvb, tree, offset, + hf_smb_print_queue_date, + hf_smb_print_queue_dos_date, hf_smb_print_queue_dos_time, FALSE); + *bcp -= 4; + + /* status */ + CHECK_BYTE_COUNT_SUBR(1); + proto_tree_add_item(tree, hf_smb_print_status, tvb, offset, 1, ENC_LITTLE_ENDIAN); + COUNT_BYTES_SUBR(1); + + /* spool file number */ + CHECK_BYTE_COUNT_SUBR(2); + proto_tree_add_item(tree, hf_smb_print_spool_file_number, tvb, offset, 2, ENC_LITTLE_ENDIAN); + COUNT_BYTES_SUBR(2); + + /* spool file size */ + CHECK_BYTE_COUNT_SUBR(4); + proto_tree_add_item(tree, hf_smb_print_spool_file_size, tvb, offset, 4, ENC_LITTLE_ENDIAN); + COUNT_BYTES_SUBR(4); + + /* reserved byte */ + CHECK_BYTE_COUNT_SUBR(1); + proto_tree_add_item(tree, hf_smb_reserved, tvb, offset, 1, ENC_NA); + COUNT_BYTES_SUBR(1); + + /* file name */ + fn_len = 16; + fn = get_unicode_or_ascii_string(tvb, &offset, si->unicode, &fn_len, TRUE, TRUE, bcp); + CHECK_STRING_SUBR(fn); + proto_tree_add_string(tree, hf_smb_print_spool_file_name, tvb, offset, 16, + fn); + COUNT_BYTES_SUBR(fn_len); + + *trunc = FALSE; + return offset; +} + +static int +dissect_get_print_queue_response(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int offset, proto_tree *smb_tree _U_, smb_info_t *si _U_) +{ + guint16 cnt = 0, len; + guint8 wc; + guint16 bc; + gboolean trunc; + + WORD_COUNT; + + /* count */ + cnt = tvb_get_letohs(tvb, offset); + proto_tree_add_uint(tree, hf_smb_count, tvb, offset, 2, cnt); + offset += 2; + + /* restart index */ + proto_tree_add_item(tree, hf_smb_restart_index, tvb, offset, 2, ENC_LITTLE_ENDIAN); + offset += 2; + + BYTE_COUNT; + + /* buffer format */ + CHECK_BYTE_COUNT(1); + proto_tree_add_item(tree, hf_smb_buffer_format, tvb, offset, 1, ENC_LITTLE_ENDIAN); + COUNT_BYTES(1); + + /* data len */ + CHECK_BYTE_COUNT(2); + len = tvb_get_letohs(tvb, offset); + proto_tree_add_uint(tree, hf_smb_data_len, tvb, offset, 2, len); + COUNT_BYTES(2); + + /* queue elements */ + while (cnt--) { + offset = dissect_print_queue_element(tvb, pinfo, tree, offset, + &bc, &trunc, si); + if (trunc) + goto endofcommand; + } + + END_OF_SMB + + return offset; +} + + +static int +dissect_send_single_block_message_request(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, int offset, proto_tree *smb_tree _U_, smb_info_t *si _U_) +{ + int name_len; + guint16 bc; + guint8 wc; + guint16 message_len; + + WORD_COUNT; + + BYTE_COUNT; + + /* buffer format */ + CHECK_BYTE_COUNT(1); + proto_tree_add_item(tree, hf_smb_buffer_format, tvb, offset, 1, ENC_LITTLE_ENDIAN); + COUNT_BYTES(1); + + /* originator name */ + /* XXX - what if this runs past bc? */ + name_len = tvb_strsize(tvb, offset); + CHECK_BYTE_COUNT(name_len); + proto_tree_add_item(tree, hf_smb_originator_name, tvb, offset, + name_len, ENC_ASCII); + COUNT_BYTES(name_len); + + /* buffer format */ + CHECK_BYTE_COUNT(1); + proto_tree_add_item(tree, hf_smb_buffer_format, tvb, offset, 1, ENC_LITTLE_ENDIAN); + COUNT_BYTES(1); + + /* destination name */ + /* XXX - what if this runs past bc? */ + name_len = tvb_strsize(tvb, offset); + CHECK_BYTE_COUNT(name_len); + proto_tree_add_item(tree, hf_smb_destination_name, tvb, offset, + name_len, ENC_ASCII); + COUNT_BYTES(name_len); + + /* buffer format */ + CHECK_BYTE_COUNT(1); + proto_tree_add_item(tree, hf_smb_buffer_format, tvb, offset, 1, ENC_LITTLE_ENDIAN); + COUNT_BYTES(1); + + /* message len */ + CHECK_BYTE_COUNT(2); + message_len = tvb_get_letohs(tvb, offset); + proto_tree_add_uint(tree, hf_smb_message_len, tvb, offset, 2, + message_len); + COUNT_BYTES(2); + + /* message */ + CHECK_BYTE_COUNT(message_len); + proto_tree_add_item(tree, hf_smb_message, tvb, offset, message_len, + ENC_ASCII); + COUNT_BYTES(message_len); + + END_OF_SMB + + return offset; +} + +static int +dissect_send_multi_block_message_start_request(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, int offset, proto_tree *smb_tree _U_, smb_info_t *si _U_) +{ + int name_len; + guint16 bc; + guint8 wc; + + WORD_COUNT; + + BYTE_COUNT; + + /* buffer format */ + CHECK_BYTE_COUNT(1); + proto_tree_add_item(tree, hf_smb_buffer_format, tvb, offset, 1, ENC_LITTLE_ENDIAN); + COUNT_BYTES(1); + + /* originator name */ + /* XXX - what if this runs past bc? */ + name_len = tvb_strsize(tvb, offset); + CHECK_BYTE_COUNT(name_len); + proto_tree_add_item(tree, hf_smb_originator_name, tvb, offset, + name_len, ENC_ASCII); + COUNT_BYTES(name_len); + + /* buffer format */ + CHECK_BYTE_COUNT(1); + proto_tree_add_item(tree, hf_smb_buffer_format, tvb, offset, 1, ENC_LITTLE_ENDIAN); + COUNT_BYTES(1); + + /* destination name */ + /* XXX - what if this runs past bc? */ + name_len = tvb_strsize(tvb, offset); + CHECK_BYTE_COUNT(name_len); + proto_tree_add_item(tree, hf_smb_destination_name, tvb, offset, + name_len, ENC_ASCII); + COUNT_BYTES(name_len); + + END_OF_SMB + + return offset; +} + +static int +dissect_message_group_id(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, int offset, proto_tree *smb_tree _U_, smb_info_t *si _U_) +{ + guint16 bc; + guint8 wc; + + WORD_COUNT; + + /* message group ID */ + proto_tree_add_item(tree, hf_smb_mgid, tvb, offset, 2, ENC_LITTLE_ENDIAN); + offset += 2; + + BYTE_COUNT; + + END_OF_SMB + + return offset; +} + +static int +dissect_send_multi_block_message_text_request(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, int offset, proto_tree *smb_tree _U_, smb_info_t *si _U_) +{ + guint16 bc; + guint8 wc; + guint16 message_len; + + WORD_COUNT; + + BYTE_COUNT; + + /* buffer format */ + CHECK_BYTE_COUNT(1); + proto_tree_add_item(tree, hf_smb_buffer_format, tvb, offset, 1, ENC_LITTLE_ENDIAN); + COUNT_BYTES(1); + + /* message len */ + CHECK_BYTE_COUNT(2); + message_len = tvb_get_letohs(tvb, offset); + proto_tree_add_uint(tree, hf_smb_message_len, tvb, offset, 2, + message_len); + COUNT_BYTES(2); + + /* message */ + CHECK_BYTE_COUNT(message_len); + proto_tree_add_item(tree, hf_smb_message, tvb, offset, message_len, + ENC_ASCII); + COUNT_BYTES(message_len); + + END_OF_SMB + + return offset; +} + +static int +dissect_forwarded_name(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, int offset, proto_tree *smb_tree _U_, smb_info_t *si _U_) +{ + int name_len; + guint16 bc; + guint8 wc; + + WORD_COUNT; + + BYTE_COUNT; + + /* buffer format */ + CHECK_BYTE_COUNT(1); + proto_tree_add_item(tree, hf_smb_buffer_format, tvb, offset, 1, ENC_LITTLE_ENDIAN); + COUNT_BYTES(1); + + /* forwarded name */ + /* XXX - what if this runs past bc? */ + name_len = tvb_strsize(tvb, offset); + CHECK_BYTE_COUNT(name_len); + proto_tree_add_item(tree, hf_smb_forwarded_name, tvb, offset, + name_len, ENC_ASCII); + COUNT_BYTES(name_len); + + END_OF_SMB + + return offset; +} + +static int +dissect_get_machine_name_response(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, int offset, proto_tree *smb_tree _U_, smb_info_t *si _U_) +{ + int name_len; + guint16 bc; + guint8 wc; + + WORD_COUNT; + + BYTE_COUNT; + + /* buffer format */ + CHECK_BYTE_COUNT(1); + proto_tree_add_item(tree, hf_smb_buffer_format, tvb, offset, 1, ENC_LITTLE_ENDIAN); + COUNT_BYTES(1); + + /* machine name */ + /* XXX - what if this runs past bc? */ + name_len = tvb_strsize(tvb, offset); + CHECK_BYTE_COUNT(name_len); + proto_tree_add_item(tree, hf_smb_machine_name, tvb, offset, + name_len, ENC_ASCII); + COUNT_BYTES(name_len); + + END_OF_SMB + + return offset; +} + + +static int +dissect_nt_create_andx_request(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int offset, proto_tree *smb_tree, smb_info_t *si _U_) +{ + guint8 wc, cmd = 0xff; + guint16 andxoffset = 0; + guint16 bc; + int fn_len = -1; + const char *fn; + guint32 create_flags = 0, access_mask = 0, file_attributes = 0; + guint32 share_access = 0, create_options = 0, create_disposition = 0; + + DISSECTOR_ASSERT(si); + + WORD_COUNT; + + /* next smb command */ + cmd = tvb_get_guint8(tvb, offset); + if (cmd != 0xff) { + proto_tree_add_uint(tree, hf_smb_andxcmd, tvb, offset, 1, cmd); + } else { + proto_tree_add_uint_format_value(tree, hf_smb_andxcmd, tvb, offset, 1, cmd, "No further commands (0xff)"); + } + offset += 1; + + /* reserved byte */ + proto_tree_add_item(tree, hf_smb_reserved, tvb, offset, 1, ENC_NA); + offset += 1; + + /* andxoffset */ + andxoffset = tvb_get_letohs(tvb, offset); + proto_tree_add_uint(tree, hf_smb_andxoffset, tvb, offset, 2, andxoffset); + offset += 2; + + /* reserved byte */ + proto_tree_add_item(tree, hf_smb_reserved, tvb, offset, 1, ENC_NA); + offset += 1; + + /* file name len */ + fn_len = tvb_get_letohs(tvb, offset); + proto_tree_add_uint(tree, hf_smb_file_name_len, tvb, offset, 2, fn_len); + offset += 2; + + /* Create flags */ + create_flags = tvb_get_letohl(tvb, offset); + offset = dissect_nt_create_bits(tvb, tree, offset, 4, create_flags); + + /* root directory fid */ + proto_tree_add_item(tree, hf_smb_root_dir_fid, tvb, offset, 4, ENC_LITTLE_ENDIAN); + offset += 4; + + /* nt access mask */ + access_mask = tvb_get_letohl(tvb, offset); + offset = dissect_smb_access_mask_bits(tvb, tree, offset, 4, access_mask); + + /* allocation size */ + proto_tree_add_item(tree, hf_smb_alloc_size64, tvb, offset, 8, ENC_LITTLE_ENDIAN); + offset += 8; + + /* Extended File Attributes */ + file_attributes = tvb_get_letohl(tvb, offset); + offset = dissect_file_ext_attr_bits(tvb, tree, offset, 4, file_attributes); + + /* share access */ + share_access = tvb_get_letohl(tvb, offset); + offset = dissect_nt_share_access_bits(tvb, tree, offset, 4, share_access); + + /* create disposition */ + create_disposition = tvb_get_letohl(tvb, offset); + proto_tree_add_item(tree, hf_smb_nt_create_disposition, tvb, offset, 4, ENC_LITTLE_ENDIAN); + offset += 4; + + /* create options */ + create_options = tvb_get_letohl(tvb, offset); + offset = dissect_nt_create_options_bits(tvb, tree, offset, 4, create_options); + + /* impersonation level */ + proto_tree_add_item(tree, hf_smb_nt_impersonation_level, tvb, offset, 4, ENC_LITTLE_ENDIAN); + offset += 4; + + /* security flags */ + offset = dissect_nt_security_flags(tvb, tree, offset); + + BYTE_COUNT; + + /* file name */ + if (fn_len == -1) { + /* + * We never set the file name length, perhaps because + * the word count was zero. This is not a valid + * packet. + */ + proto_tree_add_expert(tree, pinfo, &ei_smb_missing_word_parameters, + tvb, 0, 0); + goto endofcommand; + } + fn = get_unicode_or_ascii_string(tvb, &offset, si->unicode, &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); + + /* store it for the fid->name/openframe/closeframe matching in + * dissect_smb_fid() called from the response. + */ + if ((!pinfo->fd->visited) && si->sip && fn) { + smb_fid_saved_info_t *fsi; + + fsi = wmem_new(wmem_file_scope(), smb_fid_saved_info_t); + fsi->filename = wmem_strdup(wmem_file_scope(), fn); + fsi->create_flags = create_flags; + fsi->access_mask = access_mask; + fsi->file_attributes = file_attributes; + fsi->share_access = share_access; + fsi->create_options = create_options; + fsi->create_disposition = create_disposition; + + si->sip->extra_info_type = SMB_EI_FILEDATA; + si->sip->extra_info = fsi; + } + + col_append_fstr(pinfo->cinfo, COL_INFO, ", Path: %s", + format_text(wmem_packet_scope(), (const guchar*)fn, strlen(fn))); + + END_OF_SMB + + if (cmd != 0xff) { /* there is an andX command */ + if (andxoffset < offset) + THROW(ReportedBoundsError); + dissect_smb_command(tvb, pinfo, andxoffset, smb_tree, cmd, FALSE, si); + } + + return offset; +} + + +static int +dissect_nt_create_andx_response(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int offset, proto_tree *smb_tree, smb_info_t *si) +{ + guint8 wc, cmd = 0xff; + guint16 andxoffset = 0; + guint16 bc; + guint16 fid = 0; + guint16 ftype; + guint8 isdir; + smb_fid_info_t *fid_info = NULL; + + WORD_COUNT; + + /* next smb command */ + cmd = tvb_get_guint8(tvb, offset); + if (cmd != 0xff) { + proto_tree_add_uint(tree, hf_smb_andxcmd, tvb, offset, 1, cmd); + } else { + proto_tree_add_uint_format_value(tree, hf_smb_andxcmd, tvb, offset, 1, cmd, "No further commands (0xff)"); + } + offset += 1; + + /* reserved byte */ + proto_tree_add_item(tree, hf_smb_reserved, tvb, offset, 1, ENC_NA); + offset += 1; + + /* andxoffset */ + andxoffset = tvb_get_letohs(tvb, offset); + proto_tree_add_uint(tree, hf_smb_andxoffset, tvb, offset, 2, andxoffset); + offset += 2; + + /* oplock level */ + proto_tree_add_item(tree, hf_smb_oplock_level, tvb, offset, 1, ENC_LITTLE_ENDIAN); + offset += 1; + + /* fid */ + fid = tvb_get_letohs(tvb, offset); + fid_info = dissect_smb_fid(tvb, pinfo, tree, offset, 2, fid, TRUE, FALSE, FALSE, si); + offset += 2; + + /* create action */ + /*XXX is this really the same as create disposition in the request? it looks so*/ + /* No, it is not. It is the same as the create action from an Open&X request ... RJS */ + proto_tree_add_item(tree, hf_smb_create_action, tvb, offset, 4, ENC_LITTLE_ENDIAN); + offset += 4; + + /* create time */ + offset = dissect_nt_64bit_time(tvb, tree, offset, hf_smb_create_time); + + /* access time */ + offset = dissect_nt_64bit_time(tvb, tree, offset, hf_smb_access_time); + + /* last write time */ + offset = dissect_nt_64bit_time(tvb, tree, offset, + hf_smb_last_write_time); + + /* last change time */ + offset = dissect_nt_64bit_time(tvb, tree, offset, hf_smb_change_time); + + /* Extended File Attributes */ + offset = dissect_file_ext_attr(tvb, tree, offset); + + /* allocation size */ + proto_tree_add_item(tree, hf_smb_alloc_size64, tvb, offset, 8, ENC_LITTLE_ENDIAN); + offset += 8; + + /* end of file */ + /* We store the end of file */ + if (fid_info) { + fid_info->end_of_file = tvb_get_letoh64(tvb, offset); + } + proto_tree_add_item(tree, hf_smb_end_of_file, tvb, offset, 8, ENC_LITTLE_ENDIAN); + offset += 8; + + /* File Type */ + ftype = tvb_get_letohs(tvb, offset); + proto_tree_add_item(tree, hf_smb_file_type, tvb, offset, 2, ENC_LITTLE_ENDIAN); + offset += 2; + + /* IPC State */ + offset = dissect_ipc_state(tvb, tree, offset, FALSE); + + /* is directory */ + isdir = tvb_get_guint8(tvb, offset); + proto_tree_add_item(tree, hf_smb_is_directory, tvb, offset, 1, ENC_LITTLE_ENDIAN); + offset += 1; + + /* Always use the word count to decide if this is an "extended" response. + When the server doesn't support the 0x10 flag, it will send a normal + 34 word response, so the word count is the only way to tell which of + the response formats we have. MS-SMB 2.2.4.9.2 + Also note that the extended format is actually 50 words, but in a + "windows behavior note" they say Windows sets word count to 42. + Handle anything 42 or larger as "extended" format. */ + if (wc >= 42) { + proto_tree *tr = NULL; + + /* The first field is a Volume GUID ... */ + proto_tree_add_item(tree, hf_smb_volume_guid, + tvb, offset, 16, ENC_NA); + offset += 16; + + /* The file ID comes next */ + proto_tree_add_item(tree, hf_smb_file_id_64bit, + tvb, offset, 8, ENC_LITTLE_ENDIAN); + offset += 8; + + tr = proto_tree_add_subtree(tree, tvb, offset, 4, + ett_smb_nt_access_mask, NULL, "Maximal Access Rights"); + + offset = dissect_smb_access_mask(tvb, tr, offset); + + tr = proto_tree_add_subtree(tree, tvb, offset, 4, + ett_smb_nt_access_mask, NULL, "Guest Maximal Access Rights"); + + offset = dissect_smb_access_mask(tvb, tr, offset); + } + + /* Try to remember the type of this fid so that we can dissect + * any future security descriptor (access mask) properly + */ + if (ftype == 0) { + if (isdir == 0) { + if (fid_info) { + fid_info->type = SMB_FID_TYPE_FILE; + } + } else { + if (fid_info) { + fid_info->type = SMB_FID_TYPE_DIR; + } + } + } + if (ftype == 2) { + if (fid_info) { + fid_info->type = SMB_FID_TYPE_PIPE; + } + } + + BYTE_COUNT; + + END_OF_SMB + + if (cmd != 0xff) { /* there is an andX command */ + if (andxoffset < offset) + THROW(ReportedBoundsError); + dissect_smb_command(tvb, pinfo, andxoffset, smb_tree, cmd, FALSE, si); + } + + /* if there was an error, add a generated filename to the tree */ + if (si->nt_status) { + dissect_smb_fid(tvb, pinfo, tree, 0, 0, fid, TRUE, TRUE, TRUE, si); + } + + return offset; +} + + +static int +dissect_nt_cancel_request(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, int offset, proto_tree *smb_tree _U_, smb_info_t *si _U_) +{ + guint8 wc; + guint16 bc; + + WORD_COUNT; + + BYTE_COUNT; + + END_OF_SMB + + return offset; +} + +/* XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX + BEGIN Transaction/Transaction2 Primary and secondary requests + XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX */ + + +static const value_string trans2_cmd_vals[] = { + { 0x00, "OPEN2" }, + { 0x01, "FIND_FIRST2" }, + { 0x02, "FIND_NEXT2" }, + { 0x03, "QUERY_FS_INFO" }, + { 0x04, "SET_FS_INFO" }, + { 0x05, "QUERY_PATH_INFO" }, + { 0x06, "SET_PATH_INFO" }, + { 0x07, "QUERY_FILE_INFO" }, + { 0x08, "SET_FILE_INFO" }, + { 0x09, "FSCTL" }, + { 0x0A, "IOCTL2" }, + { 0x0B, "FIND_NOTIFY_FIRST" }, + { 0x0C, "FIND_NOTIFY_NEXT" }, + { 0x0D, "CREATE_DIRECTORY" }, + { 0x0E, "SESSION_SETUP" }, + { 0x0F, "Unknown (0x0f)" }, /* dummy so val_to_str_ext can do indexed lookup */ + { 0x10, "GET_DFS_REFERRAL" }, + { 0x11, "REPORT_DFS_INCONSISTENCY" }, + { 0, NULL } +}; +value_string_ext trans2_cmd_vals_ext = VALUE_STRING_EXT_INIT(trans2_cmd_vals); + +static const true_false_string tfs_tf_dtid = { + "Also DISCONNECT TID", + "Do NOT disconnect TID" +}; +static const true_false_string tfs_tf_owt = { + "One Way Transaction (NO RESPONSE)", + "Two way transaction" +}; + +static const true_false_string tfs_ff2_backup = { + "Find WITH backup intent", + "No backup intent" +}; +static const true_false_string tfs_ff2_continue = { + "CONTINUE search from previous position", + "New search, do NOT continue from previous position" +}; +static const true_false_string tfs_ff2_resume = { + "Return RESUME keys", + "Do NOT return resume keys" +}; +static const true_false_string tfs_ff2_close_eos = { + "CLOSE search if END OF SEARCH is reached", + "Do NOT close search if end of search reached" +}; +static const true_false_string tfs_ff2_close = { + "CLOSE search after this request", + "Do NOT close search after this request" +}; + +/* used by + TRANS2_FIND_FIRST2 +*/ +static const value_string ff2_il_vals[] = { + { 1, "Info Standard"}, + { 2, "Info Query EA Size"}, + { 3, "Info Query EAs From List"}, + { 0x0101, "Find File Directory Info"}, + { 0x0102, "Find File Full Directory Info"}, + { 0x0103, "Find File Names Info"}, + { 0x0104, "Find File Both Directory Info"}, + { 0x0105, "Find File Full Directory Info"}, + { 0x0106, "Find File Id Both Directory Info"}, + { 0x0202, "Find File Unix"}, + { 0x020B, "Find File Unix Info2"}, + {0, NULL} +}; + +/* values used by : + TRANS2_QUERY_PATH_INFORMATION + TRANS2_QUERY_FILE_INFORMATION +*/ +static const value_string qpi_loi_vals[] = { + { 1, "Info Standard"}, + { 2, "Info Query EA Size"}, + { 3, "Info Query EAs From List"}, + { 4, "Info Query All EAs"}, + { 6, "Info Is Name Valid"}, + { 0x0101, "Query File Basic Info"}, + { 0x0102, "Query File Standard Info"}, + { 0x0103, "Query File EA Info"}, + { 0x0104, "Query File Name Info"}, + { 0x0107, "Query File All Info"}, + { 0x0108, "Query File Alt Name Info"}, + { 0x0109, "Query File Stream Info"}, + { 0x010b, "Query File Compression Info"}, + { 0x0200, "Query File Unix Basic"}, + { 0x0201, "Query File Unix Link"}, + { 0x0202, "Query File Unix Hardlink"}, + { 0x0204, "Query File Posix ACL"}, + { 0x0205, "Query File Posix XATTR"}, + { 0x0206, "Query File Posix Attr Flags"}, + { 0x0207, "Query File Posix Permissions"}, + { 0x0208, "Query File Posix Lock"}, + { 0x020b, "Query File Unix Info2"}, + { 1004, "Query File Basic Info"}, + { 1005, "Query File Standard Info"}, + { 1006, "Query File Internal Info"}, + { 1007, "Query File EA Info"}, + { 1009, "Query File Name Info"}, + { 1010, "Query File Rename Info"}, + { 1011, "Query File Link Info"}, + { 1012, "Query File Names Info"}, + { 1013, "Query File Disposition Info"}, + { 1014, "Query File Position Info"}, + { 1015, "Query File Full EA Info"}, + { 1016, "Query File Mode Info"}, + { 1017, "Query File Alignment Info"}, + { 1018, "Query File All Info"}, + { 1019, "Query File Allocation Info"}, + { 1020, "Query File End of File Info"}, + { 1021, "Query File Alt Name Info"}, + { 1022, "Query File Stream Info"}, + { 1023, "Query File Pipe Info"}, + { 1024, "Query File Pipe Local Info"}, + { 1025, "Query File Pipe Remote Info"}, + { 1026, "Query File Mailslot Query Info"}, + { 1027, "Query File Mailslot Set Info"}, + { 1028, "Query File Compression Info"}, + { 1029, "Query File ObjectID Info"}, + { 1030, "Query File Completion Info"}, + { 1031, "Query File Move Cluster Info"}, + { 1032, "Query File Quota Info"}, + { 1033, "Query File Reparsepoint Info"}, + { 1034, "Query File Network Open Info"}, + { 1035, "Query File Attribute Tag Info"}, + { 1036, "Query File Tracking Info"}, + { 1037, "Query File Maximum Info"}, + {0, NULL} +}; +static value_string_ext qpi_loi_vals_ext = VALUE_STRING_EXT_INIT(qpi_loi_vals); + +/* values used by : + TRANS2_SET_PATH_INFORMATION + TRANS2_SET_FILE_INFORMATION + (the SNIA CIFS spec lists some only for TRANS2_SET_FILE_INFORMATION, + but I'm assuming they apply to TRANS2_SET_PATH_INFORMATION as + well; note that they're different from the QUERY_PATH_INFORMATION + and QUERY_FILE_INFORMATION values!) +*/ +static const value_string spi_loi_vals[] = { + { 1, "Info Standard"}, + { 2, "Info Set EAs"}, + { 4, "Info Query All EAs"}, + { 0x0101, "Set File Basic Info"}, + { 0x0102, "Set File Disposition Info"}, + { 0x0103, "Set File Allocation Info"}, + { 0x0104, "Set File End Of File Info"}, + { 0x0200, "Set File Unix Basic"}, + { 0x0201, "Set File Unix Link"}, + { 0x0202, "Set File Unix HardLink"}, + { 0x0204, "Set File Unix ACL"}, + { 0x0205, "Set File Unix XATTR"}, + { 0x0206, "Set File Unix Attr Flags"}, + { 0x0208, "Set File Posix Lock"}, + { 0x0209, "Set File Posix Open"}, + { 0x020a, "Set File Posix Unlink"}, + { 0x020b, "Set File Unix Info2"}, + { 1004, "Set File Basic Info"}, + { 1010, "Set Rename Information"}, + { 1013, "Set Disposition Information"}, + { 1014, "Set Position Information"}, + { 1016, "Set Mode Information"}, + { 1019, "Set Allocation Information"}, + { 1020, "Set EOF Information"}, + { 1023, "Set File Pipe Information"}, + { 1025, "Set File Pipe Remote Information"}, + { 1029, "Set Copy On Write Information"}, + { 1032, "Set OLE Class ID Information"}, + { 1039, "Set Inherit Context Index Information"}, + { 1040, "Set OLE Information (?)"}, + {0, NULL} +}; +static value_string_ext spi_loi_vals_ext = VALUE_STRING_EXT_INIT(spi_loi_vals); + +static const value_string qfsi_vals[] = { + { 1, "Info Allocation"}, + { 2, "Info Volume"}, + { 0x0101, "Query FS Label Info"}, + { 0x0102, "Query FS Volume Info"}, + { 0x0103, "Query FS Size Info"}, + { 0x0104, "Query FS Device Info"}, + { 0x0105, "Query FS Attribute Info"}, + { 0x0200, "Unix Query FS Info"}, + { 0x0202, "Unix Query POSIX whoami"}, + { 0x0301, "Mac Query FS Info"}, + { 1001, "Query FS Label Info"}, + { 1002, "Query FS Volume Info"}, + { 1003, "Query FS Size Info"}, + { 1004, "Query FS Device Info"}, + { 1005, "Query FS Attribute Info"}, + { 1006, "Query FS Quota Info"}, + { 1007, "Query Full FS Size Info"}, + { 1008, "Object ID Information"}, + {0, NULL} +}; +static value_string_ext qfsi_vals_ext = VALUE_STRING_EXT_INIT(qfsi_vals); + +static const value_string sfsi_vals[] = { + { 0x203, "Request Transport Encryption"}, + { 1006, "Set 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"}, + {0, NULL} +}; + +static const value_string alignment_vals[] = { + {0, "Byte alignment"}, + {1, "Word (16bit) alignment"}, + {3, "Long (32bit) alignment"}, + {7, "8 byte boundary alignment"}, + {0x0f, "16 byte boundary alignment"}, + {0x1f, "32 byte boundary alignment"}, + {0x3f, "64 byte boundary alignment"}, + {0x7f, "128 byte boundary alignment"}, + {0xff, "256 byte boundary alignment"}, + {0x1ff, "512 byte boundary alignment"}, + {0, NULL} +}; + +static const true_false_string tfs_marked_for_deletion = { + "File is MARKED FOR DELETION", + "File is NOT marked for deletion" +}; + +static const true_false_string tfs_get_dfs_server_hold_storage = { + "Referral SERVER HOLDS STORAGE for the file", + "Referral server does NOT hold storage for the file" +}; +static const true_false_string tfs_get_dfs_fielding = { + "The server in referral is FIELDING CAPABLE", + "The server in referrals is NOT fielding capable" +}; + +static const true_false_string tfs_dfs_referral_flags_name_list_referral = { + "A domain/DC referral response", + "NOT a domain/DC referral response" +}; + +static const true_false_string tfs_dfs_referral_flags_target_set_boundary = { + "The first target in the target set", + "NOT the first target in the target set" +}; + +static const value_string dfs_referral_server_type_vals[] = { + {0, "Non-root targets returned"}, + {1, "Root targets returns"}, + {0, NULL} +}; + + +static const true_false_string tfs_device_char_removable = { + "This is a REMOVABLE device", + "This is NOT a removable device" +}; +static const true_false_string tfs_device_char_read_only = { + "This is a READ-ONLY device", + "This is NOT a read-only device" +}; +static const true_false_string tfs_device_char_floppy = { + "This is a FLOPPY DISK device", + "This is NOT a floppy disk device" +}; +static const true_false_string tfs_device_char_write_once = { + "This is a WRITE-ONCE device", + "This is NOT a write-once device" +}; +static const true_false_string tfs_device_char_remote = { + "This is a REMOTE device", + "This is NOT a remote device" +}; +static const true_false_string tfs_device_char_mounted = { + "This device is MOUNTED", + "This device is NOT mounted" +}; +static const true_false_string tfs_device_char_virtual = { + "This is a VIRTUAL device", + "This is NOT a virtual device" +}; +static const true_false_string tfs_device_char_secure_open = { + "This device supports SECURE OPEN", + "This device does NOT support secure open" +}; +static const true_false_string tfs_device_char_ts = { + "This is a TERMINAL SERVICES device", + "This is NOT a terminal services device" +}; +static const true_false_string tfs_device_char_webdav = { + "This is a WEBDAV device", + "This is NOT a webdav device" +}; +static const true_false_string tfs_device_char_portable = { + "This is a PORTABLE device", + "This is NOT a portable device" +}; +static const true_false_string tfs_device_char_aat = { + "This device ALLOWS APPCONTAINER TRAVERSAL", + "This device does NOT allow appcontainer traversal" +}; + +static const true_false_string tfs_fs_attr_css = { + "This FS supports CASE SENSITIVE SEARCHes", + "This FS does NOT support case sensitive searches" +}; +static const true_false_string tfs_fs_attr_cpn = { + "This FS supports CASE PRESERVED NAMES", + "This FS does NOT support case preserved names" +}; +static const true_false_string tfs_fs_attr_uod = { + "This FS supports UNICODE NAMES", + "This FS does NOT support unicode names" +}; +static const true_false_string tfs_fs_attr_pacls = { + "This FS supports PERSISTENT ACLs", + "This FS does NOT support persistent acls" +}; +static const true_false_string tfs_fs_attr_fc = { + "This FS supports COMPRESSED FILES", + "This FS does NOT support compressed files" +}; +static const true_false_string tfs_fs_attr_vq = { + "This FS supports VOLUME QUOTAS", + "This FS does NOT support volume quotas" +}; +static const true_false_string tfs_fs_attr_srp = { + "This FS supports REPARSE POINTS", + "This FS does NOT support reparse points" +}; +static const true_false_string tfs_fs_attr_srs = { + "This FS supports REMOTE STORAGE", + "This FS does NOT support remote storage" +}; +static const true_false_string tfs_fs_attr_ssf = { + "This FS supports SPARSE FILES", + "This FS does NOT support sparse files" +}; +static const true_false_string tfs_fs_attr_sla = { + "This FS supports LFN APIs", + "This FS does NOT support lfn apis" +}; +static const true_false_string tfs_fs_attr_vic = { + "This FS VOLUME IS COMPRESSED", + "This FS volume is NOT compressed" +}; +static const true_false_string tfs_fs_attr_soids = { + "This FS supports OIDs", + "This FS does NOT support OIDs" +}; +static const true_false_string tfs_fs_attr_se = { + "This FS supports ENCRYPTION", + "This FS does NOT support encryption" +}; +static const true_false_string tfs_fs_attr_ns = { + "This FS supports NAMED STREAMS", + "This FS does NOT support named streams" +}; +static const true_false_string tfs_fs_attr_rov = { + "This is a READ ONLY VOLUME", + "This is a read/write volume" +}; +static const true_false_string tfs_fs_attr_swo = { + "This is a SEQUENTIAL WRITE ONCE VOLUME", + "This is NOT a sequential write once volume" +}; +static const true_false_string tfs_fs_attr_st = { + "This filesystem supports TRANSACTIONS", + "This filesystem does NOT support transactions" +}; +static const true_false_string tfs_fs_attr_shl = { + "This filesystem supports HARD LINKS", + "This filesystem does NOT support hard links" +}; +static const true_false_string tfs_fs_attr_sis = { + "This filesystem supports INTEGRITY STREAMS", + "This filesystem does NOT support integrity streams" +}; +static const true_false_string tfs_fs_attr_sbr = { + "This filesystem supports BLOCK REFCOUNTING", + "This filesystem does NOT support block refcounting" +}; +static const true_false_string tfs_fs_attr_ssv = { + "This filesystem supports SPARSE VDL", + "This filesystem does NOT support sparse vdl" +}; + +#define FF2_RESUME 0x0004 + +static int +dissect_ff2_flags(tvbuff_t *tvb, packet_info *pinfo, proto_tree *parent_tree, int offset, smb_info_t *si) +{ + guint16 mask; + smb_transact2_info_t *t2i; + static int * const flags[] = { + &hf_smb_ff2_backup, + &hf_smb_ff2_continue, + &hf_smb_ff2_resume, + &hf_smb_ff2_close_eos, + &hf_smb_ff2_close, + NULL + }; + + mask = tvb_get_letohs(tvb, offset); + + DISSECTOR_ASSERT(si); + + if ((si->sip != NULL) && (si->sip->extra_info_type == SMB_EI_T2I)) { + t2i = (smb_transact2_info_t *)si->sip->extra_info; + if (t2i != NULL) { + if (!pinfo->fd->visited) + t2i->resume_keys = (mask & FF2_RESUME); + } + } + + proto_tree_add_bitmask(parent_tree, tvb, offset, hf_smb_ff2, ett_smb_find_first2_flags, flags, ENC_LITTLE_ENDIAN); + offset += 2; + + return offset; +} + +#if 0 +static int +dissect_sfi_ioflag(tvbuff_t *tvb, proto_tree *parent_tree, int offset) +{ + static int * const flags[] = { + &hf_smb_sfi_writetru, + &hf_smb_sfi_caching, + NULL + }; + + proto_tree_add_bitmask(parent_tree, tvb, offset, hf_smb_sfi, ett_smb_ioflag, flags, ENC_LITTLE_ENDIAN); + offset += 2; + + return offset; +} +#endif + +int +dissect_get_dfs_request_data(tvbuff_t *tvb, packet_info *pinfo, + proto_tree *tree, int offset, guint16 *bcp, gboolean unicode) +{ + int fn_len; + const char *fn; + guint16 bc = *bcp; + + /* referral level */ + CHECK_BYTE_COUNT_TRANS(2); + proto_tree_add_item(tree, hf_smb_max_referral_level, tvb, offset, 2, ENC_LITTLE_ENDIAN); + COUNT_BYTES_TRANS(2); + + /* file name */ + fn = get_unicode_or_ascii_string(tvb, &offset, unicode, &fn_len, FALSE, FALSE, &bc); + CHECK_STRING_TRANS(fn); + proto_tree_add_string(tree, hf_smb_file_name, tvb, offset, fn_len, + fn); + COUNT_BYTES_TRANS(fn_len); + + col_append_fstr(pinfo->cinfo, COL_INFO, ", File: %s", + format_text(wmem_packet_scope(), (const guchar*)fn, strlen(fn))); + + *bcp = bc; + return offset; +} + +static int +dissect_transaction2_request_parameters(tvbuff_t *tvb, packet_info *pinfo, + proto_tree *parent_tree, int offset, int subcmd, guint16 bc, smb_info_t *si) +{ + proto_tree *tree; + smb_transact2_info_t *t2i; + int fn_len; + const char *fn; + + DISSECTOR_ASSERT(si); + + if ((si->sip != NULL) && (si->sip->extra_info_type == SMB_EI_T2I)) + t2i = (smb_transact2_info_t *)si->sip->extra_info; + else + t2i = NULL; + + tree = proto_tree_add_subtree_format(parent_tree, tvb, offset, bc, + ett_smb_transaction_params, NULL, "%s Parameters", + val_to_str_ext(subcmd, &trans2_cmd_vals_ext, + "Unknown (0x%02x)")); + + switch(subcmd) { + case 0x0000: /*TRANS2_OPEN2*/ + /* open flags */ + CHECK_BYTE_COUNT_TRANS(2); + offset = dissect_open_flags(tvb, tree, offset, 0x000f); + bc -= 2; + + /* desired access */ + CHECK_BYTE_COUNT_TRANS(2); + offset = dissect_access(tvb, tree, offset, hf_smb_desired_access); + bc -= 2; + + /* Search Attributes */ + CHECK_BYTE_COUNT_TRANS(2); + offset = dissect_search_attributes(tvb, tree, offset); + bc -= 2; + + /* File Attributes */ + CHECK_BYTE_COUNT_TRANS(2); + offset = dissect_file_attributes(tvb, tree, offset); + bc -= 2; + + /* create time */ + CHECK_BYTE_COUNT_TRANS(4); + offset = dissect_smb_datetime(tvb, tree, offset, + hf_smb_create_time, + hf_smb_create_dos_date, hf_smb_create_dos_time, + TRUE); + bc -= 4; + + /* open function */ + CHECK_BYTE_COUNT_TRANS(2); + offset = dissect_open_function(tvb, tree, offset); + bc -= 2; + + /* allocation size */ + CHECK_BYTE_COUNT_TRANS(4); + proto_tree_add_item(tree, hf_smb_alloc_size, tvb, offset, 4, ENC_LITTLE_ENDIAN); + COUNT_BYTES_TRANS(4); + + /* 10 reserved bytes */ + CHECK_BYTE_COUNT_TRANS(10); + proto_tree_add_item(tree, hf_smb_reserved, tvb, offset, 10, ENC_NA); + COUNT_BYTES_TRANS(10); + + /* file name */ + fn = get_unicode_or_ascii_string(tvb, &offset, si->unicode, &fn_len, FALSE, FALSE, &bc); + CHECK_STRING_TRANS(fn); + proto_tree_add_string(tree, hf_smb_file_name, tvb, offset, fn_len, + fn); + COUNT_BYTES_TRANS(fn_len); + + col_append_fstr(pinfo->cinfo, COL_INFO, ", Path: %s", + format_text(wmem_packet_scope(), (const guchar*)fn, strlen(fn))); + break; + case 0x0001: /*TRANS2_FIND_FIRST2*/ + /* Search Attributes */ + CHECK_BYTE_COUNT_TRANS(2); + offset = dissect_search_attributes(tvb, tree, offset); + bc -= 2; + + /* search count */ + CHECK_BYTE_COUNT_TRANS(2); + proto_tree_add_item(tree, hf_smb_search_count, tvb, offset, 2, ENC_LITTLE_ENDIAN); + COUNT_BYTES_TRANS(2); + + /* Find First2 flags */ + CHECK_BYTE_COUNT_TRANS(2); + offset = dissect_ff2_flags(tvb, pinfo, tree, offset, si); + bc -= 2; + + /* Find First2 information level */ + CHECK_BYTE_COUNT_TRANS(2); + si->info_level = tvb_get_letohs(tvb, offset); + if ((t2i != NULL) && !pinfo->fd->visited) + t2i->info_level = si->info_level; + proto_tree_add_uint(tree, hf_smb_ff2_information_level, tvb, offset, 2, si->info_level); + COUNT_BYTES_TRANS(2); + + /* storage type */ + CHECK_BYTE_COUNT_TRANS(4); + proto_tree_add_item(tree, hf_smb_storage_type, tvb, offset, 4, ENC_LITTLE_ENDIAN); + COUNT_BYTES_TRANS(4); + + /* search pattern */ + fn = get_unicode_or_ascii_string(tvb, &offset, si->unicode, &fn_len, FALSE, FALSE, &bc); + CHECK_STRING_TRANS(fn); + if (t2i && !t2i->name) { + t2i->name = wmem_strdup(wmem_file_scope(), fn); + } + proto_tree_add_string(tree, hf_smb_search_pattern, tvb, offset, fn_len, + fn); + COUNT_BYTES_TRANS(fn_len); + + col_append_fstr(pinfo->cinfo, COL_INFO, ", Pattern: %s", + format_text(wmem_packet_scope(), (const guchar*)fn, strlen(fn))); + + break; + case 0x0002: /*TRANS2_FIND_NEXT2*/ + /* sid */ + CHECK_BYTE_COUNT_TRANS(2); + proto_tree_add_item(tree, hf_smb_search_id, tvb, offset, 2, ENC_LITTLE_ENDIAN); + COUNT_BYTES_TRANS(2); + + /* search count */ + CHECK_BYTE_COUNT_TRANS(2); + proto_tree_add_item(tree, hf_smb_search_count, tvb, offset, 2, ENC_LITTLE_ENDIAN); + COUNT_BYTES_TRANS(2); + + /* Find First2 information level */ + CHECK_BYTE_COUNT_TRANS(2); + si->info_level = tvb_get_letohs(tvb, offset); + if ((t2i != NULL) && !pinfo->fd->visited) + t2i->info_level = si->info_level; + proto_tree_add_uint(tree, hf_smb_ff2_information_level, tvb, offset, 2, si->info_level); + COUNT_BYTES_TRANS(2); + + /* resume key */ + CHECK_BYTE_COUNT_TRANS(4); + proto_tree_add_item(tree, hf_smb_resume, tvb, offset, 4, ENC_LITTLE_ENDIAN); + COUNT_BYTES_TRANS(4); + + /* Find First2 flags */ + CHECK_BYTE_COUNT_TRANS(2); + offset = dissect_ff2_flags(tvb, pinfo, tree, offset, si); + bc -= 2; + + /* file name */ + fn = get_unicode_or_ascii_string(tvb, &offset, si->unicode, &fn_len, FALSE, FALSE, &bc); + CHECK_STRING_TRANS(fn); + proto_tree_add_string(tree, hf_smb_file_name, tvb, offset, fn_len, + fn); + COUNT_BYTES_TRANS(fn_len); + + col_append_fstr(pinfo->cinfo, COL_INFO, ", Continue: %s", + format_text(wmem_packet_scope(), (const guchar*)fn, strlen(fn))); + + break; + case 0x0003: /*TRANS2_QUERY_FS_INFORMATION*/ + /* level of interest */ + CHECK_BYTE_COUNT_TRANS(2); + si->info_level = tvb_get_letohs(tvb, offset); + if ((t2i != NULL) && !pinfo->fd->visited) + t2i->info_level = si->info_level; + proto_tree_add_uint(tree, hf_smb_qfsi_information_level, tvb, offset, 2, si->info_level); + COUNT_BYTES_TRANS(2); + + col_append_fstr(pinfo->cinfo, COL_INFO, ", %s", + val_to_str_ext(si->info_level, &qfsi_vals_ext, + "Unknown (0x%02x)")); + + break; + case 0x0004: /*TRANS2_SET_FS_INFORMATION*/ + /* level of interest */ + CHECK_BYTE_COUNT_TRANS(4); + si->info_level = tvb_get_letohs(tvb, offset+2); + if ((t2i != NULL) && !pinfo->fd->visited) + t2i->info_level = si->info_level; + proto_tree_add_uint(tree, hf_smb_sfsi_information_level, tvb, offset+2, 2, si->info_level); + COUNT_BYTES_TRANS(4); + + col_append_fstr(pinfo->cinfo, COL_INFO, ", %s", + val_to_str(si->info_level, sfsi_vals, + "Unknown (0x%02x)")); + + break; + case 0x0005: /*TRANS2_QUERY_PATH_INFORMATION*/ + /* level of interest */ + CHECK_BYTE_COUNT_TRANS(2); + si->info_level = tvb_get_letohs(tvb, offset); + if ((t2i != NULL) && !pinfo->fd->visited) + t2i->info_level = si->info_level; + proto_tree_add_uint(tree, hf_smb_qpi_loi, tvb, offset, 2, si->info_level); + COUNT_BYTES_TRANS(2); + + col_append_fstr( + pinfo->cinfo, COL_INFO, ", %s", + val_to_str_ext(si->info_level, &qpi_loi_vals_ext, + "Unknown (%u)")); + + /* 4 reserved bytes */ + CHECK_BYTE_COUNT_TRANS(4); + proto_tree_add_item(tree, hf_smb_reserved, tvb, offset, 4, ENC_NA); + COUNT_BYTES_TRANS(4); + + /* file name */ + fn = tvb_get_stringz_enc(wmem_packet_scope(), tvb, offset, &fn_len, (si->unicode ? ENC_UTF_16|ENC_LITTLE_ENDIAN : ENC_ASCII|ENC_NA)); + + CHECK_STRING_TRANS(fn); + proto_tree_add_string(tree, hf_smb_file_name, tvb, offset, fn_len, + fn); + COUNT_BYTES_TRANS(fn_len); + if (t2i && !t2i->name) { + t2i->name = wmem_strdup(wmem_file_scope(), fn); + } + + col_append_fstr(pinfo->cinfo, COL_INFO, ", Path: %s", + format_text(wmem_packet_scope(), (const guchar*)fn, strlen(fn))); + + break; + case 0x0006: /*TRANS2_SET_PATH_INFORMATION*/ + /* level of interest */ + CHECK_BYTE_COUNT_TRANS(2); + si->info_level = tvb_get_letohs(tvb, offset); + if ((t2i != NULL) && !pinfo->fd->visited) + t2i->info_level = si->info_level; + proto_tree_add_uint(tree, hf_smb_spi_loi, tvb, offset, 2, si->info_level); + COUNT_BYTES_TRANS(2); + + /* 4 reserved bytes */ + CHECK_BYTE_COUNT_TRANS(4); + proto_tree_add_item(tree, hf_smb_reserved, tvb, offset, 4, ENC_NA); + COUNT_BYTES_TRANS(4); + + /* file name */ + fn = get_unicode_or_ascii_string(tvb, &offset, si->unicode, &fn_len, FALSE, FALSE, &bc); + CHECK_STRING_TRANS(fn); + proto_tree_add_string(tree, hf_smb_file_name, tvb, offset, fn_len, + fn); + COUNT_BYTES_TRANS(fn_len); + + col_append_fstr(pinfo->cinfo, COL_INFO, ", Path: %s", + format_text(wmem_packet_scope(), (const guchar*)fn, strlen(fn))); + + break; + case 0x0007: { /*TRANS2_QUERY_FILE_INFORMATION*/ + guint16 fid; + + /* fid */ + CHECK_BYTE_COUNT_TRANS(2); + fid = tvb_get_letohs(tvb, offset); + dissect_smb_fid(tvb, pinfo, tree, offset, 2, fid, FALSE, FALSE, FALSE, si); + COUNT_BYTES_TRANS(2); + + /* level of interest */ + CHECK_BYTE_COUNT_TRANS(2); + si->info_level = tvb_get_letohs(tvb, offset); + if ((t2i != NULL) && !pinfo->fd->visited) + t2i->info_level = si->info_level; + proto_tree_add_uint(tree, hf_smb_qpi_loi, tvb, offset, 2, si->info_level); + COUNT_BYTES_TRANS(2); + + col_append_fstr( + pinfo->cinfo, COL_INFO, ", %s", + val_to_str_ext(si->info_level, &qpi_loi_vals_ext, + "Unknown (%u)")); + + break; + } + case 0x0008: { /*TRANS2_SET_FILE_INFORMATION*/ + guint16 fid; + + /* fid */ + CHECK_BYTE_COUNT_TRANS(2); + fid = tvb_get_letohs(tvb, offset); + dissect_smb_fid(tvb, pinfo, tree, offset, 2, fid, FALSE, FALSE, FALSE, si); + COUNT_BYTES_TRANS(2); + + /* level of interest */ + CHECK_BYTE_COUNT_TRANS(2); + si->info_level = tvb_get_letohs(tvb, offset); + if ((t2i != NULL) && !pinfo->fd->visited) + t2i->info_level = si->info_level; + proto_tree_add_uint(tree, hf_smb_spi_loi, tvb, offset, 2, si->info_level); + COUNT_BYTES_TRANS(2); + +#if 0 + /* + * XXX - "Microsoft Networks SMB File Sharing Protocol + * Extensions Version 3.0, Document Version 1.11, + * July 19, 1990" says this is I/O flags, but it's + * reserved in the SNIA spec, and some clients appear + * to leave junk in it. + * + * Is this some field used only if a particular + * dialect was negotiated, so that clients can feel + * safe not setting it if they haven't negotiated that + * dialect? Or do the (non-OS/2) clients simply not care + * about that particular OS/2-oriented dialect? + */ + + /* IO Flag */ + CHECK_BYTE_COUNT_TRANS(2); + offset = dissect_sfi_ioflag(tvb, tree, offset); + bc -= 2; +#else + /* 2 reserved bytes */ + CHECK_BYTE_COUNT_TRANS(2); + proto_tree_add_item(tree, hf_smb_reserved, tvb, offset, 2, ENC_NA); + COUNT_BYTES_TRANS(2); +#endif + + break; + } + case 0x0009: /*TRANS2_FSCTL*/ + /* this call has no parameter block in the request */ + + /* + * XXX - "Microsoft Networks SMB File Sharing Protocol + * Extensions Version 3.0, Document Version 1.11, + * July 19, 1990" says this contains a + * "File system specific parameter block". (That means + * we may not be able to dissect it in any case.) + */ + break; + case 0x000a: /*TRANS2_IOCTL2*/ + /* this call has no parameter block in the request */ + + /* + * XXX - "Microsoft Networks SMB File Sharing Protocol + * Extensions Version 3.0, Document Version 1.11, + * July 19, 1990" says this contains a + * "Device/function specific parameter block". (That + * means we may not be able to dissect it in any case.) + */ + break; + case 0x000b: /*TRANS2_FIND_NOTIFY_FIRST*/ + /* Search Attributes */ + CHECK_BYTE_COUNT_TRANS(2); + offset = dissect_search_attributes(tvb, tree, offset); + bc -= 2; + + /* Number of changes to wait for */ + CHECK_BYTE_COUNT_TRANS(2); + proto_tree_add_item(tree, hf_smb_change_count, tvb, offset, 2, ENC_LITTLE_ENDIAN); + COUNT_BYTES_TRANS(2); + + /* Find Notify information level */ + CHECK_BYTE_COUNT_TRANS(2); + si->info_level = tvb_get_letohs(tvb, offset); + if ((t2i != NULL) && !pinfo->fd->visited) + t2i->info_level = si->info_level; + proto_tree_add_uint(tree, hf_smb_fn_information_level, tvb, offset, 2, si->info_level); + COUNT_BYTES_TRANS(2); + + /* 4 reserved bytes */ + CHECK_BYTE_COUNT_TRANS(4); + proto_tree_add_item(tree, hf_smb_reserved, tvb, offset, 4, ENC_NA); + COUNT_BYTES_TRANS(4); + + /* file name */ + fn = get_unicode_or_ascii_string(tvb, &offset, si->unicode, &fn_len, FALSE, FALSE, &bc); + CHECK_STRING_TRANS(fn); + proto_tree_add_string(tree, hf_smb_file_name, tvb, offset, fn_len, + fn); + COUNT_BYTES_TRANS(fn_len); + + col_append_fstr(pinfo->cinfo, COL_INFO, ", Path: %s", + format_text(wmem_packet_scope(), (const guchar*)fn, strlen(fn))); + + break; + case 0x000c: /*TRANS2_FIND_NOTIFY_NEXT*/ + /* Monitor handle */ + CHECK_BYTE_COUNT_TRANS(2); + proto_tree_add_item(tree, hf_smb_monitor_handle, tvb, offset, 2, ENC_LITTLE_ENDIAN); + COUNT_BYTES_TRANS(2); + + /* Number of changes to wait for */ + CHECK_BYTE_COUNT_TRANS(2); + proto_tree_add_item(tree, hf_smb_change_count, tvb, offset, 2, ENC_LITTLE_ENDIAN); + COUNT_BYTES_TRANS(2); + + break; + case 0x000d: /*TRANS2_CREATE_DIRECTORY*/ + /* 4 reserved bytes */ + CHECK_BYTE_COUNT_TRANS(4); + proto_tree_add_item(tree, hf_smb_reserved, tvb, offset, 4, ENC_NA); + COUNT_BYTES_TRANS(4); + + /* dir name */ + fn = get_unicode_or_ascii_string(tvb, &offset, si->unicode, &fn_len, + FALSE, FALSE, &bc); + CHECK_STRING_TRANS(fn); + proto_tree_add_string(tree, hf_smb_dir_name, tvb, offset, fn_len, + fn); + COUNT_BYTES_TRANS(fn_len); + + col_append_fstr(pinfo->cinfo, COL_INFO, ", Dir: %s", + format_text(wmem_packet_scope(), (const guchar*)fn, strlen(fn))); + break; + case 0x000e: /*TRANS2_SESSION_SETUP*/ + /* XXX unknown structure*/ + break; + case 0x0010: /*TRANS2_GET_DFS_REFERRAL*/ + offset = dissect_get_dfs_request_data(tvb, pinfo, tree, offset, &bc, si->unicode); + break; + case 0x0011: /*TRANS2_REPORT_DFS_INCONSISTENCY*/ + /* file name */ + fn = get_unicode_or_ascii_string(tvb, &offset, si->unicode, &fn_len, FALSE, FALSE, &bc); + CHECK_STRING_TRANS(fn); + proto_tree_add_string(tree, hf_smb_file_name, tvb, offset, fn_len, + fn); + COUNT_BYTES_TRANS(fn_len); + + col_append_fstr(pinfo->cinfo, COL_INFO, ", File: %s", + format_text(wmem_packet_scope(), (const guchar*)fn, strlen(fn))); + break; + } + + /* ooops there were data we didn't know how to process */ + if (bc != 0) { + proto_tree_add_item(tree, hf_smb_unknown, tvb, offset, bc, ENC_NA); + offset += bc; + } + + return offset; +} + +/* + * XXX - just use "dissect_connect_flags()" here? + */ +static guint16 +dissect_transaction_flags(tvbuff_t *tvb, proto_tree *parent_tree, int offset) +{ + guint16 mask; + static int * const flags[] = { + &hf_smb_transaction_flags_owt, + &hf_smb_transaction_flags_dtid, + NULL + }; + + mask = tvb_get_letohs(tvb, offset); + proto_tree_add_bitmask(parent_tree, tvb, offset, hf_smb_transaction_flags, ett_smb_transaction_flags, flags, ENC_LITTLE_ENDIAN); + + return mask; +} + + +static int +dissect_get_dfs_flags(tvbuff_t *tvb, proto_tree *parent_tree, int offset) +{ + static int * const flags[] = { + &hf_smb_get_dfs_server_hold_storage, + &hf_smb_get_dfs_fielding, + NULL + }; + + proto_tree_add_bitmask(parent_tree, tvb, offset, hf_smb_get_dfs_flags, ett_smb_get_dfs_flags, flags, ENC_LITTLE_ENDIAN); + + offset += 2; + return offset; +} + +static int +dissect_dfs_referral_flags(tvbuff_t *tvb, proto_tree *parent_tree, int offset) +{ + static int * const flags[] = { + &hf_smb_dfs_referral_flags_name_list_referral, + &hf_smb_dfs_referral_flags_target_set_boundary, + NULL + }; + + proto_tree_add_bitmask(parent_tree, tvb, offset, hf_smb_dfs_referral_flags, ett_smb_dfs_referral_flags, flags, ENC_LITTLE_ENDIAN); + offset += 2; + + return offset; +} + + +/* dfs inconsistency data (4.4.2) +*/ +static int +dissect_dfs_inconsistency_data(tvbuff_t *tvb, packet_info *pinfo _U_, + proto_tree *tree, int offset, guint16 *bcp, smb_info_t *si) +{ + int fn_len; + const char *fn; + + DISSECTOR_ASSERT(si); + + /*XXX shouldn this data hold version and size? unclear from doc*/ + /* referral version */ + CHECK_BYTE_COUNT_TRANS_SUBR(2); + proto_tree_add_item(tree, hf_smb_dfs_referral_version, tvb, offset, 2, ENC_LITTLE_ENDIAN); + COUNT_BYTES_TRANS_SUBR(2); + + /* referral size */ + CHECK_BYTE_COUNT_TRANS_SUBR(2); + proto_tree_add_item(tree, hf_smb_dfs_referral_size, tvb, offset, 2, ENC_LITTLE_ENDIAN); + COUNT_BYTES_TRANS_SUBR(2); + + /* referral server type */ + CHECK_BYTE_COUNT_TRANS_SUBR(2); + proto_tree_add_item(tree, hf_smb_dfs_referral_server_type, tvb, offset, 2, ENC_LITTLE_ENDIAN); + COUNT_BYTES_TRANS_SUBR(2); + + /* referral flags */ + CHECK_BYTE_COUNT_TRANS_SUBR(2); + offset = dissect_dfs_referral_flags(tvb, tree, offset); + *bcp -= 2; + + /* node name */ + fn = get_unicode_or_ascii_string(tvb, &offset, si->unicode, &fn_len, FALSE, FALSE, bcp); + CHECK_STRING_TRANS_SUBR(fn); + proto_tree_add_string(tree, hf_smb_dfs_referral_node, tvb, offset, fn_len, + fn); + COUNT_BYTES_TRANS_SUBR(fn_len); + + return offset; +} + +static int +dissect_dfs_referral_strings(tvbuff_t *tvb, proto_tree *tree, int hfindex, + int nstring, int stroffset, int oldoffset, int offset, + guint16 bc, gboolean unicode, int *end) +{ + int istring; + const char *str; + int str_len; /* string length including the terminating NULL. */ + + if (stroffset <= oldoffset) + return oldoffset; + + bc -= (stroffset - offset); + for (istring = 0; istring < nstring; istring++) { + if ((gint16)bc > 0) { + str = get_unicode_or_ascii_string(tvb, &stroffset, unicode, &str_len, FALSE, FALSE, &bc); + CHECK_STRING_TRANS_SUBR(str); + proto_tree_add_string(tree, hfindex, tvb, stroffset, str_len, str); + stroffset += str_len; + bc -= str_len; + if (end && (*end < stroffset)) + *end = stroffset; + } + } + + return offset; +} + + +static int +dissect_dfs_referral_string(tvbuff_t *tvb, proto_tree *tree, int hfindex, + int stroffset, int oldoffset, int offset, + guint16 bc, gboolean unicode, int *end) +{ + return dissect_dfs_referral_strings(tvb, tree, hfindex, + 1, stroffset, oldoffset, offset, + bc, unicode, end); +} + +static int +dissect_dfs_referral_entry_v2(tvbuff_t *tvb, proto_tree *tree, int oldoffset, int offset, + guint16 refflags _U_, guint16 *bcp, gboolean unicode, int *ucstring_end) +{ + + guint16 pathoffset; + guint16 altpathoffset; + guint16 nodeoffset; + + /* proximity */ + CHECK_BYTE_COUNT_TRANS_SUBR(4); + proto_tree_add_item(tree, hf_smb_dfs_referral_proximity, tvb, offset, 4, ENC_LITTLE_ENDIAN); + COUNT_BYTES_TRANS_SUBR(4); + + /* ttl */ + CHECK_BYTE_COUNT_TRANS_SUBR(4); + proto_tree_add_item(tree, hf_smb_dfs_referral_ttl, tvb, offset, 4, ENC_LITTLE_ENDIAN); + COUNT_BYTES_TRANS_SUBR(4); + + /* path offset */ + CHECK_BYTE_COUNT_TRANS_SUBR(2); + pathoffset = tvb_get_letohs(tvb, offset); + proto_tree_add_uint(tree, hf_smb_dfs_referral_path_offset, tvb, offset, 2, pathoffset); + COUNT_BYTES_TRANS_SUBR(2); + + /* alt path offset */ + CHECK_BYTE_COUNT_TRANS_SUBR(2); + altpathoffset = tvb_get_letohs(tvb, offset); + proto_tree_add_uint(tree, hf_smb_dfs_referral_alt_path_offset, tvb, offset, 2, altpathoffset); + COUNT_BYTES_TRANS_SUBR(2); + + /* node offset */ + CHECK_BYTE_COUNT_TRANS_SUBR(2); + nodeoffset = tvb_get_letohs(tvb, offset); + proto_tree_add_uint(tree, hf_smb_dfs_referral_node_offset, tvb, offset, 2, nodeoffset); + COUNT_BYTES_TRANS_SUBR(2); + + /* path */ + if (pathoffset) { + dissect_dfs_referral_string(tvb, tree, hf_smb_dfs_referral_path, + pathoffset+oldoffset, oldoffset, offset, + *bcp, unicode, ucstring_end); + } + + /* alt path */ + if (altpathoffset) { + dissect_dfs_referral_string(tvb, tree, hf_smb_dfs_referral_alt_path, + altpathoffset+oldoffset, oldoffset, offset, + *bcp, unicode, ucstring_end); + } + + /* node */ + if (nodeoffset) { + dissect_dfs_referral_string(tvb, tree, hf_smb_dfs_referral_node, + nodeoffset+oldoffset, oldoffset, offset, + *bcp, unicode, ucstring_end); + } + + return offset; + +} + + +static int +dissect_dfs_referral_entry_v3(tvbuff_t *tvb, proto_tree *tree, int oldoffset, int offset, + guint16 refflags, guint16 *bcp, gboolean unicode, int *ucstring_end) +{ + guint16 domoffset; + guint16 nexpnames; + guint16 expoffset; + guint16 pathoffset; + guint16 altpathoffset; + guint16 nodeoffset; + + /* ttl */ + CHECK_BYTE_COUNT_TRANS_SUBR(4); + proto_tree_add_item(tree, hf_smb_dfs_referral_ttl, tvb, offset, 4, ENC_LITTLE_ENDIAN); + COUNT_BYTES_TRANS_SUBR(4); + + if (refflags & REFENT_FLAGS_NAME_LIST_REFERRAL) { + /* domain name offset */ + CHECK_BYTE_COUNT_TRANS_SUBR(2); + domoffset = tvb_get_letohs(tvb, offset); + proto_tree_add_uint(tree, hf_smb_dfs_referral_domain_offset, tvb, offset, 2, domoffset); + COUNT_BYTES_TRANS_SUBR(2); + + /* number of expanded names*/ + CHECK_BYTE_COUNT_TRANS_SUBR(2); + nexpnames = tvb_get_letohs(tvb, offset); + proto_tree_add_uint(tree, hf_smb_dfs_referral_number_of_expnames, tvb, offset, 2, nexpnames); + COUNT_BYTES_TRANS_SUBR(2); + + /* expanded names offset */ + CHECK_BYTE_COUNT_TRANS_SUBR(2); + expoffset = tvb_get_letohs(tvb, offset); + proto_tree_add_uint(tree, hf_smb_dfs_referral_expnames_offset, tvb, offset, 2, expoffset); + COUNT_BYTES_TRANS_SUBR(2); + + /* padding: zero or 16 bytes, which should be ignored by clients. + * we ignore them too. + */ + + /* domain name */ + if (domoffset) { + dissect_dfs_referral_string(tvb, tree, hf_smb_dfs_referral_domain_name, + domoffset+oldoffset, oldoffset, offset, + *bcp, unicode, ucstring_end); + } + /* expanded names */ + if (expoffset) { + proto_tree *exptree; + + exptree = proto_tree_add_subtree(tree, tvb, offset, *bcp, ett_smb_dfs_referral_expnames, NULL, "Expanded Names"); + + dissect_dfs_referral_strings(tvb, exptree, hf_smb_dfs_referral_expname, + nexpnames, expoffset+oldoffset, oldoffset, offset, + *bcp, unicode, ucstring_end); + } + } else { + /* path offset */ + CHECK_BYTE_COUNT_TRANS_SUBR(2); + pathoffset = tvb_get_letohs(tvb, offset); + proto_tree_add_uint(tree, hf_smb_dfs_referral_path_offset, tvb, offset, 2, pathoffset); + COUNT_BYTES_TRANS_SUBR(2); + + /* alt path offset */ + CHECK_BYTE_COUNT_TRANS_SUBR(2); + altpathoffset = tvb_get_letohs(tvb, offset); + proto_tree_add_uint(tree, hf_smb_dfs_referral_alt_path_offset, tvb, offset, 2, altpathoffset); + COUNT_BYTES_TRANS_SUBR(2); + + /* node offset */ + CHECK_BYTE_COUNT_TRANS_SUBR(2); + nodeoffset = tvb_get_letohs(tvb, offset); + proto_tree_add_uint(tree, hf_smb_dfs_referral_node_offset, tvb, offset, 2, nodeoffset); + COUNT_BYTES_TRANS_SUBR(2); + + /* service site guid */ + CHECK_BYTE_COUNT_TRANS_SUBR(16); + proto_tree_add_item(tree, hf_smb_dfs_referral_server_guid, tvb, offset, 16, ENC_NA); + COUNT_BYTES_TRANS_SUBR(16); + + /* path */ + if (pathoffset) { + dissect_dfs_referral_string(tvb, tree, hf_smb_dfs_referral_path, + pathoffset+oldoffset, oldoffset, offset, + *bcp, unicode, ucstring_end); + } + + /* alt path */ + if (altpathoffset) { + dissect_dfs_referral_string(tvb, tree, hf_smb_dfs_referral_alt_path, + altpathoffset+oldoffset, oldoffset, offset, + *bcp, unicode, ucstring_end); + } + + /* node */ + if (nodeoffset) { + dissect_dfs_referral_string(tvb, tree, hf_smb_dfs_referral_node, + nodeoffset+oldoffset, oldoffset, offset, + *bcp, unicode, ucstring_end); + } + } + + return offset; + +} + +/* get dfs referral data (4.4.1) +*/ +int +dissect_get_dfs_referral_data(tvbuff_t *tvb, packet_info *pinfo _U_, + proto_tree *tree, int offset, guint16 *bcp, gboolean unicode) +{ + guint16 numref; + guint16 refsize; + guint16 refflags; + int fn_len; + const char *fn; + int unklen; + int ucstring_end; + int ucstring_len; + + /* path consumed */ + CHECK_BYTE_COUNT_TRANS_SUBR(2); + proto_tree_add_item(tree, hf_smb_dfs_path_consumed, tvb, offset, 2, ENC_LITTLE_ENDIAN); + COUNT_BYTES_TRANS_SUBR(2); + + /* num referrals */ + CHECK_BYTE_COUNT_TRANS_SUBR(2); + numref = tvb_get_letohs(tvb, offset); + proto_tree_add_uint(tree, hf_smb_dfs_num_referrals, tvb, offset, 2, numref); + COUNT_BYTES_TRANS_SUBR(2); + + /* get dfs flags */ + CHECK_BYTE_COUNT_TRANS_SUBR(2); + offset = dissect_get_dfs_flags(tvb, tree, offset); + *bcp -= 2; + + /* XXX - in at least one capture there appears to be 2 bytes + of stuff after the Dfs flags, perhaps so that the header + in front of the referral list is a multiple of 4 bytes long. */ + CHECK_BYTE_COUNT_TRANS_SUBR(2); + proto_tree_add_item(tree, hf_smb_padding, tvb, offset, 2, ENC_NA); + COUNT_BYTES_TRANS_SUBR(2); + + /* if there are any referrals */ + if (numref) { + proto_item *ref_item; + proto_tree *ref_tree; + int old_offset = offset; + + ref_tree = proto_tree_add_subtree(tree, + tvb, offset, *bcp, ett_smb_dfs_referrals, &ref_item, "Referrals"); + ucstring_end = -1; + + while (numref--) { + proto_item *ri; + proto_tree *rt; + int old_offset_2 = offset; + guint16 version; + + rt = proto_tree_add_subtree(ref_tree, + tvb, offset, *bcp, ett_smb_dfs_referral, &ri, "Referral"); + + /* referral version */ + CHECK_BYTE_COUNT_TRANS_SUBR(2); + version = tvb_get_letohs(tvb, offset); + proto_tree_add_uint(rt, hf_smb_dfs_referral_version, + tvb, offset, 2, version); + COUNT_BYTES_TRANS_SUBR(2); + + /* referral size */ + CHECK_BYTE_COUNT_TRANS_SUBR(2); + refsize = tvb_get_letohs(tvb, offset); + proto_tree_add_uint(rt, hf_smb_dfs_referral_size, tvb, offset, 2, refsize); + COUNT_BYTES_TRANS_SUBR(2); + + /* referral server type */ + CHECK_BYTE_COUNT_TRANS_SUBR(2); + proto_tree_add_item(rt, hf_smb_dfs_referral_server_type, tvb, offset, 2, ENC_LITTLE_ENDIAN); + COUNT_BYTES_TRANS_SUBR(2); + + /* referral flags */ + CHECK_BYTE_COUNT_TRANS_SUBR(2); + refflags = tvb_get_letohs(tvb, offset); + offset = dissect_dfs_referral_flags(tvb, rt, offset); + *bcp -= 2; + + switch(version) { + + case 1: + /* node name */ + fn = get_unicode_or_ascii_string(tvb, &offset, unicode, &fn_len, FALSE, FALSE, bcp); + CHECK_STRING_TRANS_SUBR(fn); + proto_tree_add_string(rt, hf_smb_dfs_referral_node, tvb, offset, fn_len, + fn); + COUNT_BYTES_TRANS_SUBR(fn_len); + break; + + case 2: + offset = dissect_dfs_referral_entry_v2(tvb, rt, old_offset_2, offset, + refflags, bcp, unicode, &ucstring_end); + break; + case 3: + offset = dissect_dfs_referral_entry_v3(tvb, rt, old_offset_2, offset, + refflags, bcp, unicode, &ucstring_end); + break; + case 4: + /* V4 is extactly same as V3, except the version number and + * one more ReferralEntryFlags */ + offset = dissect_dfs_referral_entry_v3(tvb, rt, old_offset_2, offset, + refflags, bcp, unicode, &ucstring_end); + break; + } + + /* + * Show anything beyond the length of the referral + * as unknown data. + */ + unklen = (old_offset_2 + refsize) - offset; + if (unklen < 0) { + /* + * XXX - the length is bogus. + */ + unklen = 0; + } + if (unklen != 0) { + CHECK_BYTE_COUNT_TRANS_SUBR(unklen); + proto_tree_add_item(rt, hf_smb_unknown, tvb, + offset, unklen, ENC_NA); + COUNT_BYTES_TRANS_SUBR(unklen); + } + + proto_item_set_len(ri, offset-old_offset_2); + } + + /* + * Treat the offset past the end of the last Unicode + * string after the referrals (if any) as the last + * offset. + */ + if (ucstring_end > offset) { + ucstring_len = ucstring_end - offset; + if (*bcp < ucstring_len) + ucstring_len = *bcp; + offset += ucstring_len; + *bcp -= ucstring_len; + } + proto_item_set_len(ref_item, offset-old_offset); + } + + return offset; +} + +/* This dissects the standard four 8-byte Windows timestamps ... + */ +static int +dissect_smb_standard_8byte_timestamps(tvbuff_t *tvb, + packet_info *pinfo _U_, proto_tree *tree, + int offset, guint16 *bcp, gboolean *trunc) +{ + /* create time */ + CHECK_BYTE_COUNT_SUBR(8); + offset = dissect_nt_64bit_time(tvb, tree, offset, hf_smb_create_time); + *bcp -= 8; + + /* access time */ + CHECK_BYTE_COUNT_SUBR(8); + offset = dissect_nt_64bit_time(tvb, tree, offset, hf_smb_access_time); + *bcp -= 8; + + /* last write time */ + CHECK_BYTE_COUNT_SUBR(8); + offset = dissect_nt_64bit_time(tvb, tree, offset, + hf_smb_last_write_time); + *bcp -= 8; + + /* last change time */ + CHECK_BYTE_COUNT_SUBR(8); + offset = dissect_nt_64bit_time(tvb, tree, offset, hf_smb_change_time); + *bcp -= 8; + + *trunc = FALSE; + return offset; +} + +/* this dissects the SMB_INFO_STANDARD + as described in 4.2.16.1 of the CIFS 1.0 specification + or as described in 2.2.8.3.1 of the MS-CIFS specification for query + section 2.2.8.4.1 of the MS-CIFS specification describes it for set; + it says that everything past the last write time is "reserved", + presumably meaning that you can fetch it but not set it + for now we just use it for both query and set +*/ +static int +dissect_qsfi_SMB_INFO_STANDARD(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, + int offset, guint16 *bcp, gboolean *trunc) +{ + /* create time */ + CHECK_BYTE_COUNT_SUBR(4); + offset = dissect_smb_datetime(tvb, tree, offset, + hf_smb_create_time, hf_smb_create_dos_date, hf_smb_create_dos_time, + FALSE); + *bcp -= 4; + + /* access time */ + CHECK_BYTE_COUNT_SUBR(4); + offset = dissect_smb_datetime(tvb, tree, offset, + hf_smb_access_time, hf_smb_access_dos_date, hf_smb_access_dos_time, + FALSE); + *bcp -= 4; + + /* last write time */ + CHECK_BYTE_COUNT_SUBR(4); + offset = dissect_smb_datetime(tvb, tree, offset, + hf_smb_last_write_time, hf_smb_last_write_dos_date, hf_smb_last_write_dos_time, + FALSE); + *bcp -= 4; + + /* data size */ + CHECK_BYTE_COUNT_SUBR(4); + proto_tree_add_item(tree, hf_smb_data_size, tvb, offset, 4, ENC_LITTLE_ENDIAN); + COUNT_BYTES_SUBR(4); + + /* allocation size */ + CHECK_BYTE_COUNT_SUBR(4); + proto_tree_add_item(tree, hf_smb_alloc_size, tvb, offset, 4, ENC_LITTLE_ENDIAN); + COUNT_BYTES_SUBR(4); + + /* File Attributes */ + CHECK_BYTE_COUNT_SUBR(2); + offset = dissect_file_attributes(tvb, tree, offset); + *bcp -= 2; + + /* + * The MS-CIFS spec says this doesn't have an EA length field; + * the SNIA CIFS spec says it does, as does the 1996 + * "Microsoft Networks SMB FILE SHARING PROTOCOL Document + * Version 6.0p" document. + * + * Some older SMB documents point to the documentation + * for the OS/2 DosQFileInfo() API; the page at + * + * http://cyberkinetica.homeunix.net/os2tk45/prcp/111_L2_DosQFileInfo.html + * + * says that, for level 1 (SMB_INFO_STANDARD), there is no EA + * length - that's just for level 2 (SMB_INFO_QUERY_EA_SIZE). + * + * I've seen captures with it and without it; given the mixed + * messages sent by different documents, this is not surprising. + * + * We display it if it's there; we don't set *trunc if it's + * not. + * + * Note: in FIND_FIRST2/FIND_NEXT2, the EA length is *not* + * present. + */ + if (*bcp != 0) { + CHECK_BYTE_COUNT_SUBR(4); + proto_tree_add_item(tree, hf_smb_ea_list_length, tvb, offset, + 4, ENC_LITTLE_ENDIAN); + COUNT_BYTES_SUBR(4); + } + + *trunc = FALSE; + return offset; +} + +/* this dissects the SMB_INFO_QUERY_EA_SIZE + as described in 4.2.16.1 of the CIFS 1.0 specification + and as described in 2.2.8.3.2 of the MS-CIFS specification +*/ +static int +dissect_qfi_SMB_INFO_QUERY_EA_SIZE(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, + int offset, guint16 *bcp, gboolean *trunc) +{ + /* create time */ + CHECK_BYTE_COUNT_SUBR(4); + offset = dissect_smb_datetime(tvb, tree, offset, + hf_smb_create_time, hf_smb_create_dos_date, hf_smb_create_dos_time, + FALSE); + *bcp -= 4; + + /* access time */ + CHECK_BYTE_COUNT_SUBR(4); + offset = dissect_smb_datetime(tvb, tree, offset, + hf_smb_access_time, hf_smb_access_dos_date, hf_smb_access_dos_time, + FALSE); + *bcp -= 4; + + /* last write time */ + CHECK_BYTE_COUNT_SUBR(4); + offset = dissect_smb_datetime(tvb, tree, offset, + hf_smb_last_write_time, hf_smb_last_write_dos_date, hf_smb_last_write_dos_time, + FALSE); + *bcp -= 4; + + /* data size */ + CHECK_BYTE_COUNT_SUBR(4); + proto_tree_add_item(tree, hf_smb_data_size, tvb, offset, 4, ENC_LITTLE_ENDIAN); + COUNT_BYTES_SUBR(4); + + /* allocation size */ + CHECK_BYTE_COUNT_SUBR(4); + proto_tree_add_item(tree, hf_smb_alloc_size, tvb, offset, 4, ENC_LITTLE_ENDIAN); + COUNT_BYTES_SUBR(4); + + /* File Attributes */ + CHECK_BYTE_COUNT_SUBR(2); + offset = dissect_file_attributes(tvb, tree, offset); + *bcp -= 2; + + /* ea length */ + CHECK_BYTE_COUNT_SUBR(4); + proto_tree_add_item(tree, hf_smb_ea_list_length, tvb, offset, 4, ENC_LITTLE_ENDIAN); + COUNT_BYTES_SUBR(4); + + *trunc = FALSE; + return offset; +} + +/* this dissects the SMB_INFO_QUERY_EAS_FROM_LIST and SMB_INFO_QUERY_ALL_EAS + as described in 4.2.16.2 +*/ +static int +dissect_4_2_16_2(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, + int offset, guint16 *bcp, gboolean *trunc) +{ + guint8 name_len; + guint16 data_len; + /* EA size */ + + CHECK_BYTE_COUNT_SUBR(4); + proto_tree_add_item(tree, hf_smb_ea_list_length, tvb, offset, 4, ENC_LITTLE_ENDIAN); + COUNT_BYTES_SUBR(4); + + while (*bcp > 0) { + proto_item *item; + proto_tree *subtree; + char *display_string; + int start_offset = offset; + + subtree = proto_tree_add_subtree( + tree, tvb, offset, 0, ett_smb_ea, &item, "Extended Attribute"); + + /* EA flags */ + + CHECK_BYTE_COUNT_SUBR(1); + proto_tree_add_item( + subtree, hf_smb_ea_flags, tvb, offset, 1, ENC_LITTLE_ENDIAN); + COUNT_BYTES_SUBR(1); + + /* EA name length */ + + name_len = tvb_get_guint8(tvb, offset); + + CHECK_BYTE_COUNT_SUBR(1); + proto_tree_add_item( + subtree, hf_smb_ea_name_length, tvb, offset, 1, ENC_LITTLE_ENDIAN); + COUNT_BYTES_SUBR(1); + + /* EA data length */ + + data_len = tvb_get_letohs(tvb, offset); + + CHECK_BYTE_COUNT_SUBR(2); + proto_tree_add_item( + subtree, hf_smb_ea_data_length, tvb, offset, 2, ENC_LITTLE_ENDIAN); + COUNT_BYTES_SUBR(2); + + /* EA name */ + + CHECK_BYTE_COUNT_SUBR(name_len + 1); + proto_tree_add_item_ret_display_string( + subtree, hf_smb_ea_name, tvb, offset, name_len + 1, + ENC_ASCII|ENC_NA, + wmem_packet_scope(), &display_string); + proto_item_append_text(item, ": %s", display_string); + COUNT_BYTES_SUBR(name_len + 1); + + /* EA data */ + + CHECK_BYTE_COUNT_SUBR(data_len); + proto_tree_add_item( + subtree, hf_smb_ea_data, tvb, offset, data_len, ENC_NA); + COUNT_BYTES_SUBR(data_len); + + proto_item_set_len(item, offset - start_offset); + } + + *trunc = FALSE; + return offset; +} + +/* this dissects the SMB_INFO_IS_NAME_VALID + as described in 4.2.16.3 +*/ +static int +dissect_4_2_16_3(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, + int offset, guint16 *bcp, gboolean *trunc, smb_info_t *si) +{ + int fn_len; + const char *fn; + + DISSECTOR_ASSERT(si); + + /* file name */ + fn = get_unicode_or_ascii_string(tvb, &offset, si->unicode, &fn_len, FALSE, FALSE, bcp); + CHECK_STRING_SUBR(fn); + proto_tree_add_string(tree, hf_smb_file_name, tvb, offset, fn_len, + fn); + COUNT_BYTES_SUBR(fn_len); + + *trunc = FALSE; + return offset; +} + +/* this dissects the SMB_QUERY_FILE_BASIC_INFO + as described in 4.2.16.4 +*/ +static int +dissect_4_2_16_4(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, + int offset, guint16 *bcp, gboolean *trunc) +{ + + offset = dissect_smb_standard_8byte_timestamps(tvb, pinfo, tree, offset, bcp, trunc); + if (*trunc) { + return offset; + } + + /* File Attributes */ + CHECK_BYTE_COUNT_SUBR(4); + offset = dissect_file_ext_attr(tvb, tree, offset); + *bcp -= 4; + + *trunc = FALSE; + return offset; +} + +/* this dissects the SMB_QUERY_FILE_STANDARD_INFO + as described in 4.2.16.5 of the SNIA CIFS spec + and section 2.2.8.3.7 of the MS-CIFS spec +*/ +int +dissect_qfi_SMB_FILE_STANDARD_INFO(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, + int offset, guint16 *bcp, gboolean *trunc) +{ + /* allocation size */ + CHECK_BYTE_COUNT_SUBR(8); + proto_tree_add_item(tree, hf_smb_alloc_size64, tvb, offset, 8, ENC_LITTLE_ENDIAN); + COUNT_BYTES_SUBR(8); + + /* end of file */ + CHECK_BYTE_COUNT_SUBR(8); + proto_tree_add_item(tree, hf_smb_end_of_file, tvb, offset, 8, ENC_LITTLE_ENDIAN); + COUNT_BYTES_SUBR(8); + + /* number of links */ + CHECK_BYTE_COUNT_SUBR(4); + proto_tree_add_item(tree, hf_smb_number_of_links, tvb, offset, 4, ENC_LITTLE_ENDIAN); + COUNT_BYTES_SUBR(4); + + /* delete pending */ + CHECK_BYTE_COUNT_SUBR(1); + proto_tree_add_item(tree, hf_smb_delete_pending, tvb, offset, 1, ENC_LITTLE_ENDIAN); + COUNT_BYTES_SUBR(1); + + /* is directory */ + CHECK_BYTE_COUNT_SUBR(1); + proto_tree_add_item(tree, hf_smb_is_directory, tvb, offset, 1, ENC_LITTLE_ENDIAN); + COUNT_BYTES_SUBR(1); + + *trunc = FALSE; + return offset; +} + +/* this dissects the SMB_QUERY_FILE_INTERNAL_INFO +*/ +int +dissect_qfi_SMB_FILE_INTERNAL_INFO(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, + int offset, guint16 *bcp, gboolean *trunc) +{ + /* file id */ + CHECK_BYTE_COUNT_SUBR(8); + proto_tree_add_item(tree, hf_smb_index_number, tvb, offset, 8, ENC_LITTLE_ENDIAN); + COUNT_BYTES_SUBR(8); + + *trunc = FALSE; + return offset; +} + +/* this dissects the SMB_QUERY_FILE_POSITION_INFO +*/ +int +dissect_qsfi_SMB_FILE_POSITION_INFO(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, + int offset, guint16 *bcp, gboolean *trunc) +{ + /* file position */ + CHECK_BYTE_COUNT_SUBR(8); + proto_tree_add_item(tree, hf_smb_position, tvb, offset, 8, ENC_LITTLE_ENDIAN); + COUNT_BYTES_SUBR(8); + + *trunc = FALSE; + return offset; +} + +/* this dissects the SMB_QUERY_FILE_MODE_INFO +*/ +int +dissect_qsfi_SMB_FILE_MODE_INFO(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, + int offset, guint16 *bcp, gboolean *trunc) +{ + /* mode */ + CHECK_BYTE_COUNT_SUBR(4); + proto_tree_add_item(tree, hf_smb_mode, tvb, offset, 4, ENC_LITTLE_ENDIAN); + COUNT_BYTES_SUBR(4); + + *trunc = FALSE; + return offset; +} + +/* this dissects the SMB_QUERY_FILE_ALIGNMENT_INFO +*/ +int +dissect_qfi_SMB_FILE_ALIGNMENT_INFO(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, + int offset, guint16 *bcp, gboolean *trunc) +{ + /* alignment */ + CHECK_BYTE_COUNT_SUBR(4); + proto_tree_add_item(tree, hf_smb_t2_alignment, tvb, offset, 4, ENC_LITTLE_ENDIAN); + COUNT_BYTES_SUBR(4); + + *trunc = FALSE; + return offset; +} + +/* this dissects the SMB_QUERY_FILE_EA_INFO + as described in 4.2.16.6 of the SNIA CIFS spec + and 2.2.8.3.8 of the MS-CIFS spec +*/ +int +dissect_qfi_SMB_FILE_EA_INFO(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, + int offset, guint16 *bcp, gboolean *trunc) +{ + /* ea length */ + CHECK_BYTE_COUNT_SUBR(4); + proto_tree_add_item(tree, hf_smb_ea_list_length, tvb, offset, 4, ENC_LITTLE_ENDIAN); + COUNT_BYTES_SUBR(4); + + *trunc = FALSE; + return offset; +} + +/* this dissects the SMB_FILE_ALLOCATION_INFO + as described in 4.2.19.3 in the SNIA CIFS spec + and the SMB_SET_FILE_ALLOCATION_INFO + as described in 2.2.8.4.5 in the MS-CIFS spec for set (MS-CIFS doesn't + say it can be queried) +*/ +int +dissect_qsfi_SMB_FILE_ALLOCATION_INFO(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, + int offset, guint16 *bcp, gboolean *trunc) +{ + /* allocation size */ + CHECK_BYTE_COUNT_SUBR(8); + proto_tree_add_item(tree, hf_smb_alloc_size64, tvb, offset, 8, ENC_LITTLE_ENDIAN); + COUNT_BYTES_SUBR(8); + + *trunc = FALSE; + return offset; +} + +/* this dissects the SMB_FILE_ENDOFFILE_INFO + as described in 4.2.19.4 in the SNIA CIFS spec + and the SMB_SET_FILE_END_OF_FILE_INFO + as described in 2.2.8.4.6 in the MS-CIFS spec for set (MS-CIFS doesn't + say it can be queried) +*/ +int +dissect_qsfi_SMB_FILE_ENDOFFILE_INFO(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, + int offset, guint16 *bcp, gboolean *trunc) +{ + /* offset of end of file */ + CHECK_BYTE_COUNT_SUBR(8); + proto_tree_add_item(tree, hf_smb_end_of_file, tvb, offset, 8, ENC_LITTLE_ENDIAN); + COUNT_BYTES_SUBR(8); + + *trunc = FALSE; + return offset; +} + +/* this dissects the SMB_QUERY_FILE_NAME_INFO + as described in 4.2.16.7 of the SNIA CIFS spec + and in 2.2.8.3.9 of the MS-CIFS spec + this is the same as SMB_QUERY_FILE_ALT_NAME_INFO + as described in 4.2.16.9 of the SNIA CIFS spec + and 2.2.8.3.11 of the MS-CIFS spec + although the latter two are used to fetch the 8.3 name + rather than the long name + + https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-fscc/4718fc40-e539-4014-8e33-b675af74e3e1 + + FileNormalizedNameInformation: + https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-fscc/20bcadba-808c-4880-b757-4af93e41edf6 +*/ +int +dissect_qfi_SMB_FILE_NAME_INFO(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, + int offset, guint16 *bcp, gboolean *trunc, gboolean unicode) +{ + int fn_len; + const char *fn; + + /* file name len */ + CHECK_BYTE_COUNT_SUBR(4); + proto_tree_add_item_ret_uint(tree, hf_smb_file_name_len, tvb, offset, 4, ENC_LITTLE_ENDIAN, &fn_len); + COUNT_BYTES_SUBR(4); + + /* file name */ + fn = get_unicode_or_ascii_string(tvb, &offset, unicode, &fn_len, TRUE, TRUE, bcp); + + CHECK_STRING_SUBR(fn); + + proto_tree_add_string(tree, hf_smb_file_name, tvb, offset, fn_len, + fn); + COUNT_BYTES_SUBR(fn_len); + + *trunc = FALSE; + return offset; +} + +/* this dissects the SMB_QUERY_FILE_ALL_INFO + as described in 2.2.8.3.8 of the MS-CIFS spec + but not as described in 4.2.16.8 since SNIA spec is wrong +*/ +static int +dissect_qfi_SMB_FILE_ALL_INFO(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, + int offset, guint16 *bcp, gboolean *trunc, smb_info_t *si) +{ + guint32 fn_len; + const char *fn; + + DISSECTOR_ASSERT(si); + + offset = dissect_smb_standard_8byte_timestamps(tvb, pinfo, tree, offset, bcp, trunc); + if (*trunc) { + return offset; + } + + /* File Attributes */ + CHECK_BYTE_COUNT_SUBR(4); + offset = dissect_file_ext_attr(tvb, tree, offset); + *bcp -= 4; + + /* 4 pad bytes */ + offset += 4; + *bcp -= 4; + + /* allocation size */ + CHECK_BYTE_COUNT_SUBR(8); + proto_tree_add_item(tree, hf_smb_alloc_size64, tvb, offset, 8, ENC_LITTLE_ENDIAN); + COUNT_BYTES_SUBR(8); + + /* end of file */ + CHECK_BYTE_COUNT_SUBR(8); + proto_tree_add_item(tree, hf_smb_end_of_file, tvb, offset, 8, ENC_LITTLE_ENDIAN); + COUNT_BYTES_SUBR(8); + + /* number of links */ + CHECK_BYTE_COUNT_SUBR(4); + proto_tree_add_item(tree, hf_smb_number_of_links, tvb, offset, 4, ENC_LITTLE_ENDIAN); + COUNT_BYTES_SUBR(4); + + /* delete pending */ + CHECK_BYTE_COUNT_SUBR(1); + proto_tree_add_item(tree, hf_smb_delete_pending, tvb, offset, 1, ENC_LITTLE_ENDIAN); + COUNT_BYTES_SUBR(1); + + /* is directory */ + CHECK_BYTE_COUNT_SUBR(1); + proto_tree_add_item(tree, hf_smb_is_directory, tvb, offset, 1, ENC_LITTLE_ENDIAN); + COUNT_BYTES_SUBR(1); + + /* 2 pad bytes */ + offset += 2; + *bcp -= 2; + + /* ea length */ + CHECK_BYTE_COUNT_SUBR(4); + proto_tree_add_item(tree, hf_smb_ea_list_length, tvb, offset, 4, ENC_LITTLE_ENDIAN); + COUNT_BYTES_SUBR(4); + + /* file name len */ + CHECK_BYTE_COUNT_SUBR(4); + fn_len = (guint32)tvb_get_letohl(tvb, offset); + proto_tree_add_uint(tree, hf_smb_file_name_len, tvb, offset, 4, fn_len); + COUNT_BYTES_SUBR(4); + + + /* file name */ + CHECK_BYTE_COUNT_SUBR(fn_len); + fn = get_unicode_or_ascii_string(tvb, &offset, si->unicode, &fn_len, TRUE, TRUE, bcp); + if (fn != NULL) { + proto_tree_add_string(tree, hf_smb_file_name, tvb, offset, fn_len, + fn); + COUNT_BYTES_SUBR(fn_len); + } + + + if (*trunc) + return offset; + + return offset; +} + +/* this dissects the SMB_QUERY_FILE_STREAM_INFO + as described in 4.2.16.10 of the SNIA CIFS spec + and 2.2.8.3.12 of the MS-CIFS spec +*/ +int +dissect_qfi_SMB_FILE_STREAM_INFO(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *parent_tree, + int offset, guint16 *bcp, gboolean *trunc, int unicode) +{ + proto_item *item; + proto_tree *tree; + int old_offset; + guint32 neo; + int fn_len; + const char *fn; + int padcnt; + + + for (;;) { + old_offset = offset; + + /* next entry offset */ + CHECK_BYTE_COUNT_SUBR(4); + tree = proto_tree_add_subtree(parent_tree, tvb, offset, *bcp, ett_smb_ff2_data, &item, "Stream Info"); + + neo = tvb_get_letohl(tvb, offset); + proto_tree_add_uint(tree, hf_smb_next_entry_offset, tvb, offset, 4, neo); + COUNT_BYTES_SUBR(4); + + /* stream name len */ + CHECK_BYTE_COUNT_SUBR(4); + fn_len = tvb_get_letohl(tvb, offset); + proto_tree_add_uint(tree, hf_smb_t2_stream_name_length, tvb, offset, 4, fn_len); + COUNT_BYTES_SUBR(4); + + /* stream size */ + CHECK_BYTE_COUNT_SUBR(8); + proto_tree_add_item(tree, hf_smb_t2_stream_size, tvb, offset, 8, ENC_LITTLE_ENDIAN); + COUNT_BYTES_SUBR(8); + + /* allocation size */ + CHECK_BYTE_COUNT_SUBR(8); + proto_tree_add_item(tree, hf_smb_alloc_size64, tvb, offset, 8, ENC_LITTLE_ENDIAN); + COUNT_BYTES_SUBR(8); + + /* stream name */ + fn = get_unicode_or_ascii_string(tvb, &offset, unicode, &fn_len, FALSE, TRUE, bcp); + CHECK_STRING_SUBR(fn); + proto_tree_add_string(tree, hf_smb_t2_stream_name, tvb, offset, fn_len, + fn); + COUNT_BYTES_SUBR(fn_len); + + proto_item_append_text(item, ": %s", format_text(wmem_packet_scope(), (const guchar*)fn, strlen(fn))); + proto_item_set_len(item, offset-old_offset); + + 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) { + CHECK_BYTE_COUNT_SUBR(padcnt); + COUNT_BYTES_SUBR(padcnt); + } + } + + *trunc = FALSE; + return offset; +} + +/* this dissects the SMB_QUERY_FILE_COMPRESSION_INFO + as described in 4.2.16.11 of the SNIA CIFS spec + and 2.2.8.3.13 of the MS-CIFS spec +*/ +int +dissect_qfi_SMB_FILE_COMPRESSION_INFO(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, + int offset, guint16 *bcp, gboolean *trunc) +{ + /* compressed file size */ + CHECK_BYTE_COUNT_SUBR(8); + proto_tree_add_item(tree, hf_smb_t2_compressed_file_size, tvb, offset, 8, ENC_LITTLE_ENDIAN); + COUNT_BYTES_SUBR(8); + + /* compression format */ + CHECK_BYTE_COUNT_SUBR(2); + proto_tree_add_item(tree, hf_smb_t2_compressed_format, tvb, offset, 2, ENC_LITTLE_ENDIAN); + COUNT_BYTES_SUBR(2); + + /* compression unit shift */ + CHECK_BYTE_COUNT_SUBR(1); + proto_tree_add_item(tree, hf_smb_t2_compressed_unit_shift, tvb, offset, 1, ENC_LITTLE_ENDIAN); + COUNT_BYTES_SUBR(1); + + /* compression chunk shift */ + CHECK_BYTE_COUNT_SUBR(1); + proto_tree_add_item(tree, hf_smb_t2_compressed_chunk_shift, tvb, offset, 1, ENC_LITTLE_ENDIAN); + COUNT_BYTES_SUBR(1); + + /* compression cluster shift */ + CHECK_BYTE_COUNT_SUBR(1); + proto_tree_add_item(tree, hf_smb_t2_compressed_cluster_shift, tvb, offset, 1, ENC_LITTLE_ENDIAN); + COUNT_BYTES_SUBR(1); + + /* 3 reserved bytes */ + CHECK_BYTE_COUNT_SUBR(3); + proto_tree_add_item(tree, hf_smb_reserved, tvb, offset, 3, ENC_NA); + COUNT_BYTES_SUBR(3); + + *trunc = FALSE; + return offset; +} + +/* 4.2.16.12 - SMB_QUERY_FILE_UNIX_BASIC */ + +static const value_string unix_file_type_vals[] = { + { 0, "File" }, + { 1, "Directory" }, + { 2, "Symbolic link" }, + { 3, "Character device" }, + { 4, "Block device" }, + { 5, "FIFO" }, + { 6, "Socket" }, + { 0, NULL } +}; + +static int +dissect_4_2_16_12(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, + int offset, guint16 *bcp, gboolean *trunc) +{ + /* End of file (file size) */ + CHECK_BYTE_COUNT_SUBR(8); + proto_tree_add_item(tree, hf_smb_unix_file_size, tvb, offset, 8, ENC_LITTLE_ENDIAN); + COUNT_BYTES_SUBR(8); + + /* Number of bytes */ + CHECK_BYTE_COUNT_SUBR(8); + proto_tree_add_item(tree, hf_smb_unix_file_num_bytes, tvb, offset, 8, ENC_LITTLE_ENDIAN); + COUNT_BYTES_SUBR(8); + + /* Last status change */ + CHECK_BYTE_COUNT_SUBR(8); + offset = dissect_nt_64bit_time(tvb, tree, offset, hf_smb_unix_file_last_status); + *bcp -= 8; /* dissect_nt_64bit_time() increments offset */ + + /* Last access time */ + CHECK_BYTE_COUNT_SUBR(8); + offset = dissect_nt_64bit_time(tvb, tree, offset, hf_smb_unix_file_last_access); + *bcp -= 8; + + /* Last modification time */ + CHECK_BYTE_COUNT_SUBR(8); + offset = dissect_nt_64bit_time(tvb, tree, offset, hf_smb_unix_file_last_change); + *bcp -= 8; + + /* File owner uid */ + CHECK_BYTE_COUNT_SUBR(8); + proto_tree_add_item(tree, hf_smb_unix_file_uid, tvb, offset, 8, ENC_LITTLE_ENDIAN); + COUNT_BYTES_SUBR(8); + + /* File group gid */ + CHECK_BYTE_COUNT_SUBR(8); + proto_tree_add_item(tree, hf_smb_unix_file_gid, tvb, offset, 8, ENC_LITTLE_ENDIAN); + COUNT_BYTES_SUBR(8); + + /* File type */ + CHECK_BYTE_COUNT_SUBR(4); + proto_tree_add_item(tree, hf_smb_unix_file_type, tvb, offset, 4, ENC_LITTLE_ENDIAN); + COUNT_BYTES_SUBR(4); + + /* Major device number */ + CHECK_BYTE_COUNT_SUBR(8); + proto_tree_add_item(tree, hf_smb_unix_file_dev_major, tvb, offset, 8, ENC_LITTLE_ENDIAN); + COUNT_BYTES_SUBR(8); + + /* Minor device number */ + CHECK_BYTE_COUNT_SUBR(8); + proto_tree_add_item(tree, hf_smb_unix_file_dev_minor, tvb, offset, 8, ENC_LITTLE_ENDIAN); + COUNT_BYTES_SUBR(8); + + /* Unique id */ + CHECK_BYTE_COUNT_SUBR(8); + proto_tree_add_item(tree, hf_smb_unix_file_unique_id, tvb, offset, 8, ENC_LITTLE_ENDIAN); + COUNT_BYTES_SUBR(8); + + /* Permissions */ + CHECK_BYTE_COUNT_SUBR(8); + proto_tree_add_item(tree, hf_smb_unix_file_permissions, tvb, offset, 8, ENC_LITTLE_ENDIAN); + COUNT_BYTES_SUBR(8); + + /* Nlinks */ + CHECK_BYTE_COUNT_SUBR(8); + proto_tree_add_item(tree, hf_smb_unix_file_nlinks, tvb, offset, 8, ENC_LITTLE_ENDIAN); + COUNT_BYTES_SUBR(8); + + /* Sometimes there is one extra byte in the data field which I + guess could be padding, but we are only using 4 or 8 byte + data types so this is a bit confusing. -tpot */ + + *trunc = FALSE; + return offset; +} + +/* 4.2.16.13 - SMB_QUERY_FILE_UNIX_LINK */ + +static int +dissect_4_2_16_13(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, + int offset, guint16 *bcp, gboolean *trunc, smb_info_t *si) +{ + const char *fn; + int fn_len = 0; + + DISSECTOR_ASSERT(si); + + /* Link destination */ + + fn = get_unicode_or_ascii_string( + tvb, &offset, si->unicode, &fn_len, FALSE, TRUE, bcp); + + CHECK_STRING_SUBR(fn); + proto_tree_add_string( + tree, hf_smb_unix_file_link_dest, tvb, offset, fn_len, fn); + COUNT_BYTES_SUBR(fn_len); + + *trunc = FALSE; + return offset; +} + +/* unix ACL +*/ +static int +dissect_qspi_unix_acl(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, + int offset, guint16 *bcp, gboolean *trunc) +{ + guint16 num_file_aces; + static int * const perm_fields[] = { + &hf_smb_posix_ace_perm_read, + &hf_smb_posix_ace_perm_write, + &hf_smb_posix_ace_perm_execute, + NULL + }; + + /* version */ + CHECK_BYTE_COUNT_SUBR(2); + proto_tree_add_item(tree, hf_smb_posix_acl_version, tvb, offset, 2, ENC_LITTLE_ENDIAN); + COUNT_BYTES_SUBR(2); + + /* num file acls */ + CHECK_BYTE_COUNT_SUBR(2); + num_file_aces = tvb_get_letohs(tvb, offset); + proto_tree_add_item(tree, hf_smb_posix_num_file_aces, tvb, offset, 2, ENC_LITTLE_ENDIAN); + COUNT_BYTES_SUBR(2); + + /* num default acls */ + CHECK_BYTE_COUNT_SUBR(2); + proto_tree_add_item(tree, hf_smb_posix_num_def_aces, tvb, offset, 2, ENC_LITTLE_ENDIAN); + COUNT_BYTES_SUBR(2); + + while (num_file_aces--) { + proto_item *it, *type_item; + proto_tree *tr; + int old_offset = offset; + guint8 ace_type; + + tr = proto_tree_add_subtree(tree, tvb, offset, 0, ett_smb_posix_ace, &it, "ACE"); + + /* ace type */ + CHECK_BYTE_COUNT_SUBR(1); + ace_type = tvb_get_guint8(tvb, offset); + type_item = proto_tree_add_item(tr, hf_smb_posix_ace_type, tvb, offset, 1, ENC_LITTLE_ENDIAN); + COUNT_BYTES_SUBR(1); + + CHECK_BYTE_COUNT_SUBR(1); + proto_tree_add_bitmask(tr, tvb, offset, hf_smb_posix_ace_flags, ett_smb_posix_ace_perms, perm_fields, ENC_BIG_ENDIAN); + COUNT_BYTES_SUBR(1); + + switch(ace_type) { + case POSIX_ACE_TYPE_USER_OBJ: + CHECK_BYTE_COUNT_SUBR(4); + proto_tree_add_item(tr, hf_smb_posix_ace_perm_owner_uid, tvb, offset, 4, ENC_LITTLE_ENDIAN); + COUNT_BYTES_SUBR(4); + + CHECK_BYTE_COUNT_SUBR(4); + /* 4 reserved bytes */ + COUNT_BYTES_SUBR(4); + break; + case POSIX_ACE_TYPE_GROUP_OBJ: + CHECK_BYTE_COUNT_SUBR(4); + proto_tree_add_item(tr, hf_smb_posix_ace_perm_owner_gid, tvb, offset, 4, ENC_LITTLE_ENDIAN); + COUNT_BYTES_SUBR(4); + + CHECK_BYTE_COUNT_SUBR(4); + /* 4 reserved bytes */ + COUNT_BYTES_SUBR(4); + break; + + case POSIX_ACE_TYPE_MASK: + case POSIX_ACE_TYPE_OTHER: + CHECK_BYTE_COUNT_SUBR(8); + /* 8 reserved bytes */ + COUNT_BYTES_SUBR(8); + break; + + case POSIX_ACE_TYPE_USER: + CHECK_BYTE_COUNT_SUBR(4); + proto_tree_add_item(tr, hf_smb_posix_ace_perm_uid, tvb, offset, 4, ENC_LITTLE_ENDIAN); + COUNT_BYTES_SUBR(4); + + CHECK_BYTE_COUNT_SUBR(4); + /* 4 reserved bytes */ + COUNT_BYTES_SUBR(4); + break; + + case POSIX_ACE_TYPE_GROUP: + CHECK_BYTE_COUNT_SUBR(4); + proto_tree_add_item(tr, hf_smb_posix_ace_perm_gid, tvb, offset, 4, ENC_LITTLE_ENDIAN); + COUNT_BYTES_SUBR(4); + + CHECK_BYTE_COUNT_SUBR(4); + /* 4 reserved bytes */ + COUNT_BYTES_SUBR(4); + break; + default: + expert_add_info(pinfo, type_item, &ei_smb_posix_ace_type); + CHECK_BYTE_COUNT_SUBR(8); + /* skip 8 bytes */ + COUNT_BYTES_SUBR(8); + } + + proto_item_set_len(it, offset-old_offset); + } + + *trunc = FALSE; + return offset; +} + +static int +dissect_qspi_unix_xattr(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, + int offset, guint16 *bcp _U_, gboolean *trunc) +{ + proto_tree_add_expert(tree, pinfo, &ei_smb_not_implemented, tvb, offset, 0); + + *trunc = FALSE; + return offset; +} + +static int +dissect_qspi_unix_attr_flags(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, + int offset, guint16 *bcp _U_, gboolean *trunc) +{ + proto_tree_add_expert(tree, pinfo, &ei_smb_not_implemented, tvb, offset, 0); + + *trunc = FALSE; + return offset; +} + +static int +dissect_qpi_unix_permissions(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, + int offset, guint16 *bcp _U_, gboolean *trunc) +{ + proto_tree_add_expert(tree, pinfo, &ei_smb_not_implemented, tvb, offset, 0); + + *trunc = FALSE; + return offset; +} + +static int +dissect_qspi_unix_lock(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, + int offset, guint16 *bcp _U_, gboolean *trunc) +{ + proto_tree_add_expert(tree, pinfo, &ei_smb_not_implemented, tvb, offset, 0); + + *trunc = FALSE; + return offset; +} + +static int +dissect_qspi_unix_open(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, + int offset, guint16 *bcp _U_, gboolean *trunc) +{ + proto_tree_add_expert(tree, pinfo, &ei_smb_not_implemented, tvb, offset, 0); + + *trunc = FALSE; + return offset; +} + +static int +dissect_qspi_unix_unlink(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, + int offset, guint16 *bcp _U_, gboolean *trunc) +{ + proto_tree_add_expert(tree, pinfo, &ei_smb_not_implemented, tvb, offset, 0); + + *trunc = FALSE; + return offset; +} + +/* SMB_FIND_FILE_UNIX_INFO2 */ + +#if 0 +static const true_false_string tfs_i2f_secure_delete = { + "File should be erased such that the data is not recoverable", + "File need not be erased such that the data is not recoverable" +}; +static const true_false_string tfs_i2f_enable_undelete = { + "File should opt-in to a server-specific deletion recovery scheme", + "File should not opt-in to a server-specific deletion recovery scheme" +}; +static const true_false_string tfs_i2f_synchronous = { + "I/O to this file should be performed synchronously", + "I/O to this file need not be performed synchronously" +}; +static const true_false_string tfs_i2f_immutable = { + "NO changes can be made to this file", + "Changes can be made to this file if permissions allow it" +}; +static const true_false_string tfs_i2f_append_only = { + "Only appends can be made to this file", + "Writes can be made atop existing data in this file" +}; +static const true_false_string tfs_i2f_do_not_backup = { + "Backup programs should ignore this file", + "Backup programs should not ignore this file" +}; +static const true_false_string tfs_i2f_no_update_atime = { + "The server is not required to update the last access time on this file", + "The server is required to update the last access time on this file" +}; +static const true_false_string tfs_i2f_hidden = { + "User interface programs may ignore this file", + "User interface programs should not ignore this file based solely on this flag" +}; +#endif + +static int +dissect_unix_info2_file_flags(tvbuff_t *tvb, proto_tree *parent_tree, int offset, int hf) +{ + static int * const flags[] = { + &hf_smb_unix_info2_file_flags_secure_delete, + &hf_smb_unix_info2_file_flags_enable_undelete, + &hf_smb_unix_info2_file_flags_synchronous, + &hf_smb_unix_info2_file_flags_immutable, + &hf_smb_unix_info2_file_flags_append_only, + &hf_smb_unix_info2_file_flags_do_not_backup, + &hf_smb_unix_info2_file_flags_no_update_atime, + &hf_smb_unix_info2_file_flags_hidden, + NULL + }; + + proto_tree_add_bitmask(parent_tree, tvb, offset, hf, ett_smb_info2_file_flags, flags, ENC_LITTLE_ENDIAN); + offset += 4; + + return offset; +} + +static int +dissect_qspi_unix_info2(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, + int offset, guint16 *bcp, gboolean *trunc) +{ + /* End of file (file size) */ + CHECK_BYTE_COUNT_SUBR(8); + proto_tree_add_item(tree, hf_smb_unix_file_size, tvb, offset, 8, ENC_LITTLE_ENDIAN); + COUNT_BYTES_SUBR(8); + + /* Number of bytes (or blocks? The SNIA spec for UNIX basic + info says "bytes", the Samba page for this says "blocks") */ + CHECK_BYTE_COUNT_SUBR(8); + proto_tree_add_item(tree, hf_smb_unix_file_num_bytes, tvb, offset, 8, ENC_LITTLE_ENDIAN); + COUNT_BYTES_SUBR(8); + + /* Last status change */ + CHECK_BYTE_COUNT_SUBR(8); + offset = dissect_nt_64bit_time(tvb, tree, offset, hf_smb_unix_file_last_status); + *bcp -= 8; + + /* Last access time */ + CHECK_BYTE_COUNT_SUBR(8); + offset = dissect_nt_64bit_time(tvb, tree, offset, hf_smb_unix_file_last_access); + *bcp -= 8; + + /* Last modification time */ + CHECK_BYTE_COUNT_SUBR(8); + offset = dissect_nt_64bit_time(tvb, tree, offset, hf_smb_unix_file_last_change); + *bcp -= 8; + + /* File owner uid */ + CHECK_BYTE_COUNT_SUBR(8); + proto_tree_add_item(tree, hf_smb_unix_file_uid, tvb, offset, 8, ENC_LITTLE_ENDIAN); + COUNT_BYTES_SUBR(8); + + /* File group gid */ + CHECK_BYTE_COUNT_SUBR(8); + proto_tree_add_item(tree, hf_smb_unix_file_gid, tvb, offset, 8, ENC_LITTLE_ENDIAN); + COUNT_BYTES_SUBR(8); + + /* File type */ + CHECK_BYTE_COUNT_SUBR(4); + proto_tree_add_item(tree, hf_smb_unix_file_type, tvb, offset, 4, ENC_LITTLE_ENDIAN); + COUNT_BYTES_SUBR(4); + + /* Major device number */ + CHECK_BYTE_COUNT_SUBR(8); + proto_tree_add_item(tree, hf_smb_unix_file_dev_major, tvb, offset, 8, ENC_LITTLE_ENDIAN); + COUNT_BYTES_SUBR(8); + + /* Minor device number */ + CHECK_BYTE_COUNT_SUBR(8); + proto_tree_add_item(tree, hf_smb_unix_file_dev_minor, tvb, offset, 8, ENC_LITTLE_ENDIAN); + COUNT_BYTES_SUBR(8); + + /* Unique id */ + CHECK_BYTE_COUNT_SUBR(8); + proto_tree_add_item(tree, hf_smb_unix_file_unique_id, tvb, offset, 8, ENC_LITTLE_ENDIAN); + COUNT_BYTES_SUBR(8); + + /* Permissions */ + CHECK_BYTE_COUNT_SUBR(8); + proto_tree_add_item(tree, hf_smb_unix_file_permissions, tvb, offset, 8, ENC_LITTLE_ENDIAN); + COUNT_BYTES_SUBR(8); + + /* Nlinks */ + CHECK_BYTE_COUNT_SUBR(8); + proto_tree_add_item(tree, hf_smb_unix_file_nlinks, tvb, offset, 8, ENC_LITTLE_ENDIAN); + COUNT_BYTES_SUBR(8); + + /* Creation time */ + CHECK_BYTE_COUNT_SUBR(8); + offset = dissect_nt_64bit_time(tvb, tree, offset, hf_smb_unix_file_creation_time); + *bcp -= 8; + + /* File flags */ + CHECK_BYTE_COUNT_SUBR(4); + offset = dissect_unix_info2_file_flags(tvb, tree, offset, hf_smb_unix_info2_file_flags); + *bcp -= 4; + + /* File flags mask */ + CHECK_BYTE_COUNT_SUBR(4); + offset = dissect_unix_info2_file_flags(tvb, tree, offset, hf_smb_unix_info2_file_flags_mask); + *bcp -= 4; + + *trunc = FALSE; + return offset; +} + +/* this dissects the SMB_QUERY_FILE_NETWORK_OPEN_INFO +*/ +int +dissect_qfi_SMB_FILE_NETWORK_OPEN_INFO(tvbuff_t *tvb, + packet_info *pinfo, proto_tree *tree, + int offset, guint16 *bcp, gboolean *trunc) +{ + + offset = dissect_smb_standard_8byte_timestamps(tvb, pinfo, tree, offset, bcp, trunc); + if (*trunc) { + return offset; + } + + /* allocation size */ + CHECK_BYTE_COUNT_SUBR(8); + proto_tree_add_item(tree, hf_smb_alloc_size64, tvb, offset, 8, ENC_LITTLE_ENDIAN); + COUNT_BYTES_SUBR(8); + + /* end of file */ + CHECK_BYTE_COUNT_SUBR(8); + proto_tree_add_item(tree, hf_smb_end_of_file, tvb, offset, 8, ENC_LITTLE_ENDIAN); + COUNT_BYTES_SUBR(8); + + /* File Attributes */ + CHECK_BYTE_COUNT_SUBR(4); + offset = dissect_file_ext_attr(tvb, tree, offset); + *bcp -= 4; + + /* 4 reserved bytes */ + CHECK_BYTE_COUNT_SUBR(4); + proto_tree_add_item(tree, hf_smb_reserved, tvb, offset, 4, ENC_NA); + COUNT_BYTES_SUBR(4); + + *trunc = FALSE; + return offset; +} + +/* this dissects the SMB_FILE_ATTRIBUTE_TAG_INFO +*/ +int +dissect_qfi_SMB_FILE_ATTRIBUTE_TAG_INFO(tvbuff_t *tvb, + packet_info *pinfo _U_, proto_tree *tree, + int offset, guint16 *bcp, gboolean *trunc) +{ + /* attribute */ + CHECK_BYTE_COUNT_SUBR(4); + proto_tree_add_item(tree, hf_smb_attribute, tvb, offset, 4, ENC_LITTLE_ENDIAN); + COUNT_BYTES_SUBR(4); + + /* reparse tag */ + CHECK_BYTE_COUNT_SUBR(4); + proto_tree_add_item(tree, hf_smb_reparse_tag, tvb, offset, 4, ENC_LITTLE_ENDIAN); + COUNT_BYTES_SUBR(4); + + *trunc = FALSE; + return offset; +} + +/* this dissects the SMB_SET_FILE_DISPOSITION_INFO + as described in 4.2.19.2 +*/ +static int +dissect_4_2_19_2(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, + int offset, guint16 *bcp, gboolean *trunc) +{ + /* marked for deletion? */ + CHECK_BYTE_COUNT_SUBR(1); + proto_tree_add_item(tree, hf_smb_t2_marked_for_deletion, tvb, offset, 1, ENC_LITTLE_ENDIAN); + COUNT_BYTES_SUBR(1); + + *trunc = FALSE; + return offset; +} + +/* Set File Rename Info */ + +static const true_false_string tfs_smb_replace = { + "Remove target file if it exists", + "Do NOT remove target file if it exists", +}; + +static int +dissect_rename_info(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, + int offset, guint16 *bcp, gboolean *trunc, smb_info_t *si) +{ + const char *fn; + guint32 target_name_len; + int fn_len; + + DISSECTOR_ASSERT(si); + + /* Replace flag */ + CHECK_BYTE_COUNT_SUBR(4); + proto_tree_add_item(tree, hf_smb_replace, tvb, offset, 4, ENC_LITTLE_ENDIAN); + COUNT_BYTES_SUBR(4); + + /* Root directory handle */ + CHECK_BYTE_COUNT_SUBR(4); + proto_tree_add_item(tree, hf_smb_root_dir_handle, tvb, offset, 4, ENC_LITTLE_ENDIAN); + COUNT_BYTES_SUBR(4); + + /* Target name length */ + CHECK_BYTE_COUNT_SUBR(4); + target_name_len = tvb_get_letohl(tvb, offset); + proto_tree_add_uint(tree, hf_smb_target_name_len, tvb, offset, 4, target_name_len); + COUNT_BYTES_SUBR(4); + + /* Target name */ + fn_len = target_name_len; + fn = get_unicode_or_ascii_string( + tvb, &offset, si->unicode, &fn_len, FALSE, TRUE, bcp); + + CHECK_STRING_SUBR(fn); + proto_tree_add_string( + tree, hf_smb_target_name, tvb, offset, fn_len, fn); + COUNT_BYTES_SUBR(fn_len); + + *trunc = FALSE; + return offset; +} + +static int +dissect_disposition_info(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, + int offset, guint16 *bcp, gboolean *trunc, smb_info_t *si) +{ +#if 0 + const char *fn; + guint32 target_name_len;*/ + int fn_len; +#endif + + DISSECTOR_ASSERT(si); + + /* Disposition flags */ + CHECK_BYTE_COUNT_SUBR(1); + proto_tree_add_item(tree, hf_smb_disposition_delete_on_close, tvb, offset, 1, ENC_LITTLE_ENDIAN); + COUNT_BYTES_SUBR(1); + + *trunc = FALSE; + return offset; +} + +int +dissect_sfi_SMB_FILE_PIPE_INFO(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, + int offset, guint16 *bcp, gboolean *trunc) +{ + /* pipe info flag */ + CHECK_BYTE_COUNT_SUBR(1); + proto_tree_add_item(tree, hf_smb_pipe_info_flag, tvb, offset, 1, ENC_LITTLE_ENDIAN); + COUNT_BYTES_SUBR(1); + + *trunc = FALSE; + return offset; +} + +/*dissect the data block for TRANS2_QUERY_PATH_INFORMATION and + TRANS2_QUERY_FILE_INFORMATION*/ +static int +dissect_qpi_loi_vals(tvbuff_t * tvb, packet_info * pinfo, proto_tree * tree, + proto_item *item, int offset, guint16 *bcp, smb_info_t *si) +{ + gboolean trunc = FALSE; + + if (!*bcp) { + return offset; + } + + DISSECTOR_ASSERT(si); + + switch(si->info_level) { + case 1: /*Info Standard*/ + offset = dissect_qsfi_SMB_INFO_STANDARD(tvb, pinfo, tree, offset, bcp, + &trunc); + break; + + case 2: /*Info Query EA Size*/ + offset = dissect_qfi_SMB_INFO_QUERY_EA_SIZE(tvb, pinfo, tree, offset, bcp, + &trunc); + break; + case 3: /*Info Query EAs From List*/ + case 4: /*Info Query All EAs*/ + offset = dissect_4_2_16_2(tvb, pinfo, tree, offset, bcp, + &trunc); + break; + case 6: /*Info Is Name Valid*/ + offset = dissect_4_2_16_3(tvb, pinfo, tree, offset, bcp, + &trunc, si); + break; + case 0x0101: /*Query File Basic Info*/ + case 1004: /* SMB_FILE_BASIC_INFORMATION */ + offset = dissect_4_2_16_4(tvb, pinfo, tree, offset, bcp, + &trunc); + break; + case 0x0102: /*Query File Standard Info*/ + case 1005: /* SMB_FILE_STANDARD_INFORMATION */ + offset = dissect_qfi_SMB_FILE_STANDARD_INFO(tvb, pinfo, tree, offset, bcp, + &trunc); + break; + case 1006: /* SMB_FILE_INTERNAL_INFORMATION */ + offset = dissect_qfi_SMB_FILE_INTERNAL_INFO(tvb, pinfo, tree, offset, bcp, + &trunc); + break; + case 0x0103: /*Query File EA Info*/ + case 1007: /* SMB_FILE_EA_INFORMATION */ + offset = dissect_qfi_SMB_FILE_EA_INFO(tvb, pinfo, tree, offset, bcp, + &trunc); + break; + case 0x0104: /*Query File Name Info*/ + case 1009: /* SMB_FILE_NAME_INFORMATION */ + offset = dissect_qfi_SMB_FILE_NAME_INFO(tvb, pinfo, tree, offset, bcp, + &trunc, si->unicode); + break; + case 1014: /* SMB_FILE_POSITION_INFORMATION */ + offset = dissect_qsfi_SMB_FILE_POSITION_INFO(tvb, pinfo, tree, offset, bcp, + &trunc); + break; + case 1016: /* SMB_FILE_MODE_INFORMATION */ + offset = dissect_qsfi_SMB_FILE_MODE_INFO(tvb, pinfo, tree, offset, bcp, + &trunc); + break; + case 1017: /* SMB_FILE_ALIGNMENT_INFORMATION */ + offset = dissect_qfi_SMB_FILE_ALIGNMENT_INFO(tvb, pinfo, tree, offset, bcp, + &trunc); + break; + case 0x0107: /*Query File All Info*/ + case 1018: /* SMB_FILE_ALL_INFORMATION */ + offset = dissect_qfi_SMB_FILE_ALL_INFO(tvb, pinfo, tree, offset, bcp, + &trunc, si); + break; + case 1019: /* SMB_FILE_ALLOCATION_INFORMATION */ + offset = dissect_qsfi_SMB_FILE_ALLOCATION_INFO(tvb, pinfo, tree, offset, bcp, + &trunc); + break; + case 1020: /* SMB_FILE_ENDOFFILE_INFORMATION */ + offset = dissect_qsfi_SMB_FILE_ENDOFFILE_INFO(tvb, pinfo, tree, offset, bcp, + &trunc); + break; + case 0x0108: /*Query File Alt File Info*/ + case 1021: /* SMB_FILE_ALTERNATE_NAME_INFORMATION */ + offset = dissect_qfi_SMB_FILE_NAME_INFO(tvb, pinfo, tree, offset, bcp, + &trunc, si->unicode); + break; + case 1022: /* SMB_FILE_STREAM_INFORMATION */ + si->unicode = TRUE; + /* FALLTHRU */ + case 0x0109: /*Query File Stream Info*/ + offset = dissect_qfi_SMB_FILE_STREAM_INFO(tvb, pinfo, tree, offset, bcp, + &trunc, si->unicode); + break; + case 0x010b: /*Query File Compression Info*/ + case 1028: /* SMB_FILE_COMPRESSION_INFORMATION */ + offset = dissect_qfi_SMB_FILE_COMPRESSION_INFO(tvb, pinfo, tree, offset, bcp, + &trunc); + break; + case 1034: /* SMB_FILE_NETWORK_OPEN_INFO */ + offset = dissect_qfi_SMB_FILE_NETWORK_OPEN_INFO(tvb, pinfo, tree, offset, bcp, &trunc); + break; + case 1035: /* SMB_FILE_ATTRIBUTE_TAG_INFO */ + offset = dissect_qfi_SMB_FILE_ATTRIBUTE_TAG_INFO(tvb, pinfo, tree, offset, bcp, &trunc); + break; + case 0x0200: /* Query File Unix Basic*/ + offset = dissect_4_2_16_12(tvb, pinfo, tree, offset, bcp, + &trunc); + break; + case 0x0201: /* Query File Unix Link*/ + offset = dissect_4_2_16_13(tvb, pinfo, tree, offset, bcp, + &trunc, si); + break; + case 0x0202: /* Query File Unix HardLink*/ + /* XXX add this from the SNIA doc */ + break; + case 0x0204: /* Query File Unix ACL*/ + offset = dissect_qspi_unix_acl(tvb, pinfo, tree, offset, bcp, + &trunc); + break; + case 0x0205: /* Query File Unix XATTR*/ + offset = dissect_qspi_unix_xattr(tvb, pinfo, tree, offset, bcp, + &trunc); + break; + case 0x0206: /* Query File Unix Attr Flags*/ + offset = dissect_qspi_unix_attr_flags(tvb, pinfo, tree, offset, bcp, + &trunc); + break; + case 0x0207: /* Query File Unix Permissions*/ + offset = dissect_qpi_unix_permissions(tvb, pinfo, tree, offset, bcp, + &trunc); + break; + case 0x0208: /* Query File Unix Lock*/ + offset = dissect_qspi_unix_lock(tvb, pinfo, tree, offset, bcp, + &trunc); + break; + case 0x020b: /* Query File Unix Info2*/ + offset = dissect_qspi_unix_info2(tvb, pinfo, tree, offset, bcp, + &trunc); + break; + + default: + proto_tree_add_expert(tree, pinfo, &ei_smb_info_level_unknown, tvb, offset, *bcp); + offset += *bcp; + *bcp = 0; + trunc = FALSE; + break; + } + + if (trunc) { + expert_add_info(pinfo, item, &ei_smb_mal_information_level); + } + return offset; +} + +/*dissect the data block for TRANS2_SET_PATH_INFORMATION and + TRANS2_SET_FILE_INFORMATION*/ +static int +dissect_spi_loi_vals(tvbuff_t * tvb, packet_info * pinfo, proto_tree * tree, + proto_item *item, int offset, guint16 *bcp, smb_info_t *si) +{ + gboolean trunc; + + if (!*bcp) { + return offset; + } + + DISSECTOR_ASSERT(si); + + switch(si->info_level) { + case 1: /*Info Standard*/ + offset = dissect_qsfi_SMB_INFO_STANDARD(tvb, pinfo, tree, offset, bcp, + &trunc); + break; + case 2: /*Info Set EAs*/ + offset = dissect_4_2_16_2(tvb, pinfo, tree, offset, bcp, + &trunc); + break; + case 4: /*Info Query All EAs - not in [MS-CIFS]*/ + offset = dissect_4_2_16_2(tvb, pinfo, tree, offset, bcp, + &trunc); + break; + case 0x0101: /*Set File Basic Info*/ + case 1004: /* SMB_FILE_BASIC_INFORMATION */ + offset = dissect_4_2_16_4(tvb, pinfo, tree, offset, bcp, + &trunc); + break; + case 0x0102: /*Set File Disposition Info*/ + offset = dissect_4_2_19_2(tvb, pinfo, tree, offset, bcp, + &trunc); + break; + case 0x0103: /*Set File Allocation Info*/ + case 1019: /* Set File Allocation Information */ + offset = dissect_qsfi_SMB_FILE_ALLOCATION_INFO(tvb, pinfo, tree, offset, bcp, + &trunc); + break; + case 0x0104: /*Set End Of File Info*/ + case 1020: /* SMB_FILE_ENDOFFILE_INFORMATION */ + offset = dissect_qsfi_SMB_FILE_ENDOFFILE_INFO(tvb, pinfo, tree, offset, bcp, + &trunc); + break; + case 0x0200: /*Set File Unix Basic. Same as query. */ + offset = dissect_4_2_16_12(tvb, pinfo, tree, offset, bcp, + &trunc); + break; + case 0x0201: /*Set File Unix Link. Same as query. */ + offset = dissect_4_2_16_13(tvb, pinfo, tree, offset, bcp, + &trunc, si); + break; + case 0x0202: /*Set File Unix HardLink. Same as link query. */ + offset = dissect_4_2_16_13(tvb, pinfo, tree, offset, bcp, + &trunc, si); + break; + case 0x0204: /* Set File Unix ACL*/ + offset = dissect_qspi_unix_acl(tvb, pinfo, tree, offset, bcp, + &trunc); + break; + case 0x0205: /* Set File Unix XATTR*/ + offset = dissect_qspi_unix_xattr(tvb, pinfo, tree, offset, bcp, + &trunc); + break; + case 0x0206: /* Set File Unix Attr Flags*/ + offset = dissect_qspi_unix_attr_flags(tvb, pinfo, tree, offset, bcp, + &trunc); + break; + case 0x0208: /* Set File Unix Lock*/ + offset = dissect_qspi_unix_lock(tvb, pinfo, tree, offset, bcp, + &trunc); + break; + case 0x0209: /* Set File Unix Open*/ + offset = dissect_qspi_unix_open(tvb, pinfo, tree, offset, bcp, + &trunc); + break; + case 0x020a: /* Set File Unix Unlink*/ + offset = dissect_qspi_unix_unlink(tvb, pinfo, tree, offset, bcp, + &trunc); + break; + case 0x020b: /* Set File Unix Info2*/ + offset = dissect_qspi_unix_info2(tvb, pinfo, tree, offset, bcp, + &trunc); + break; + case 1010: /* Set File Rename */ + offset = dissect_rename_info(tvb, pinfo, tree, offset, bcp, + &trunc, si); + break; + case 1013: /* Set Disposition Information */ + offset = dissect_disposition_info(tvb, pinfo, tree, offset, bcp, + &trunc, si); + break; + case 1014: /* SMB_FILE_POSITION_INFORMATION */ + offset = dissect_qsfi_SMB_FILE_POSITION_INFO(tvb, pinfo, tree, offset, bcp, + &trunc); + break; + case 1016: /* SMB_FILE_MODE_INFORMATION */ + offset = dissect_qsfi_SMB_FILE_MODE_INFO(tvb, pinfo, tree, offset, bcp, + &trunc); + break; + case 1023: /* Set Pipe Info */ + offset = dissect_sfi_SMB_FILE_PIPE_INFO(tvb, pinfo, tree, offset, bcp, + &trunc); + break; + case 1025: + case 1029: + case 1032: + case 1039: + case 1040: + /* XXX: TODO, extra levels discovered by tridge */ + proto_tree_add_expert(tree, pinfo, &ei_smb_info_level_not_understood, tvb, offset, *bcp); + offset += *bcp; + *bcp = 0; + trunc = FALSE; + break; + + default: + proto_tree_add_expert(tree, pinfo, &ei_smb_info_level_unknown, tvb, offset, *bcp); + offset += *bcp; + *bcp = 0; + trunc = FALSE; + break; + } + + if (trunc) { + expert_add_info(pinfo, item, &ei_smb_mal_information_level); + } + return offset; +} + + +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, proto_tree *parent_tree, int offset) +{ + static int * const mask[] = { + &hf_smb_quota_flags_deny_disk, + &hf_smb_quota_flags_log_warning, + &hf_smb_quota_flags_log_limit, + &hf_smb_quota_flags_enabled, + NULL + }; + + proto_tree_add_bitmask(parent_tree, tvb, offset, hf_smb_quota_flags, + ett_smb_quotaflags, mask, ENC_NA); +} + +int +dissect_nt_quota(tvbuff_t *tvb, 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, ENC_NA); + 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, ENC_LITTLE_ENDIAN); + 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, ENC_LITTLE_ENDIAN); + COUNT_BYTES_TRANS_SUBR(8); + + /* one byte of quota flags */ + CHECK_BYTE_COUNT_TRANS_SUBR(1); + dissect_quota_flags(tvb, 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, ENC_NA); + COUNT_BYTES_TRANS_SUBR(7); + + return offset; +} + +static int +dissect_sfsi_request(tvbuff_t * tvb, packet_info * pinfo, proto_tree * tree, + int offset, guint16 *bcp, smb_info_t *si) +{ + if (!*bcp) { + return offset; + } + + DISSECTOR_ASSERT(si); + + switch(si->info_level) { + case 0x203: /* REQUEST_TRANSPORT_ENCRYPTION */ { + proto_item *blob_item; + tvbuff_t *blob_tvb; + proto_tree *blob_tree; + + /* security blob */ + blob_item = proto_tree_add_item(tree, hf_smb_security_blob, + tvb, offset, + tvb_reported_length_remaining(tvb, offset), + ENC_NA); + + /* As an optimization, because Windows is perverse, + we check to see if NTLMSSP is the first part of the + blob, and if so, call the NTLMSSP dissector, + otherwise we call the GSS-API dissector. This is because + Windows can request RAW NTLMSSP, but will happily handle + a client that wraps NTLMSSP in SPNEGO + */ + + blob_tree = proto_item_add_subtree(blob_item, + ett_smb_secblob); + + blob_tvb = tvb_new_subset_remaining(tvb, offset); + + if (tvb_strneql(blob_tvb, 0, "NTLMSSP", 7) == 0) { + call_dissector(ntlmssp_handle, blob_tvb, pinfo, blob_tree); + } else { + call_dissector(gssapi_handle, blob_tvb, pinfo, blob_tree); + } + + offset += tvb_reported_length_remaining(tvb, offset); + *bcp = 0; + break; + } + case 1006: /* QUERY_FS_QUOTA_INFO */ + offset = dissect_nt_quota(tvb, tree, offset, bcp); + break; + } + + return offset; +} + +static int +dissect_sfsi_response(tvbuff_t * tvb, packet_info * pinfo, proto_tree * tree, + int offset, guint16 *bcp, smb_info_t *si) +{ + if (!*bcp) { + return offset; + } + + DISSECTOR_ASSERT(si); + + switch(si->info_level) { + case 0x203: /* REQUEST_TRANSPORT_ENCRYPTION */ { + proto_item *blob_item; + tvbuff_t *blob_tvb; + proto_tree *blob_tree; + + /* security blob */ + blob_item = proto_tree_add_item(tree, hf_smb_security_blob, + tvb, offset, + tvb_reported_length_remaining(tvb, offset), + ENC_NA); + + /* As an optimization, because Windows is perverse, + we check to see if NTLMSSP is the first part of the + blob, and if so, call the NTLMSSP dissector, + otherwise we call the GSS-API dissector. This is because + Windows can request RAW NTLMSSP, but will happily handle + a client that wraps NTLMSSP in SPNEGO + */ + + blob_tree = proto_item_add_subtree(blob_item, + ett_smb_secblob); + + blob_tvb = tvb_new_subset_remaining(tvb, offset); + + if (tvb_strneql(blob_tvb, 0, "NTLMSSP", 7) == 0) { + call_dissector(ntlmssp_handle, blob_tvb, pinfo, blob_tree); + } else { + call_dissector(gssapi_handle, blob_tvb, pinfo, blob_tree); + } + + offset += tvb_reported_length_remaining(tvb, offset); + *bcp = 0; + break; + } + case 1006: /* QUERY_FS_QUOTA_INFO */ + /* nothing */ + break; + } + + return offset; +} + +static int +dissect_transaction2_request_data(tvbuff_t *tvb, packet_info *pinfo, + proto_tree *parent_tree, int offset, int subcmd, guint16 dc, smb_info_t *si) +{ + proto_item *item; + proto_tree *tree; + + DISSECTOR_ASSERT(si); + + tree = proto_tree_add_subtree_format(parent_tree, tvb, offset, dc, + ett_smb_transaction_data, &item, "%s Data", + val_to_str_ext(subcmd, &trans2_cmd_vals_ext, + "Unknown (0x%02x)")); + + switch(subcmd) { + case 0x0000: /*TRANS2_OPEN2*/ + /* XXX don't know how to decode FEAList */ + break; + case 0x0001: /*TRANS2_FIND_FIRST2*/ + /* XXX don't know how to decode FEAList */ + break; + case 0x0002: /*TRANS2_FIND_NEXT2*/ + /* XXX don't know how to decode FEAList */ + break; + case 0x0003: /*TRANS2_QUERY_FS_INFORMATION*/ + /* no data field in this request */ + break; + case 0x0004: /* TRANS2_SET_FS_INFORMATION */ + offset = dissect_sfsi_request(tvb, pinfo, tree, offset, &dc, si); + break; + case 0x0005: /*TRANS2_QUERY_PATH_INFORMATION*/ + /* no data field in this request */ + /* + * XXX - "Microsoft Networks SMB File Sharing Protocol + * Extensions Version 3.0, Document Version 1.11, + * July 19, 1990" says there may be "Additional + * FileInfoLevel dependent information" here. + * + * Was that just a cut-and-pasteo? + * TRANS2_SET_PATH_INFORMATION *does* have that information + * here. + */ + break; + case 0x0006: /*TRANS2_SET_PATH_INFORMATION*/ + offset = dissect_spi_loi_vals(tvb, pinfo, tree, item, offset, &dc, si); + break; + case 0x0007: /*TRANS2_QUERY_FILE_INFORMATION*/ + /* no data field in this request */ + /* + * XXX - "Microsoft Networks SMB File Sharing Protocol + * Extensions Version 3.0, Document Version 1.11, + * July 19, 1990" says there may be "Additional + * FileInfoLevel dependent information" here. + * + * Was that just a cut-and-pasteo? + * TRANS2_SET_FILE_INFORMATION *does* have that information + * here. + */ + break; + case 0x0008: /*TRANS2_SET_FILE_INFORMATION*/ + offset = dissect_spi_loi_vals(tvb, pinfo, tree, item, offset, &dc, si); + break; + case 0x0009: /*TRANS2_FSCTL*/ + /*XXX don't know how to decode this yet */ + + /* + * XXX - "Microsoft Networks SMB File Sharing Protocol + * Extensions Version 3.0, Document Version 1.11, + * July 19, 1990" says this contains a + * "File system specific data block". (That means we + * may not be able to dissect it in any case.) + */ + break; + case 0x000a: /*TRANS2_IOCTL2*/ + /*XXX don't know how to decode this yet */ + + /* + * XXX - "Microsoft Networks SMB File Sharing Protocol + * Extensions Version 3.0, Document Version 1.11, + * July 19, 1990" says this contains a + * "Device/function specific data block". (That + * means we may not be able to dissect it in any case.) + */ + break; + case 0x000b: /*TRANS2_FIND_NOTIFY_FIRST*/ + /*XXX don't know how to decode this yet */ + + /* + * XXX - "Microsoft Networks SMB File Sharing Protocol + * Extensions Version 3.0, Document Version 1.11, + * July 19, 1990" says this contains "additional + * level dependent match data". + */ + break; + case 0x000c: /*TRANS2_FIND_NOTIFY_NEXT*/ + /*XXX don't know how to decode this yet */ + + /* + * XXX - "Microsoft Networks SMB File Sharing Protocol + * Extensions Version 3.0, Document Version 1.11, + * July 19, 1990" says this contains "additional + * level dependent monitor information". + */ + break; + case 0x000d: /*TRANS2_CREATE_DIRECTORY*/ + /* XXX optional FEAList, unknown what FEAList looks like*/ + break; + case 0x000e: /*TRANS2_SESSION_SETUP*/ + /*XXX don't know how to decode this yet */ + break; + case 0x0010: /*TRANS2_GET_DFS_REFERRAL*/ + /* no data field in this request */ + break; + case 0x0011: /*TRANS2_REPORT_DFS_INCONSISTENCY*/ + offset = dissect_dfs_inconsistency_data(tvb, pinfo, tree, offset, &dc, si); + break; + } + + /* ooops there were data we didn't know how to process */ + if (dc != 0) { + proto_tree_add_item(tree, hf_smb_unknown, tvb, offset, dc, ENC_NA); + offset += dc; + } + + return offset; +} + + +static void +dissect_trans_data(tvbuff_t *s_tvb, tvbuff_t *p_tvb, tvbuff_t *d_tvb, + proto_tree *tree) +{ + int i; + int offset; + guint length; + + /* + * Show the setup words. + */ + if (s_tvb != NULL) { + length = tvb_reported_length(s_tvb); + for (i = 0, offset = 0; length >= 2; + i++, offset += 2, length -= 2) { + /* + * XXX - add a setup word filterable field? + */ + proto_tree_add_uint_format(tree, hf_smb_trans_data_setup_word, s_tvb, offset, 2, + tvb_get_letohs(s_tvb, offset), "Setup Word %d: 0x%04x", i, tvb_get_letohs(s_tvb, offset)); + } + } + + /* + * Show the parameters, if any. + */ + if (p_tvb != NULL) { + length = tvb_reported_length(p_tvb); + if (length != 0) { + proto_tree_add_item(tree, hf_smb_trans_data_parameters, p_tvb, 0, length, ENC_NA); + } + } + + /* + * Show the data, if any. + */ + if (d_tvb != NULL) { + length = tvb_reported_length(d_tvb); + if (length != 0) { + proto_tree_add_item(tree, hf_smb_trans_data, d_tvb, 0, length, ENC_NA); + } + } +} + +/* This routine handles the following 4 calls + Transaction 0x25 + Transaction Secondary 0x26 + Transaction2 0x32 + Transaction2 Secondary 0x33 +*/ +static int +dissect_transaction_request(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int offset, proto_tree *smb_tree _U_, smb_info_t *si) +{ + guint8 wc, sc = 0; + int so = offset; + int sl = 0; + int spo = offset; + int spc = 0; + guint16 od = 0, po = 0, pc = 0, dc = 0, pd, dd = 0; + int subcmd = -1; + guint32 to; + int an_len; + const char *an = NULL; + smb_transact2_info_t *t2i; + smb_transact_info_t *tri; + guint16 bc; + int padcnt; + gboolean dissected_trans; + + DISSECTOR_ASSERT(si); + + WORD_COUNT; + + if (wc == 8 || (wc == 9 && si->cmd == SMB_COM_TRANSACTION2_SECONDARY)) { + /*secondary client request*/ + + /* total param count, only a 16bit integer here*/ + proto_tree_add_item(tree, hf_smb_total_param_count, tvb, offset, 2, ENC_LITTLE_ENDIAN); + offset += 2; + + /* total data count , only 16bit integer here*/ + proto_tree_add_item(tree, hf_smb_total_data_count, tvb, offset, 2, ENC_LITTLE_ENDIAN); + offset += 2; + + /* param count */ + pc = tvb_get_letohs(tvb, offset); + proto_tree_add_uint(tree, hf_smb_param_count16, tvb, offset, 2, pc); + offset += 2; + + /* param offset */ + po = tvb_get_letohs(tvb, offset); + proto_tree_add_uint(tree, hf_smb_param_offset16, tvb, offset, 2, po); + offset += 2; + + /* param disp */ + pd = tvb_get_letohs(tvb, offset); + proto_tree_add_uint(tree, hf_smb_param_disp16, tvb, offset, 2, pd); + offset += 2; + + /* data count */ + dc = tvb_get_letohs(tvb, offset); + proto_tree_add_uint(tree, hf_smb_data_count16, tvb, offset, 2, dc); + offset += 2; + + /* data offset */ + od = tvb_get_letohs(tvb, offset); + proto_tree_add_uint(tree, hf_smb_data_offset16, tvb, offset, 2, od); + offset += 2; + + /* data disp */ + dd = tvb_get_letohs(tvb, offset); + proto_tree_add_uint(tree, hf_smb_data_disp16, tvb, offset, 2, dd); + offset += 2; + + if (si->cmd == SMB_COM_TRANSACTION2 || si->cmd == SMB_COM_TRANSACTION2_SECONDARY) { + guint16 fid; + + /* fid */ + fid = tvb_get_letohs(tvb, offset); + dissect_smb_fid(tvb, pinfo, tree, offset, 2, fid, FALSE, FALSE, FALSE, si); + + offset += 2; + } + + /* There are no setup words. */ + so = offset; + sl = 0; + } else { + /* it is not a secondary request */ + + /* total param count , only a 16 bit integer here*/ + proto_tree_add_item(tree, hf_smb_total_param_count, tvb, offset, 2, ENC_LITTLE_ENDIAN); + offset += 2; + + /* total data count , only 16bit integer here*/ + proto_tree_add_item(tree, hf_smb_total_data_count, tvb, offset, 2, ENC_LITTLE_ENDIAN); + offset += 2; + + /* max param count , only 16bit integer here*/ + proto_tree_add_item(tree, hf_smb_max_param_count, tvb, offset, 2, ENC_LITTLE_ENDIAN); + offset += 2; + + /* max data count, only 16bit integer here*/ + proto_tree_add_item(tree, hf_smb_max_data_count, tvb, offset, 2, ENC_LITTLE_ENDIAN); + offset += 2; + + /* max setup count, only 16bit integer here*/ + proto_tree_add_item(tree, hf_smb_max_setup_count, tvb, offset, 1, ENC_NA); + offset += 1; + + /* reserved byte */ + proto_tree_add_item(tree, hf_smb_reserved, tvb, offset, 1, ENC_NA); + offset += 1; + + /* transaction flags */ + dissect_transaction_flags(tvb, tree, offset); + offset += 2; + + /* timeout */ + to = tvb_get_letohl(tvb, offset); + proto_tree_add_uint_format_value(tree, hf_smb_timeout, tvb, offset, 4, to, "%s", smbext20_timeout_msecs_to_str(to)); + offset += 4; + + /* 2 reserved bytes */ + proto_tree_add_item(tree, hf_smb_reserved, tvb, offset, 2, ENC_NA); + offset += 2; + + /* param count */ + pc = tvb_get_letohs(tvb, offset); + proto_tree_add_uint(tree, hf_smb_param_count16, tvb, offset, 2, pc); + offset += 2; + + /* param offset */ + po = tvb_get_letohs(tvb, offset); + proto_tree_add_uint(tree, hf_smb_param_offset16, tvb, offset, 2, po); + offset += 2; + + /* data count */ + dc = tvb_get_letohs(tvb, offset); + proto_tree_add_uint(tree, hf_smb_data_count16, tvb, offset, 2, dc); + offset += 2; + + /* data offset */ + od = tvb_get_letohs(tvb, offset); + proto_tree_add_uint(tree, hf_smb_data_offset16, tvb, offset, 2, od); + offset += 2; + + /* data displacement is zero here */ + dd = 0; + + /* setup count */ + sc = tvb_get_guint8(tvb, offset); + proto_tree_add_uint(tree, hf_smb_setup_count, tvb, offset, 1, sc); + offset += 1; + + /* reserved byte */ + proto_tree_add_item(tree, hf_smb_reserved, tvb, offset, 1, ENC_NA); + offset += 1; + + /* this is where the setup bytes, if any start */ + so = offset; + sl = sc*2; + + /* if there were any setup bytes, decode them */ + if (sc) { + switch(si->cmd) { + + case SMB_COM_TRANSACTION2: + /* TRANSACTION2 only has one setup word and + that is the subcommand code. + + XXX - except for TRANS2_FSCTL + and TRANS2_IOCTL. */ + subcmd = tvb_get_letohs(tvb, offset); + proto_tree_add_uint(tree, hf_smb_trans2_subcmd, + tvb, offset, 2, subcmd); + col_append_fstr(pinfo->cinfo, COL_INFO, ", %s", + val_to_str_ext(subcmd, &trans2_cmd_vals_ext, + "Unknown (0x%02x)")); + + if (!si->unidir) { + if (!pinfo->fd->visited && si->sip) { + /* + * Allocate a new + * smb_transact2_info_t + * structure. + */ + t2i = wmem_new(wmem_file_scope(), smb_transact2_info_t); + t2i->subcmd = subcmd; + t2i->info_level = -1; + t2i->resume_keys = FALSE; + t2i->name = NULL; + si->sip->extra_info = t2i; + si->sip->extra_info_type = SMB_EI_T2I; + } + } + + /* + * XXX - process TRANS2_FSCTL and + * TRANS2_IOCTL setup words here. + */ + break; + + case SMB_COM_TRANSACTION: + /* TRANSACTION setup words processed below */ + break; + } + + offset += sl; + } + } + + BYTE_COUNT; + + if (wc != 8) { + /* primary request */ + /* name is NULL if transaction2 */ + if (si->cmd == SMB_COM_TRANSACTION) { + /* Transaction Name */ + an = get_unicode_or_ascii_string(tvb, &offset, + si->unicode, &an_len, FALSE, FALSE, &bc); + if (an == NULL) + goto endofcommand; + proto_tree_add_string(tree, hf_smb_trans_name, tvb, + offset, an_len, an); + COUNT_BYTES(an_len); + } + } + + /* + * The pipe or mailslot arguments for Transaction start with + * the first setup word (or where the first setup word would + * be if there were any setup words), and run to the current + * offset (which could mean that there aren't any). + */ + spo = so; + spc = offset - spo; + + /* parameters */ + if (po > offset) { + /* We have some initial padding bytes. + */ + padcnt = po-offset; + if (padcnt > bc) + padcnt = bc; + proto_tree_add_item(tree, hf_smb_padding, tvb, offset, padcnt, ENC_NA); + COUNT_BYTES(padcnt); + } + if (pc) { + CHECK_BYTE_COUNT(pc); + switch(si->cmd) { + + case SMB_COM_TRANSACTION2: + /* TRANSACTION2 parameters*/ + offset = dissect_transaction2_request_parameters(tvb, + pinfo, tree, offset, subcmd, pc, si); + bc -= pc; + break; + + case SMB_COM_TRANSACTION: + /* TRANSACTION parameters processed below */ + COUNT_BYTES(pc); + break; + } + } + + /* data */ + if (od > offset) { + /* We have some initial padding bytes. + */ + padcnt = od-offset; + if (padcnt > bc) + padcnt = bc; + proto_tree_add_item(tree, hf_smb_padding, tvb, offset, padcnt, ENC_NA); + COUNT_BYTES(padcnt); + } + if (dc) { + CHECK_BYTE_COUNT(dc); + switch(si->cmd) { + + case SMB_COM_TRANSACTION2: + /* TRANSACTION2 data*/ + offset = dissect_transaction2_request_data(tvb, pinfo, + tree, offset, subcmd, dc, si); + bc -= dc; + break; + + case SMB_COM_TRANSACTION: + /* TRANSACTION data processed below */ + COUNT_BYTES(dc); + break; + } + } + + /*TRANSACTION request parameters */ + if (si->cmd == SMB_COM_TRANSACTION) { + /*XXX replace this block with a function and use that one + for both requests/responses*/ + if (dd == 0) { + tvbuff_t *p_tvb, *d_tvb, *s_tvb; + tvbuff_t *sp_tvb, *pd_tvb; + + if (pc > 0) { + if (pc>tvb_reported_length_remaining(tvb, po)) { + p_tvb = tvb_new_subset_length_caplen(tvb, po, tvb_reported_length_remaining(tvb, po), pc); + } else { + p_tvb = tvb_new_subset_length(tvb, po, pc); + } + } else { + p_tvb = NULL; + } + if (dc > 0) { + if (dc>tvb_reported_length_remaining(tvb, od)) { + d_tvb = tvb_new_subset_length_caplen(tvb, od, tvb_reported_length_remaining(tvb, od), dc); + } else { + d_tvb = tvb_new_subset_length(tvb, od, dc); + } + } else { + d_tvb = NULL; + } + if (sl) { + if (sl>tvb_reported_length_remaining(tvb, so)) { + s_tvb = tvb_new_subset_length_caplen(tvb, so, tvb_reported_length_remaining(tvb, so), sl); + } else { + s_tvb = tvb_new_subset_length(tvb, so, sl); + } + } else { + s_tvb = NULL; + } + + if (!si->unidir) { + if (!pinfo->fd->visited && si->sip) { + /* + * Allocate a new smb_transact_info_t + * structure. + */ + tri = wmem_new(wmem_file_scope(), smb_transact_info_t); + tri->subcmd = -1; + tri->trans_subcmd = -1; + tri->function = -1; + tri->fid = -1; + tri->lanman_cmd = 0; + tri->param_descrip = NULL; + tri->data_descrip = NULL; + tri->aux_data_descrip = NULL; + tri->info_level = -1; + si->sip->extra_info = tri; + si->sip->extra_info_type = SMB_EI_TRI; + } else { + /* + * We already filled the structure + * in; don't bother doing so again. + */ + tri = NULL; + } + } else { + /* + * This is a unidirectional message, for + * which there will be no reply; don't + * bother allocating an "smb_transact_info_t" + * structure for it. + */ + tri = NULL; + } + dissected_trans = FALSE; + if (an == NULL) + goto endofcommand; + if (strncmp("\\PIPE\\", an, 6) == 0) { + if (tri != NULL) + tri->subcmd = TRANSACTION_PIPE; + + /* + * A tvbuff containing the setup words and + * the pipe path. + */ + sp_tvb = tvb_new_subset_length(tvb, spo, spc); + + /* + * A tvbuff containing the parameters and the + * data. + */ + pd_tvb = tvb_new_subset_remaining(tvb, po); + + dissected_trans = dissect_pipe_smb(sp_tvb, + s_tvb, pd_tvb, p_tvb, d_tvb, an+6, pinfo, + top_tree_global, si); + + /* In case we did not see the TreeConnect call, + store this TID here as well as a IPC TID + so we know that future Read/Writes to this + TID is (probably) DCERPC. + */ + if (g_hash_table_lookup(si->ct->tid_service, GUINT_TO_POINTER(si->tid))) { + g_hash_table_remove(si->ct->tid_service, GUINT_TO_POINTER(si->tid)); + } + g_hash_table_insert(si->ct->tid_service, GUINT_TO_POINTER(si->tid), (void *)TID_IPC); + } else if (strncmp("\\MAILSLOT\\", an, 10) == 0) { + if (tri != NULL) + tri->subcmd = TRANSACTION_MAILSLOT; + + /* + * A tvbuff containing the setup words and + * the mailslot path. + */ + sp_tvb = tvb_new_subset_length(tvb, spo, spc); + dissected_trans = dissect_mailslot_smb(sp_tvb, + s_tvb, d_tvb, an+10, pinfo, top_tree_global, si); + } + if (!dissected_trans) + dissect_trans_data(s_tvb, p_tvb, d_tvb, tree); + } else { + col_append_str(pinfo->cinfo, COL_INFO, + "[transact continuation]"); + } + } + + END_OF_SMB + + return offset; +} + + + +static int +dissect_4_3_4_1(tvbuff_t *tvb, packet_info *pinfo, proto_tree *parent_tree, + int offset, guint16 *bcp, gboolean *trunc, smb_info_t *si) +{ + int fn_len; + const char *fn; + int old_offset = offset; + proto_item *item; + proto_tree *tree; + smb_transact2_info_t *t2i; + gboolean resume_keys = FALSE; + guint32 bytes_needed = 0; + + DISSECTOR_ASSERT(si); + + if ((si->sip != NULL) && (si->sip->extra_info_type == SMB_EI_T2I)) { + t2i = (smb_transact2_info_t *)si->sip->extra_info; + if (t2i != NULL) + resume_keys = t2i->resume_keys; + } + + tree = proto_tree_add_subtree(parent_tree, tvb, offset, *bcp, ett_smb_ff2_data, &item, + val_to_str(si->info_level, ff2_il_vals, "Unknown (0x%02x)")); + + /* + * Figure out of there are enough bytes to display the whole entry. + * This consistes of 22 bytes or 26 bytes if resume_keys, followed + * by a length byte and that many chars. + */ + bytes_needed = 23 + (resume_keys ? 4 : 0); + tvb_ensure_bytes_exist(tvb, offset, bytes_needed); + + /* Now, get the length */ + fn_len = tvb_get_guint8(tvb, offset + bytes_needed - 1); + tvb_ensure_bytes_exist(tvb, offset, bytes_needed + fn_len); + + if (resume_keys) { + /* resume key */ + CHECK_BYTE_COUNT_SUBR(4); + proto_tree_add_item(tree, hf_smb_resume, tvb, offset, 4, ENC_LITTLE_ENDIAN); + COUNT_BYTES_SUBR(4); + } + + /* create time */ + CHECK_BYTE_COUNT_SUBR(4); + offset = dissect_smb_datetime(tvb, tree, offset, + hf_smb_create_time, + hf_smb_create_dos_date, hf_smb_create_dos_time, FALSE); + *bcp -= 4; + + /* access time */ + CHECK_BYTE_COUNT_SUBR(4); + offset = dissect_smb_datetime(tvb, tree, offset, + hf_smb_access_time, + hf_smb_access_dos_date, hf_smb_access_dos_time, FALSE); + *bcp -= 4; + + /* last write time */ + CHECK_BYTE_COUNT_SUBR(4); + offset = dissect_smb_datetime(tvb, tree, offset, + hf_smb_last_write_time, + hf_smb_last_write_dos_date, hf_smb_last_write_dos_time, FALSE); + *bcp -= 4; + + /* data size */ + CHECK_BYTE_COUNT_SUBR(4); + proto_tree_add_item(tree, hf_smb_data_size, tvb, offset, 4, ENC_LITTLE_ENDIAN); + COUNT_BYTES_SUBR(4); + + /* allocation size */ + CHECK_BYTE_COUNT_SUBR(4); + proto_tree_add_item(tree, hf_smb_alloc_size, tvb, offset, 4, ENC_LITTLE_ENDIAN); + COUNT_BYTES_SUBR(4); + + /* File Attributes */ + CHECK_BYTE_COUNT_SUBR(2); + offset = dissect_file_attributes(tvb, tree, offset); + *bcp -= 2; + + /* file name len */ + CHECK_BYTE_COUNT_SUBR(1); + fn_len = tvb_get_guint8(tvb, offset); + proto_tree_add_uint(tree, hf_smb_file_name_len, tvb, offset, 1, fn_len); + COUNT_BYTES_SUBR(1); + if (si->unicode) + fn_len += 2; /* include terminating '\0' */ + else + fn_len++; /* include terminating '\0' */ + + /* file name */ + fn = get_unicode_or_ascii_string(tvb, &offset, si->unicode, &fn_len, FALSE, TRUE, bcp); + CHECK_STRING_SUBR(fn); + proto_tree_add_string(tree, hf_smb_file_name, tvb, offset, fn_len, + fn); + COUNT_BYTES_SUBR(fn_len); + + col_append_fstr(pinfo->cinfo, COL_INFO, " %s", + format_text(wmem_packet_scope(), fn, strlen(fn))); + + proto_item_append_text(item, " File: %s", format_text(wmem_packet_scope(), (const guchar*)fn, strlen(fn))); + proto_item_set_len(item, offset-old_offset); + + *trunc = FALSE; + return offset; +} + +static int +dissect_4_3_4_2(tvbuff_t *tvb, packet_info *pinfo, proto_tree *parent_tree, + int offset, guint16 *bcp, gboolean *trunc, smb_info_t *si) +{ + int fn_len; + const char *fn; + int old_offset = offset; + proto_item *item; + proto_tree *tree; + smb_transact2_info_t *t2i; + gboolean resume_keys = FALSE; + guint32 bytes_needed = 0; + + DISSECTOR_ASSERT(si); + + if ((si->sip != NULL) && (si->sip->extra_info_type == SMB_EI_T2I)) { + t2i = (smb_transact2_info_t *)si->sip->extra_info; + if (t2i != NULL) + resume_keys = t2i->resume_keys; + } + + tree = proto_tree_add_subtree(parent_tree, tvb, offset, *bcp, ett_smb_ff2_data, &item, + val_to_str(si->info_level, ff2_il_vals, "Unknown (0x%02x)")); + + /* + * Figure out of there are enough bytes to display the whole entry. + * This consistes of 26 bytes or 30 bytes if resume_keys, followed + * by a length byte and that many chars. + */ + bytes_needed = 27 + (resume_keys ? 4 : 0); + tvb_ensure_bytes_exist(tvb, offset, bytes_needed); + + /* Now, get the length */ + fn_len = tvb_get_guint8(tvb, offset + bytes_needed - 1); + tvb_ensure_bytes_exist(tvb, offset, bytes_needed + fn_len); + + if (resume_keys) { + /* resume key */ + CHECK_BYTE_COUNT_SUBR(4); + proto_tree_add_item(tree, hf_smb_resume, tvb, offset, 4, ENC_LITTLE_ENDIAN); + COUNT_BYTES_SUBR(4); + } + + /* create time */ + CHECK_BYTE_COUNT_SUBR(4); + offset = dissect_smb_datetime(tvb, tree, offset, + hf_smb_create_time, + hf_smb_create_dos_date, hf_smb_create_dos_time, FALSE); + *bcp -= 4; + + /* access time */ + CHECK_BYTE_COUNT_SUBR(4); + offset = dissect_smb_datetime(tvb, tree, offset, + hf_smb_access_time, + hf_smb_access_dos_date, hf_smb_access_dos_time, FALSE); + *bcp -= 4; + + /* last write time */ + CHECK_BYTE_COUNT_SUBR(4); + offset = dissect_smb_datetime(tvb, tree, offset, + hf_smb_last_write_time, + hf_smb_last_write_dos_date, hf_smb_last_write_dos_time, FALSE); + *bcp -= 4; + + /* data size */ + CHECK_BYTE_COUNT_SUBR(4); + proto_tree_add_item(tree, hf_smb_data_size, tvb, offset, 4, ENC_LITTLE_ENDIAN); + COUNT_BYTES_SUBR(4); + + /* allocation size */ + CHECK_BYTE_COUNT_SUBR(4); + proto_tree_add_item(tree, hf_smb_alloc_size, tvb, offset, 4, ENC_LITTLE_ENDIAN); + COUNT_BYTES_SUBR(4); + + /* File Attributes */ + CHECK_BYTE_COUNT_SUBR(2); + offset = dissect_file_attributes(tvb, tree, offset); + *bcp -= 2; + + /* ea length */ + CHECK_BYTE_COUNT_SUBR(4); + proto_tree_add_item(tree, hf_smb_ea_list_length, tvb, offset, 4, ENC_LITTLE_ENDIAN); + COUNT_BYTES_SUBR(4); + + /* file name len */ + CHECK_BYTE_COUNT_SUBR(1); + fn_len = tvb_get_guint8(tvb, offset); + proto_tree_add_uint(tree, hf_smb_file_name_len, tvb, offset, 1, fn_len); + COUNT_BYTES_SUBR(1); + + /* file name */ + fn = get_unicode_or_ascii_string(tvb, &offset, si->unicode, &fn_len, TRUE, TRUE, bcp); + CHECK_STRING_SUBR(fn); + proto_tree_add_string(tree, hf_smb_file_name, tvb, offset, fn_len, + fn); + COUNT_BYTES_SUBR(fn_len); + + col_append_fstr(pinfo->cinfo, COL_INFO, " %s", + format_text(wmem_packet_scope(), (const guchar*)fn, strlen(fn))); + + proto_item_append_text(item, " File: %s", format_text(wmem_packet_scope(), (const guchar*)fn, strlen(fn))); + + /* + * To quote the footnote for FileName in Section 2.2.8.1.2: + * + * Windows NT servers always append a single NULL padding byte + * to the FileName field. The length of this additional byte + * is not included in the value of the FileNameLength field. + * + * That's "single byte", not "UTF-16 null character". + * + * XXX - what about other servers? Do we need to somehow + * determine whether the server is a "Windows NT server" or + * not? + */ + CHECK_BYTE_COUNT_SUBR(1); + COUNT_BYTES_SUBR(1); + + proto_item_set_len(item, offset-old_offset); + + *trunc = FALSE; + return offset; +} + +/* + * According to MS-CIFS 2.2.8.1.3 this is like the function above with the + * addition of the list of EA name value pairs before the file name. + * + * The EAs are formatted as an SMB_FEA as in 2.2.1.2.2. We will deal with + * this soon. + */ +static int +dissect_4_3_4_3(tvbuff_t *tvb, packet_info *pinfo, proto_tree *parent_tree, + int offset, guint16 *bcp, gboolean *trunc, smb_info_t *si) +{ + int fn_len; + const char *fn; + int old_offset = offset; + int ea_size = 0; + proto_item *item; + proto_tree *tree; + smb_transact2_info_t *t2i; + gboolean resume_keys = FALSE; + + + DISSECTOR_ASSERT(si); + + if ((si->sip != NULL) && (si->sip->extra_info_type == SMB_EI_T2I)) { + t2i = (smb_transact2_info_t *)si->sip->extra_info; + if (t2i != NULL) + resume_keys = t2i->resume_keys; + } + + tree = proto_tree_add_subtree(parent_tree, tvb, offset, *bcp, ett_smb_ff2_data, &item, + val_to_str(si->info_level, ff2_il_vals, "Unknown (0x%02x)")); + + if (resume_keys) { + /* resume key */ + CHECK_BYTE_COUNT_SUBR(4); + proto_tree_add_item(tree, hf_smb_resume, tvb, offset, 4, ENC_LITTLE_ENDIAN); + COUNT_BYTES_SUBR(4); + } + + /* create time */ + CHECK_BYTE_COUNT_SUBR(4); + offset = dissect_smb_datetime(tvb, tree, offset, + hf_smb_create_time, + hf_smb_create_dos_date, hf_smb_create_dos_time, FALSE); + *bcp -= 4; + + /* access time */ + CHECK_BYTE_COUNT_SUBR(4); + offset = dissect_smb_datetime(tvb, tree, offset, + hf_smb_access_time, + hf_smb_access_dos_date, hf_smb_access_dos_time, FALSE); + *bcp -= 4; + + /* last write time */ + CHECK_BYTE_COUNT_SUBR(4); + offset = dissect_smb_datetime(tvb, tree, offset, + hf_smb_last_write_time, + hf_smb_last_write_dos_date, hf_smb_last_write_dos_time, FALSE); + *bcp -= 4; + + /* data size */ + CHECK_BYTE_COUNT_SUBR(4); + proto_tree_add_item(tree, hf_smb_data_size, tvb, offset, 4, ENC_LITTLE_ENDIAN); + COUNT_BYTES_SUBR(4); + + /* allocation size */ + CHECK_BYTE_COUNT_SUBR(4); + proto_tree_add_item(tree, hf_smb_alloc_size, tvb, offset, 4, ENC_LITTLE_ENDIAN); + COUNT_BYTES_SUBR(4); + + /* File Attributes */ + CHECK_BYTE_COUNT_SUBR(2); + offset = dissect_file_attributes(tvb, tree, offset); + *bcp -= 2; + + /* ea length */ + CHECK_BYTE_COUNT_SUBR(4); + ea_size = tvb_get_letohl(tvb, offset); + proto_tree_add_item(tree, hf_smb_ea_list_length, tvb, offset, 4, ENC_LITTLE_ENDIAN); + COUNT_BYTES_SUBR(4); + + /* The EAs ... they are formatted as in MS-CIFS 2.2.1.2.2 */ + proto_tree_add_bytes_format(tree, hf_smb_file_data, tvb, offset, ea_size, NULL, "EAs"); + COUNT_BYTES_SUBR(ea_size); + *bcp -= ea_size; + + /* file name len */ + CHECK_BYTE_COUNT_SUBR(1); + fn_len = tvb_get_guint8(tvb, offset); + proto_tree_add_uint(tree, hf_smb_file_name_len, tvb, offset, 1, fn_len); + COUNT_BYTES_SUBR(1); + if (si->unicode) + fn_len += 2; /* include terminating '\0' */ + else + fn_len++; /* include terminating '\0' */ + + /* file name */ + fn = get_unicode_or_ascii_string(tvb, &offset, si->unicode, &fn_len, FALSE, TRUE, bcp); + CHECK_STRING_SUBR(fn); + proto_tree_add_string(tree, hf_smb_file_name, tvb, offset, fn_len, + fn); + COUNT_BYTES_SUBR(fn_len); + + col_append_fstr(pinfo->cinfo, COL_INFO, " %s", + format_text(wmem_packet_scope(), (const guchar*)fn, strlen(fn))); + + proto_item_append_text(item, " File: %s", format_text(wmem_packet_scope(), (const guchar*)fn, strlen(fn))); + proto_item_set_len(item, offset-old_offset); + + return offset; +} + +static int +dissect_4_3_4_4(tvbuff_t *tvb, packet_info *pinfo, proto_tree *parent_tree, + int offset, guint16 *bcp, gboolean *trunc, smb_info_t *si) +{ + int fn_len; + const char *fn; + int old_offset = offset; + proto_item *item; + proto_tree *tree; + guint32 neo; + int padcnt; + + DISSECTOR_ASSERT(si); + + /* + * We check this first before adding the sub-tree so things do not + * get ugly. + */ + + /* next entry offset */ + CHECK_BYTE_COUNT_SUBR(4); + neo = tvb_get_letohl(tvb, offset); + + /* Ensure we have the bytes we need, which is up to neo */ + tvb_ensure_bytes_exist(tvb, offset, neo ? neo : *bcp); + + tree = proto_tree_add_subtree(parent_tree, tvb, offset, *bcp, ett_smb_ff2_data, &item, + val_to_str(si->info_level, ff2_il_vals, "Unknown (0x%02x)")); + + /* + * We assume that the presence of a next entry offset implies the + * absence of a resume key, as appears to be the case for 4.3.4.6. + */ + + CHECK_BYTE_COUNT_SUBR(4); + proto_tree_add_uint(tree, hf_smb_next_entry_offset, tvb, offset, 4, neo); + COUNT_BYTES_SUBR(4); + + /* file index */ + CHECK_BYTE_COUNT_SUBR(4); + proto_tree_add_item(tree, hf_smb_file_index, tvb, offset, 4, ENC_LITTLE_ENDIAN); + COUNT_BYTES_SUBR(4); + + offset = dissect_smb_standard_8byte_timestamps(tvb, pinfo, tree, offset, bcp, trunc); + if (*trunc) { + return offset; + } + + /* end of file */ + CHECK_BYTE_COUNT_SUBR(8); + proto_tree_add_item(tree, hf_smb_end_of_file, tvb, offset, 8, ENC_LITTLE_ENDIAN); + COUNT_BYTES_SUBR(8); + + /* allocation size */ + CHECK_BYTE_COUNT_SUBR(8); + proto_tree_add_item(tree, hf_smb_alloc_size64, tvb, offset, 8, ENC_LITTLE_ENDIAN); + COUNT_BYTES_SUBR(8); + + /* Extended File Attributes */ + CHECK_BYTE_COUNT_SUBR(4); + offset = dissect_file_ext_attr(tvb, tree, offset); + *bcp -= 4; + + /* file name len */ + CHECK_BYTE_COUNT_SUBR(4); + fn_len = tvb_get_letohl(tvb, offset); + proto_tree_add_uint(tree, hf_smb_file_name_len, tvb, offset, 4, fn_len); + COUNT_BYTES_SUBR(4); + + /* file name */ + fn = get_unicode_or_ascii_string(tvb, &offset, si->unicode, &fn_len, FALSE, TRUE, bcp); + CHECK_STRING_SUBR(fn); + proto_tree_add_string(tree, hf_smb_file_name, tvb, offset, fn_len, + fn); + COUNT_BYTES_SUBR(fn_len); + + col_append_fstr(pinfo->cinfo, COL_INFO, " %s", + format_text(wmem_packet_scope(), (const guchar*)fn, strlen(fn))); + + /* skip to next structure */ + if (neo) { + padcnt = (old_offset + neo) - offset; + if (padcnt < 0) { + /* + * XXX - this is bogus; flag it? + */ + padcnt = 0; + } + if (padcnt != 0) { + CHECK_BYTE_COUNT_SUBR(padcnt); + COUNT_BYTES_SUBR(padcnt); + } + } + + proto_item_append_text(item, " File: %s", format_text(wmem_packet_scope(), (const guchar*)fn, strlen(fn))); + proto_item_set_len(item, offset-old_offset); + + *trunc = FALSE; + return offset; +} + +static int +dissect_4_3_4_5(tvbuff_t *tvb, packet_info *pinfo, proto_tree *parent_tree, + int offset, guint16 *bcp, gboolean *trunc, smb_info_t *si) +{ + int fn_len; + const char *fn; + int old_offset = offset; + proto_item *item; + proto_tree *tree; + guint32 neo; + int padcnt; + + DISSECTOR_ASSERT(si); + + /* + * We check this first before adding the sub-tree so things do not + * get ugly. + */ + + /* next entry offset */ + CHECK_BYTE_COUNT_SUBR(4); + neo = tvb_get_letohl(tvb, offset); + + /* Ensure we have the bytes we need, which is up to neo */ + tvb_ensure_bytes_exist(tvb, offset, neo ? neo : *bcp); + + tree = proto_tree_add_subtree(parent_tree, tvb, offset, *bcp, ett_smb_ff2_data, &item, + val_to_str(si->info_level, ff2_il_vals, "Unknown (0x%02x)")); + + /* + * We assume that the presence of a next entry offset implies the + * absence of a resume key, as appears to be the case for 4.3.4.6. + */ + + CHECK_BYTE_COUNT_SUBR(4); + proto_tree_add_uint(tree, hf_smb_next_entry_offset, tvb, offset, 4, neo); + COUNT_BYTES_SUBR(4); + + /* file index */ + CHECK_BYTE_COUNT_SUBR(4); + proto_tree_add_item(tree, hf_smb_file_index, tvb, offset, 4, ENC_LITTLE_ENDIAN); + COUNT_BYTES_SUBR(4); + + /* standard 8-byte timestamps */ + offset = dissect_smb_standard_8byte_timestamps(tvb, pinfo, tree, offset, bcp, trunc); + if (*trunc) { + return offset; + } + + /* end of file */ + CHECK_BYTE_COUNT_SUBR(8); + proto_tree_add_item(tree, hf_smb_end_of_file, tvb, offset, 8, ENC_LITTLE_ENDIAN); + COUNT_BYTES_SUBR(8); + + /* allocation size */ + CHECK_BYTE_COUNT_SUBR(8); + proto_tree_add_item(tree, hf_smb_alloc_size64, tvb, offset, 8, ENC_LITTLE_ENDIAN); + COUNT_BYTES_SUBR(8); + + /* Extended File Attributes */ + CHECK_BYTE_COUNT_SUBR(4); + offset = dissect_file_ext_attr(tvb, tree, offset); + *bcp -= 4; + + /* file name len */ + CHECK_BYTE_COUNT_SUBR(4); + fn_len = tvb_get_letohl(tvb, offset); + proto_tree_add_uint(tree, hf_smb_file_name_len, tvb, offset, 4, fn_len); + COUNT_BYTES_SUBR(4); + + /* ea length */ + CHECK_BYTE_COUNT_SUBR(4); + proto_tree_add_item(tree, hf_smb_ea_list_length, tvb, offset, 4, ENC_LITTLE_ENDIAN); + COUNT_BYTES_SUBR(4); + + /* file name */ + fn = get_unicode_or_ascii_string(tvb, &offset, si->unicode, &fn_len, FALSE, TRUE, bcp); + CHECK_STRING_SUBR(fn); + proto_tree_add_string(tree, hf_smb_file_name, tvb, offset, fn_len, + fn); + COUNT_BYTES_SUBR(fn_len); + + col_append_fstr(pinfo->cinfo, COL_INFO, " %s", + format_text(wmem_packet_scope(), (const guchar*)fn, strlen(fn))); + + /* skip to next structure */ + if (neo) { + padcnt = (old_offset + neo) - offset; + if (padcnt < 0) { + /* + * XXX - this is bogus; flag it? + */ + padcnt = 0; + } + if (padcnt != 0) { + CHECK_BYTE_COUNT_SUBR(padcnt); + COUNT_BYTES_SUBR(padcnt); + } + } + + proto_item_append_text(item, " File: %s", format_text(wmem_packet_scope(), (const guchar*)fn, strlen(fn))); + proto_item_set_len(item, offset-old_offset); + + *trunc = FALSE; + return offset; +} + +static int +dissect_4_3_4_6(tvbuff_t *tvb, packet_info *pinfo, proto_tree *parent_tree, + int offset, guint16 *bcp, gboolean *trunc, smb_info_t *si) +{ + int fn_len, sfn_len; + const char *fn, *sfn; + int old_offset = offset; + proto_item *item; + proto_tree *tree; + guint32 neo; + int padcnt; + + DISSECTOR_ASSERT(si); + + /* + * We check this first before adding the sub-tree so things do not + * get ugly. + */ + + /* next entry offset */ + CHECK_BYTE_COUNT_SUBR(4); + neo = tvb_get_letohl(tvb, offset); + + /* Ensure we have the bytes we need, which is up to neo */ + tvb_ensure_bytes_exist(tvb, offset, neo ? neo : *bcp); + + tree = proto_tree_add_subtree(parent_tree, tvb, offset, *bcp, ett_smb_ff2_data, &item, + val_to_str(si->info_level, ff2_il_vals, "Unknown (0x%02x)")); + + /* + * XXX - I have not seen any of these that contain a resume + * key, even though some of the requests had the "return resume + * key" flag set. + */ + + CHECK_BYTE_COUNT_SUBR(4); + proto_tree_add_uint(tree, hf_smb_next_entry_offset, tvb, offset, 4, neo); + COUNT_BYTES_SUBR(4); + + /* file index */ + CHECK_BYTE_COUNT_SUBR(4); + proto_tree_add_item(tree, hf_smb_file_index, tvb, offset, 4, ENC_LITTLE_ENDIAN); + COUNT_BYTES_SUBR(4); + + /* dissect standard 8-byte timestamps */ + offset = dissect_smb_standard_8byte_timestamps(tvb, pinfo, tree, offset, bcp, trunc); + if (*trunc) { + return offset; + } + + /* end of file */ + CHECK_BYTE_COUNT_SUBR(8); + proto_tree_add_item(tree, hf_smb_end_of_file, tvb, offset, 8, ENC_LITTLE_ENDIAN); + COUNT_BYTES_SUBR(8); + + /* allocation size */ + CHECK_BYTE_COUNT_SUBR(8); + proto_tree_add_item(tree, hf_smb_alloc_size64, tvb, offset, 8, ENC_LITTLE_ENDIAN); + COUNT_BYTES_SUBR(8); + + /* Extended File Attributes */ + CHECK_BYTE_COUNT_SUBR(4); + offset = dissect_file_ext_attr(tvb, tree, offset); + *bcp -= 4; + + /* file name len */ + CHECK_BYTE_COUNT_SUBR(4); + fn_len = tvb_get_letohl(tvb, offset); + proto_tree_add_uint(tree, hf_smb_file_name_len, tvb, offset, 4, fn_len); + COUNT_BYTES_SUBR(4); + + /* + * EA length. + * + * XXX - in one captures, this has the topmost bit set, and the + * rest of the bits have the value 7. Is the topmost bit being + * set some indication that the value *isn't* the length of + * the EAs? + */ + CHECK_BYTE_COUNT_SUBR(4); + proto_tree_add_item(tree, hf_smb_ea_list_length, tvb, offset, 4, ENC_LITTLE_ENDIAN); + COUNT_BYTES_SUBR(4); + + /* short file name len */ + CHECK_BYTE_COUNT_SUBR(1); + sfn_len = tvb_get_guint8(tvb, offset); + proto_tree_add_uint(tree, hf_smb_short_file_name_len, tvb, offset, 1, sfn_len); + COUNT_BYTES_SUBR(1); + + /* reserved byte */ + CHECK_BYTE_COUNT_SUBR(1); + proto_tree_add_item(tree, hf_smb_reserved, tvb, offset, 1, ENC_NA); + COUNT_BYTES_SUBR(1); + + /* short file name - it's not always in Unicode */ + sfn = get_unicode_or_ascii_string(tvb, &offset, si->unicode, &sfn_len, FALSE, TRUE, bcp); + CHECK_STRING_SUBR(sfn); + proto_tree_add_string(tree, hf_smb_short_file_name, tvb, offset, 24, + sfn); + COUNT_BYTES_SUBR(24); + + /* file name */ + fn = get_unicode_or_ascii_string(tvb, &offset, si->unicode, &fn_len, FALSE, TRUE, bcp); + CHECK_STRING_SUBR(fn); + proto_tree_add_string(tree, hf_smb_file_name, tvb, offset, fn_len, + fn); + COUNT_BYTES_SUBR(fn_len); + + col_append_fstr(pinfo->cinfo, COL_INFO, " %s", + format_text(wmem_packet_scope(), (const guchar*)fn, strlen(fn))); + + /* skip to next structure */ + if (neo) { + padcnt = (old_offset + neo) - offset; + if (padcnt < 0) { + /* + * XXX - this is bogus; flag it? + */ + padcnt = 0; + } + if (padcnt != 0) { + CHECK_BYTE_COUNT_SUBR(padcnt); + COUNT_BYTES_SUBR(padcnt); + } + } + + proto_item_append_text(item, " File: %s", format_text(wmem_packet_scope(), (const guchar*)fn, strlen(fn))); + proto_item_set_len(item, offset-old_offset); + + *trunc = FALSE; + return offset; +} + +static int +dissect_4_3_4_6full(tvbuff_t *tvb, packet_info *pinfo, proto_tree *parent_tree, + int offset, guint16 *bcp, gboolean *trunc, smb_info_t *si) +{ + int fn_len; + const char *fn; + int old_offset = offset; + proto_item *item; + proto_tree *tree; + guint32 neo; + int padcnt; + + DISSECTOR_ASSERT(si); + + /* + * We check this first before adding the sub-tree so things do not + * get ugly. + */ + + /* next entry offset */ + CHECK_BYTE_COUNT_SUBR(4); + neo = tvb_get_letohl(tvb, offset); + + /* Ensure we have the bytes we need, which is up to neo */ + tvb_ensure_bytes_exist(tvb, offset, neo ? neo : *bcp); + + tree = proto_tree_add_subtree(parent_tree, tvb, offset, *bcp, ett_smb_ff2_data, &item, + val_to_str(si->info_level, ff2_il_vals, "Unknown (0x%02x)")); + + /* + * XXX - I have not seen any of these that contain a resume + * key, even though some of the requests had the "return resume + * key" flag set. + */ + + CHECK_BYTE_COUNT_SUBR(4); + proto_tree_add_uint(tree, hf_smb_next_entry_offset, tvb, offset, 4, neo); + COUNT_BYTES_SUBR(4); + + /* file index */ + CHECK_BYTE_COUNT_SUBR(4); + proto_tree_add_item(tree, hf_smb_file_index, tvb, offset, 4, ENC_LITTLE_ENDIAN); + COUNT_BYTES_SUBR(4); + + /* dissect standard 8-byte timestamps */ + offset = dissect_smb_standard_8byte_timestamps(tvb, pinfo, tree, offset, bcp, trunc); + if (*trunc) { + return offset; + } + + /* end of file */ + CHECK_BYTE_COUNT_SUBR(8); + proto_tree_add_item(tree, hf_smb_end_of_file, tvb, offset, 8, ENC_LITTLE_ENDIAN); + COUNT_BYTES_SUBR(8); + + /* allocation size */ + CHECK_BYTE_COUNT_SUBR(8); + proto_tree_add_item(tree, hf_smb_alloc_size64, tvb, offset, 8, ENC_LITTLE_ENDIAN); + COUNT_BYTES_SUBR(8); + + /* Extended File Attributes */ + CHECK_BYTE_COUNT_SUBR(4); + offset = dissect_file_ext_attr(tvb, tree, offset); + *bcp -= 4; + + /* file name len */ + CHECK_BYTE_COUNT_SUBR(4); + fn_len = tvb_get_letohl(tvb, offset); + proto_tree_add_uint(tree, hf_smb_file_name_len, tvb, offset, 4, fn_len); + COUNT_BYTES_SUBR(4); + + /* + * EA length. + * + * XXX - in one captures, this has the topmost bit set, and the + * rest of the bits have the value 7. Is the topmost bit being + * set some indication that the value *isn't* the length of + * the EAs? + */ + CHECK_BYTE_COUNT_SUBR(4); + proto_tree_add_item(tree, hf_smb_ea_list_length, tvb, offset, 4, ENC_LITTLE_ENDIAN); + COUNT_BYTES_SUBR(4); + + /* skip 4 bytes */ + COUNT_BYTES_SUBR(4); + + CHECK_BYTE_COUNT_SUBR(8); + proto_tree_add_item(tree, hf_smb_index_number, tvb, offset, 8, ENC_LITTLE_ENDIAN); + COUNT_BYTES_SUBR(8); + + /* file name */ + fn = get_unicode_or_ascii_string(tvb, &offset, si->unicode, &fn_len, FALSE, TRUE, bcp); + CHECK_STRING_SUBR(fn); + proto_tree_add_string(tree, hf_smb_file_name, tvb, offset, fn_len, + fn); + COUNT_BYTES_SUBR(fn_len); + + col_append_fstr(pinfo->cinfo, COL_INFO, " %s", + format_text(wmem_packet_scope(), (const guchar*)fn, strlen(fn))); + + /* skip to next structure */ + if (neo) { + padcnt = (old_offset + neo) - offset; + if (padcnt < 0) { + /* + * XXX - this is bogus; flag it? + */ + padcnt = 0; + } + if (padcnt != 0) { + CHECK_BYTE_COUNT_SUBR(padcnt); + COUNT_BYTES_SUBR(padcnt); + } + } + + proto_item_append_text(item, " File: %s", format_text(wmem_packet_scope(), (const guchar*)fn, strlen(fn))); + proto_item_set_len(item, offset-old_offset); + + *trunc = FALSE; + return offset; +} + +static int +dissect_4_3_4_6_id_both(tvbuff_t *tvb, packet_info *pinfo, proto_tree *parent_tree, + int offset, guint16 *bcp, gboolean *trunc, smb_info_t *si) +{ + int fn_len, sfn_len; + const char *fn, *sfn; + int old_offset = offset; + proto_item *item; + proto_tree *tree; + guint32 neo; + int padcnt; + + DISSECTOR_ASSERT(si); + + /* + * We check this first before adding the sub-tree so things do not + * get ugly. + */ + + /* next entry offset */ + CHECK_BYTE_COUNT_SUBR(4); + neo = tvb_get_letohl(tvb, offset); + + /* Ensure we have the bytes we need, which is up to neo */ + tvb_ensure_bytes_exist(tvb, offset, neo ? neo : *bcp); + + tree = proto_tree_add_subtree(parent_tree, tvb, offset, *bcp, ett_smb_ff2_data, &item, + val_to_str(si->info_level, ff2_il_vals, "Unknown (0x%02x)")); + + /* + * XXX - I have not seen any of these that contain a resume + * key, even though some of the requests had the "return resume + * key" flag set. + */ + + CHECK_BYTE_COUNT_SUBR(4); + proto_tree_add_uint(tree, hf_smb_next_entry_offset, tvb, offset, 4, neo); + COUNT_BYTES_SUBR(4); + + /* file index */ + CHECK_BYTE_COUNT_SUBR(4); + proto_tree_add_item(tree, hf_smb_file_index, tvb, offset, 4, ENC_LITTLE_ENDIAN); + COUNT_BYTES_SUBR(4); + + /* dissect standard 8-byte timestamps */ + offset = dissect_smb_standard_8byte_timestamps(tvb, pinfo, tree, offset, bcp, trunc); + if (*trunc) { + return offset; + } + + /* end of file */ + CHECK_BYTE_COUNT_SUBR(8); + proto_tree_add_item(tree, hf_smb_end_of_file, tvb, offset, 8, ENC_LITTLE_ENDIAN); + COUNT_BYTES_SUBR(8); + + /* allocation size */ + CHECK_BYTE_COUNT_SUBR(8); + proto_tree_add_item(tree, hf_smb_alloc_size64, tvb, offset, 8, ENC_LITTLE_ENDIAN); + COUNT_BYTES_SUBR(8); + + /* Extended File Attributes */ + CHECK_BYTE_COUNT_SUBR(4); + offset = dissect_file_ext_attr(tvb, tree, offset); + *bcp -= 4; + + /* file name len */ + CHECK_BYTE_COUNT_SUBR(4); + fn_len = tvb_get_letohl(tvb, offset); + proto_tree_add_uint(tree, hf_smb_file_name_len, tvb, offset, 4, fn_len); + COUNT_BYTES_SUBR(4); + + /* + * EA length. + * + * XXX - in one captures, this has the topmost bit set, and the + * rest of the bits have the value 7. Is the topmost bit being + * set some indication that the value *isn't* the length of + * the EAs? + */ + CHECK_BYTE_COUNT_SUBR(4); + proto_tree_add_item(tree, hf_smb_ea_list_length, tvb, offset, 4, ENC_LITTLE_ENDIAN); + COUNT_BYTES_SUBR(4); + + /* short file name len */ + CHECK_BYTE_COUNT_SUBR(1); + sfn_len = tvb_get_guint8(tvb, offset); + proto_tree_add_uint(tree, hf_smb_short_file_name_len, tvb, offset, 1, sfn_len); + COUNT_BYTES_SUBR(1); + + /* reserved byte */ + CHECK_BYTE_COUNT_SUBR(1); + proto_tree_add_item(tree, hf_smb_reserved, tvb, offset, 1, ENC_NA); + COUNT_BYTES_SUBR(1); + + /* short file name - it's not always in Unicode */ + sfn = get_unicode_or_ascii_string(tvb, &offset, si->unicode, &sfn_len, FALSE, TRUE, bcp); + CHECK_STRING_SUBR(sfn); + proto_tree_add_string(tree, hf_smb_short_file_name, tvb, offset, 24, + sfn); + COUNT_BYTES_SUBR(24); + + /* reserved bytes */ + CHECK_BYTE_COUNT_SUBR(2); + proto_tree_add_item(tree, hf_smb_reserved, tvb, offset, 2, ENC_NA); + COUNT_BYTES_SUBR(2); + + /* file id */ + CHECK_BYTE_COUNT_SUBR(8); + proto_tree_add_item(tree, hf_smb_index_number, tvb, offset, 8, ENC_LITTLE_ENDIAN); + COUNT_BYTES_SUBR(8); + + /* file name */ + fn = get_unicode_or_ascii_string(tvb, &offset, si->unicode, &fn_len, FALSE, TRUE, bcp); + CHECK_STRING_SUBR(fn); + proto_tree_add_string(tree, hf_smb_file_name, tvb, offset, fn_len, + fn); + COUNT_BYTES_SUBR(fn_len); + + col_append_fstr(pinfo->cinfo, COL_INFO, " %s", + format_text(wmem_packet_scope(), (const guchar*)fn, strlen(fn))); + + /* skip to next structure */ + if (neo) { + padcnt = (old_offset + neo) - offset; + if (padcnt < 0) { + /* + * XXX - this is bogus; flag it? + */ + padcnt = 0; + } + if (padcnt != 0) { + CHECK_BYTE_COUNT_SUBR(padcnt); + COUNT_BYTES_SUBR(padcnt); + } + } + + proto_item_append_text(item, " File: %s", format_text(wmem_packet_scope(), (const guchar*)fn, strlen(fn))); + proto_item_set_len(item, offset-old_offset); + + *trunc = FALSE; + return offset; +} + +static int +dissect_4_3_4_7(tvbuff_t *tvb, packet_info *pinfo, proto_tree *parent_tree, + int offset, guint16 *bcp, gboolean *trunc, smb_info_t *si) +{ + int fn_len; + const char *fn; + int old_offset = offset; + proto_item *item; + proto_tree *tree; + guint32 neo; + int padcnt; + + DISSECTOR_ASSERT(si); + + /* + * We check this first before adding the sub-tree so things do not + * get ugly. + */ + + /* next entry offset */ + CHECK_BYTE_COUNT_SUBR(4); + neo = tvb_get_letohl(tvb, offset); + + /* Ensure we have the bytes we need, which is up to neo */ + tvb_ensure_bytes_exist(tvb, offset, neo ? neo : *bcp); + + tree = proto_tree_add_subtree(parent_tree, tvb, offset, *bcp, ett_smb_ff2_data, &item, + val_to_str(si->info_level, ff2_il_vals, "Unknown (0x%02x)")); + + /* + * We assume that the presence of a next entry offset implies the + * absence of a resume key, as appears to be the case for 4.3.4.6. + */ + + CHECK_BYTE_COUNT_SUBR(4); + proto_tree_add_uint(tree, hf_smb_next_entry_offset, tvb, offset, 4, neo); + COUNT_BYTES_SUBR(4); + + /* file index */ + CHECK_BYTE_COUNT_SUBR(4); + proto_tree_add_item(tree, hf_smb_file_index, tvb, offset, 4, ENC_LITTLE_ENDIAN); + COUNT_BYTES_SUBR(4); + + /* file name len */ + CHECK_BYTE_COUNT_SUBR(4); + fn_len = tvb_get_letohl(tvb, offset); + proto_tree_add_uint(tree, hf_smb_file_name_len, tvb, offset, 4, fn_len); + COUNT_BYTES_SUBR(4); + + /* file name */ + fn = get_unicode_or_ascii_string(tvb, &offset, si->unicode, &fn_len, FALSE, TRUE, bcp); + CHECK_STRING_SUBR(fn); + proto_tree_add_string(tree, hf_smb_file_name, tvb, offset, fn_len, + fn); + COUNT_BYTES_SUBR(fn_len); + + col_append_fstr(pinfo->cinfo, COL_INFO, " %s", + format_text(wmem_packet_scope(), (const guchar*)fn, strlen(fn))); + + /* skip to next structure */ + if (neo) { + padcnt = (old_offset + neo) - offset; + if (padcnt < 0) { + /* + * XXX - this is bogus; flag it? + */ + padcnt = 0; + } + if (padcnt != 0) { + CHECK_BYTE_COUNT_SUBR(padcnt); + COUNT_BYTES_SUBR(padcnt); + } + } + + proto_item_append_text(item, " File: %s", format_text(wmem_packet_scope(), (const guchar*)fn, strlen(fn))); + proto_item_set_len(item, offset-old_offset); + + *trunc = FALSE; + return offset; +} + +/* 4.3.4.8 - SMB_FIND_FILE_UNIX */ + +static int +dissect_4_3_4_8(tvbuff_t *tvb, packet_info *pinfo, + proto_tree *tree, int offset, guint16 *bcp, + gboolean *trunc, smb_info_t *si) +{ + const char *fn; + int fn_len; + int pad; + + DISSECTOR_ASSERT(si); + + /* NextEntryOffset */ + CHECK_BYTE_COUNT_SUBR(4); + proto_tree_add_item(tree, hf_smb_unix_find_file_nextoffset, tvb, offset, 4, ENC_LITTLE_ENDIAN); + COUNT_BYTES_SUBR(4); + + /* ResumeKey */ + CHECK_BYTE_COUNT_SUBR(4); + proto_tree_add_item(tree, hf_smb_unix_find_file_resumekey, tvb, offset, 4, ENC_LITTLE_ENDIAN); + COUNT_BYTES_SUBR(4); + + /* Unix basic info */ + offset = dissect_4_2_16_12(tvb, pinfo, tree, offset, bcp, trunc); + if (*trunc) + return offset; + + /* Name */ + + fn = get_unicode_or_ascii_string( + tvb, &offset, si->unicode, &fn_len, FALSE, FALSE, bcp); + + CHECK_STRING_SUBR(fn); + proto_tree_add_string( + tree, hf_smb_unix_file_name, tvb, offset, fn_len, fn); + COUNT_BYTES_SUBR(fn_len); + + /* Pad to 4 bytes */ + + if (offset % 4) { + pad = 4 - (offset % 4); + COUNT_BYTES_SUBR(pad); + } + + *trunc = FALSE; + return offset; +} + +static int +dissect_find_file_unix_info2(tvbuff_t *tvb, packet_info *pinfo, + proto_tree *tree, int offset, guint16 *bcp, + gboolean *trunc, smb_info_t *si) +{ + const char *fn; + guint32 namelen; + int fn_len; + int pad; + + DISSECTOR_ASSERT(si); + + /* NextEntryOffset */ + CHECK_BYTE_COUNT_SUBR(4); + proto_tree_add_item(tree, hf_smb_unix_find_file_nextoffset, tvb, offset, 4, ENC_LITTLE_ENDIAN); + COUNT_BYTES_SUBR(4); + + /* ResumeKey */ + CHECK_BYTE_COUNT_SUBR(4); + proto_tree_add_item(tree, hf_smb_unix_find_file_resumekey, tvb, offset, 4, ENC_LITTLE_ENDIAN); + COUNT_BYTES_SUBR(4); + + /* Unix Info2 */ + offset = dissect_qspi_unix_info2(tvb, pinfo, tree, offset, bcp, trunc); + if (*trunc) + return offset; + + /* Name length */ + CHECK_BYTE_COUNT_SUBR(4); + namelen = tvb_get_letohl(tvb, offset); + proto_tree_add_uint(tree, hf_smb_unix_file_name_length, tvb, offset, 4, namelen); + COUNT_BYTES_SUBR(4); + + /* Name */ + + /* + * namelen could be > 2^31-1; this will catch that. + * The length argument to get_unicode_or_ascii_string() is an + * int, not an unsigned int, so we have to worry about that. + */ + tvb_ensure_bytes_exist(tvb, offset, namelen); + fn_len = namelen; + fn = get_unicode_or_ascii_string( + tvb, &offset, si->unicode, &fn_len, TRUE, TRUE, bcp); + + CHECK_STRING_SUBR(fn); + proto_tree_add_string( + tree, hf_smb_unix_file_name, tvb, offset, fn_len, fn); + COUNT_BYTES_SUBR(fn_len); + + /* Pad to 4 bytes */ + + if (offset % 4) { + pad = 4 - (offset % 4); + CHECK_BYTE_COUNT_SUBR(pad); + COUNT_BYTES_SUBR(pad); + } + + *trunc = FALSE; + return offset; +} + +/*dissect the data block for TRANS2_FIND_FIRST2*/ +static int +dissect_ff2_response_data(tvbuff_t * tvb, packet_info * pinfo, + proto_tree * tree, int offset, guint16 *bcp, gboolean *trunc, smb_info_t *si) +{ + if (!*bcp) { + *trunc = FALSE; + return offset; + } + + DISSECTOR_ASSERT(si); + + switch(si->info_level) { + case 1: /*Info Standard*/ + offset = dissect_4_3_4_1(tvb, pinfo, tree, offset, bcp, + trunc, si); + break; + case 2: /*Info Query EA Size*/ + offset = dissect_4_3_4_2(tvb, pinfo, tree, offset, bcp, + trunc, si); + break; + case 3: /* Info Query EAs From List same as + * InfoQueryEASize. + * Not according to MS-CIFS 2.2.8.1.3. RJS + */ + offset = dissect_4_3_4_3(tvb, pinfo, tree, offset, bcp, + trunc, si); + break; + case 0x0101: /*Find File Directory Info*/ + offset = dissect_4_3_4_4(tvb, pinfo, tree, offset, bcp, + trunc, si); + break; + case 0x0102: /*Find File Full Directory Info*/ + offset = dissect_4_3_4_5(tvb, pinfo, tree, offset, bcp, + trunc, si); + break; + case 0x0103: /*Find File Names Info*/ + offset = dissect_4_3_4_7(tvb, pinfo, tree, offset, bcp, + trunc, si); + break; + case 0x0104: /*Find File Both Directory Info*/ + offset = dissect_4_3_4_6(tvb, pinfo, tree, offset, bcp, + trunc, si); + break; + case 0x0105: /*Find File Full Directory Info*/ + offset = dissect_4_3_4_6full(tvb, pinfo, tree, offset, bcp, + trunc, si); + break; + case 0x0106: /*Find File Id Both Directory Info*/ + offset = dissect_4_3_4_6_id_both(tvb, pinfo, tree, offset, bcp, + trunc, si); + break; + case 0x0202: /*Find File Unix*/ + offset = dissect_4_3_4_8(tvb, pinfo, tree, offset, bcp, + trunc, si); + break; + case 0x020B: /*Find File Unix Info2*/ + offset = dissect_find_file_unix_info2(tvb, pinfo, tree, offset, bcp, + trunc, si); + break; + default: /* unknown info level */ + *trunc = FALSE; + break; + } + return offset; +} + + +/* is this one just wrong and should be dissect_fs0105_attributes above ? */ +static int +dissect_fs_attributes(tvbuff_t *tvb, proto_tree *parent_tree, int offset) +{ + static int * const flags[] = { + /* case sensitive search */ + &hf_smb_fs_attr_css, + /* case preserved names */ + &hf_smb_fs_attr_cpn, + /* unicode on disk */ + &hf_smb_fs_attr_uod, + /* persistent acls */ + &hf_smb_fs_attr_pacls, + /* file compression */ + &hf_smb_fs_attr_fc, + /* volume quotas */ + &hf_smb_fs_attr_vq, + /* sparse files */ + &hf_smb_fs_attr_ssf, + /* reparse points */ + &hf_smb_fs_attr_srp, + /* remote storage */ + &hf_smb_fs_attr_srs, + /* lfn apis */ + &hf_smb_fs_attr_sla, + /* volume is compressed */ + &hf_smb_fs_attr_vic, + /* support oids */ + &hf_smb_fs_attr_soids, + /* encryption */ + &hf_smb_fs_attr_se, + /* named streams */ + &hf_smb_fs_attr_ns, + /* read only volume */ + &hf_smb_fs_attr_rov, + /* sequential write once */ + &hf_smb_fs_attr_swo, + /* supports transactions */ + &hf_smb_fs_attr_st, + /* supports hard links */ + &hf_smb_fs_attr_shl, + /* supports integrity streams */ + &hf_smb_fs_attr_sis, + /* supports block refcounting */ + &hf_smb_fs_attr_sbr, + /* supports sparse vdl */ + &hf_smb_fs_attr_ssv, + NULL + }; + + proto_tree_add_bitmask(parent_tree, tvb, offset, hf_smb_fs_attr, ett_smb_fs_attributes, flags, ENC_LITTLE_ENDIAN); + offset += 4; + + return offset; +} + + +static int +dissect_device_characteristics(tvbuff_t *tvb, proto_tree *parent_tree, int offset) +{ + static int * const mask[] = { + &hf_smb_device_char_removable, + &hf_smb_device_char_read_only, + &hf_smb_device_char_floppy, + &hf_smb_device_char_write_once, + &hf_smb_device_char_remote, + &hf_smb_device_char_mounted, + &hf_smb_device_char_virtual, + &hf_smb_device_char_secure_open, + &hf_smb_device_char_ts, + &hf_smb_device_char_webdav, + &hf_smb_device_char_portable, + &hf_smb_device_char_aat, + NULL + }; + + proto_tree_add_bitmask_with_flags(parent_tree, tvb, offset, hf_smb_device_char, + ett_smb_device_characteristics, mask, ENC_LITTLE_ENDIAN, BMT_NO_APPEND); + + offset += 4; + return offset; +} + +/*dissect the data block for TRANS2_QUERY_FS_INFORMATION*/ + +static const true_false_string tfs_smb_mac_access_ctrl = { + "Macintosh Access Control Supported", + "Macintosh Access Control Not Supported" +}; + +static const true_false_string tfs_smb_mac_getset_comments = { + "Macintosh Get & Set Comments Supported", + "Macintosh Get & Set Comments Not Supported" +}; + +static const true_false_string tfs_smb_mac_desktopdb_calls = { + "Macintosh Get & Set Desktop Database Info Supported", + "Macintosh Get & Set Desktop Database Info Not Supported" +}; + +static const true_false_string tfs_smb_mac_unique_ids = { + "Macintosh Unique IDs Supported", + "Macintosh Unique IDs Not Supported" +}; + +static const true_false_string tfs_smb_mac_streams = { + "Macintosh and Streams Extensions Not Supported", + "Macintosh and Streams Extensions Supported" +}; + +int +dissect_qfsi_FS_VOLUME_INFO(tvbuff_t * tvb, packet_info * pinfo _U_, proto_tree * tree, int offset, guint16 *bcp, int unicode) +{ + int fn_len, vll; + const char *fn; + + /* create time */ + CHECK_BYTE_COUNT_TRANS_SUBR(8); + offset = dissect_nt_64bit_time(tvb, tree, offset, + hf_smb_create_time); + *bcp -= 8; + + /* volume serial number */ + CHECK_BYTE_COUNT_TRANS_SUBR(4); + proto_tree_add_item(tree, hf_smb_volume_serial_num, tvb, offset, 4, ENC_LITTLE_ENDIAN); + COUNT_BYTES_TRANS_SUBR(4); + + /* volume label length */ + CHECK_BYTE_COUNT_TRANS_SUBR(4); + vll = tvb_get_letohl(tvb, offset); + proto_tree_add_uint(tree, hf_smb_volume_label_len, tvb, offset, 4, vll); + COUNT_BYTES_TRANS_SUBR(4); + + /* 2 reserved bytes */ + CHECK_BYTE_COUNT_TRANS_SUBR(2); + proto_tree_add_item(tree, hf_smb_reserved, tvb, offset, 2, ENC_NA); + COUNT_BYTES_TRANS_SUBR(2); + + /* label */ + fn_len = vll; + fn = get_unicode_or_ascii_string(tvb, &offset, unicode, &fn_len, FALSE, TRUE, bcp); + CHECK_STRING_TRANS_SUBR(fn); + proto_tree_add_string(tree, hf_smb_volume_label, tvb, offset, fn_len, + fn); + COUNT_BYTES_TRANS_SUBR(fn_len); + + return offset; +} + +int +dissect_qfsi_FS_SIZE_INFO(tvbuff_t * tvb, packet_info * pinfo _U_, proto_tree * tree, int offset, guint16 *bcp) +{ + /* allocation size */ + CHECK_BYTE_COUNT_TRANS_SUBR(8); + proto_tree_add_item(tree, hf_smb_alloc_size64, tvb, offset, 8, ENC_LITTLE_ENDIAN); + COUNT_BYTES_TRANS_SUBR(8); + + /* free allocation units */ + CHECK_BYTE_COUNT_TRANS_SUBR(8); + proto_tree_add_item(tree, hf_smb_free_alloc_units64, tvb, offset, 8, ENC_LITTLE_ENDIAN); + COUNT_BYTES_TRANS_SUBR(8); + + /* sectors per unit */ + CHECK_BYTE_COUNT_TRANS_SUBR(4); + proto_tree_add_item(tree, hf_smb_sector_unit, tvb, offset, 4, ENC_LITTLE_ENDIAN); + COUNT_BYTES_TRANS_SUBR(4); + + /* bytes per sector */ + CHECK_BYTE_COUNT_TRANS_SUBR(4); + proto_tree_add_item(tree, hf_smb_fs_sector, tvb, offset, 4, ENC_LITTLE_ENDIAN); + COUNT_BYTES_TRANS_SUBR(4); + + return offset; +} + +int +dissect_qfsi_FS_DEVICE_INFO(tvbuff_t * tvb, packet_info * pinfo _U_, proto_tree * tree, int offset, guint16 *bcp) +{ + /* device type */ + CHECK_BYTE_COUNT_TRANS_SUBR(4); + proto_tree_add_item(tree, hf_smb_device_type, tvb, offset, 4, ENC_LITTLE_ENDIAN); + COUNT_BYTES_TRANS_SUBR(4); + + /* device characteristics */ + CHECK_BYTE_COUNT_TRANS_SUBR(4); + offset = dissect_device_characteristics(tvb, tree, offset); + *bcp -= 4; + + return offset; +} + +int +dissect_qfsi_FS_ATTRIBUTE_INFO(tvbuff_t * tvb, packet_info * pinfo _U_, proto_tree * tree, int offset, guint16 *bcp) +{ + int fn_len, fnl; + const char *fn; + + /* FS attributes */ + CHECK_BYTE_COUNT_TRANS_SUBR(4); + offset = dissect_fs_attributes(tvb, tree, offset); + *bcp -= 4; + + /* max name len */ + CHECK_BYTE_COUNT_TRANS_SUBR(4); + proto_tree_add_item(tree, hf_smb_max_name_len, tvb, offset, 4, ENC_LITTLE_ENDIAN); + COUNT_BYTES_TRANS_SUBR(4); + + /* fs name length */ + CHECK_BYTE_COUNT_TRANS_SUBR(4); + fnl = tvb_get_letohl(tvb, offset); + proto_tree_add_uint(tree, hf_smb_fs_name_len, tvb, offset, 4, fnl); + COUNT_BYTES_TRANS_SUBR(4); + + /* label */ + fn_len = fnl; + fn = get_unicode_or_ascii_string(tvb, &offset, TRUE, &fn_len, FALSE, TRUE, bcp); + CHECK_STRING_TRANS_SUBR(fn); + proto_tree_add_string(tree, hf_smb_fs_name, tvb, offset, fn_len, + fn); + COUNT_BYTES_TRANS_SUBR(fn_len); + + return offset; +} + +int +dissect_qfsi_FS_OBJECTID_INFO(tvbuff_t * tvb, packet_info * pinfo, proto_tree * tree, int offset, guint16 *bcp) +{ + CHECK_BYTE_COUNT_TRANS_SUBR(64); + + dissect_smb2_FILE_OBJECTID_BUFFER(tvb, pinfo, tree, offset); + + COUNT_BYTES_TRANS_SUBR(64); + + return offset; +} + +int +dissect_qfsi_FS_FULL_SIZE_INFO(tvbuff_t * tvb, packet_info * pinfo _U_, proto_tree * tree, int offset, guint16 *bcp) +{ + /* allocation size */ + CHECK_BYTE_COUNT_TRANS_SUBR(8); + proto_tree_add_item(tree, hf_smb_alloc_size64, tvb, offset, 8, ENC_LITTLE_ENDIAN); + COUNT_BYTES_TRANS_SUBR(8); + + /* caller free allocation units */ + CHECK_BYTE_COUNT_TRANS_SUBR(8); + proto_tree_add_item(tree, hf_smb_caller_free_alloc_units64, tvb, offset, 8, ENC_LITTLE_ENDIAN); + COUNT_BYTES_TRANS_SUBR(8); + + /* actual free allocation units */ + CHECK_BYTE_COUNT_TRANS_SUBR(8); + proto_tree_add_item(tree, hf_smb_actual_free_alloc_units64, tvb, offset, 8, ENC_LITTLE_ENDIAN); + COUNT_BYTES_TRANS_SUBR(8); + + /* sectors per unit */ + CHECK_BYTE_COUNT_TRANS_SUBR(4); + proto_tree_add_item(tree, hf_smb_sector_unit, tvb, offset, 4, ENC_LITTLE_ENDIAN); + COUNT_BYTES_TRANS_SUBR(4); + + /* bytes per sector */ + CHECK_BYTE_COUNT_TRANS_SUBR(4); + proto_tree_add_item(tree, hf_smb_fs_sector, tvb, offset, 4, ENC_LITTLE_ENDIAN); + COUNT_BYTES_TRANS_SUBR(4); + + return offset; +} + +static int +dissect_qfsi_vals(tvbuff_t * tvb, packet_info * pinfo, proto_tree * tree, + int offset, guint16 *bcp, smb_info_t *si) +{ + int fn_len, vll; + const char *fn; + + if (!*bcp) { + return offset; + } + + DISSECTOR_ASSERT(si); + + switch(si->info_level) { + case 1: /* SMB_INFO_ALLOCATION */ + /* filesystem id */ + CHECK_BYTE_COUNT_TRANS_SUBR(4); + proto_tree_add_item(tree, hf_smb_fs_id, tvb, offset, 4, ENC_LITTLE_ENDIAN); + COUNT_BYTES_TRANS_SUBR(4); + + /* sectors per unit */ + CHECK_BYTE_COUNT_TRANS_SUBR(4); + proto_tree_add_item(tree, hf_smb_sector_unit, tvb, offset, 4, ENC_LITTLE_ENDIAN); + COUNT_BYTES_TRANS_SUBR(4); + + /* units */ + CHECK_BYTE_COUNT_TRANS_SUBR(4); + proto_tree_add_item(tree, hf_smb_fs_units, tvb, offset, 4, ENC_LITTLE_ENDIAN); + COUNT_BYTES_TRANS_SUBR(4); + + /* avail units */ + CHECK_BYTE_COUNT_TRANS_SUBR(4); + proto_tree_add_item(tree, hf_smb_avail_units, tvb, offset, 4, ENC_LITTLE_ENDIAN); + COUNT_BYTES_TRANS_SUBR(4); + + /* bytes per sector, only 16bit integer here */ + CHECK_BYTE_COUNT_TRANS_SUBR(2); + proto_tree_add_item(tree, hf_smb_fs_sector, tvb, offset, 2, ENC_LITTLE_ENDIAN); + COUNT_BYTES_TRANS_SUBR(2); + + break; + case 2: /* SMB_INFO_VOLUME */ + /* volume serial number */ + CHECK_BYTE_COUNT_TRANS_SUBR(4); + proto_tree_add_item(tree, hf_smb_volume_serial_num, tvb, offset, 4, ENC_LITTLE_ENDIAN); + COUNT_BYTES_TRANS_SUBR(4); + + /* volume label length, only one byte here */ + CHECK_BYTE_COUNT_TRANS_SUBR(1); + proto_tree_add_item(tree, hf_smb_volume_label_len, tvb, offset, 1, ENC_NA); + COUNT_BYTES_TRANS_SUBR(1); + + /* label - not aligned! */ + fn = get_unicode_or_ascii_string(tvb, &offset, si->unicode, &fn_len, TRUE, FALSE, bcp); + CHECK_STRING_TRANS_SUBR(fn); + proto_tree_add_string(tree, hf_smb_volume_label, tvb, offset, fn_len, + fn); + COUNT_BYTES_TRANS_SUBR(fn_len); + + break; + case 0x0101: /* SMB_QUERY_FS_LABEL_INFO */ + case 1002: /* SMB_FS_LABEL_INFORMATION */ + /* volume label length */ + CHECK_BYTE_COUNT_TRANS_SUBR(4); + vll = tvb_get_letohl(tvb, offset); + proto_tree_add_uint(tree, hf_smb_volume_label_len, tvb, offset, 4, vll); + COUNT_BYTES_TRANS_SUBR(4); + + /* label */ + fn_len = vll; + fn = get_unicode_or_ascii_string(tvb, &offset, si->unicode, &fn_len, FALSE, TRUE, bcp); + CHECK_STRING_TRANS_SUBR(fn); + proto_tree_add_string(tree, hf_smb_volume_label, tvb, offset, fn_len, + fn); + COUNT_BYTES_TRANS_SUBR(fn_len); + + break; + case 0x0102: /* SMB_QUERY_FS_VOLUME_INFO */ + case 1001: /* SMB_FS_VOLUME_INFORMATION */ + offset = dissect_qfsi_FS_VOLUME_INFO(tvb, pinfo, tree, offset, bcp, si->unicode); + break; + case 0x0103: /* SMB_QUERY_FS_SIZE_INFO */ + case 1003: /* SMB_FS_SIZE_INFORMATION */ + offset = dissect_qfsi_FS_SIZE_INFO(tvb, pinfo, tree, offset, bcp); + break; + case 0x0104: /* SMB_QUERY_FS_DEVICE_INFO */ + case 1004: /* SMB_FS_DEVICE_INFORMATION */ + offset = dissect_qfsi_FS_DEVICE_INFO(tvb, pinfo, tree, offset, bcp); + break; + case 0x0105: /* SMB_QUERY_FS_ATTRIBUTE_INFO */ + case 1005: /* SMB_FS_ATTRIBUTE_INFORMATION */ + offset = dissect_qfsi_FS_ATTRIBUTE_INFO(tvb, pinfo, tree, offset, bcp); + break; + case 0x200: { /* SMB_QUERY_CIFS_UNIX_INFO */ + proto_item *item_2 = NULL; + proto_tree *subtree = NULL; + + /* MajorVersionNumber */ + CHECK_BYTE_COUNT_TRANS_SUBR(2); + proto_tree_add_item(tree, hf_smb_unix_major_version, tvb, offset, 2, ENC_LITTLE_ENDIAN); + COUNT_BYTES_TRANS_SUBR(2); + + /* MinorVersionNumber */ + CHECK_BYTE_COUNT_TRANS_SUBR(2); + proto_tree_add_item(tree, hf_smb_unix_minor_version, tvb, offset, 2, ENC_LITTLE_ENDIAN); + COUNT_BYTES_TRANS_SUBR(2); + + /* Capability */ + + CHECK_BYTE_COUNT_TRANS_SUBR(8); + + if (tree) { + item_2 = proto_tree_add_item(tree, hf_smb_unix_capability, tvb, offset, 8, ENC_LITTLE_ENDIAN); + subtree = proto_item_add_subtree( + item_2, ett_smb_unix_capabilities); + } + + proto_tree_add_item( + subtree, hf_smb_unix_capability_fcntl, tvb, offset, 4, + ENC_LITTLE_ENDIAN); + + proto_tree_add_item( + subtree, hf_smb_unix_capability_posix_acl, tvb, offset, 4, + ENC_LITTLE_ENDIAN); + + proto_tree_add_item( + subtree, hf_smb_unix_capability_xattr, tvb, offset, 4, + ENC_LITTLE_ENDIAN); + + proto_tree_add_item( + subtree, hf_smb_unix_capability_attr, tvb, offset, 4, + ENC_LITTLE_ENDIAN); + + proto_tree_add_item( + subtree, hf_smb_unix_capability_posix_paths, tvb, offset, 4, + ENC_LITTLE_ENDIAN); + + proto_tree_add_item( + subtree, hf_smb_unix_capability_posix_path_ops, tvb, offset, 4, + ENC_LITTLE_ENDIAN); + + proto_tree_add_item( + subtree, hf_smb_unix_capability_large_read, tvb, offset, 4, + ENC_LITTLE_ENDIAN); + + proto_tree_add_item( + subtree, hf_smb_unix_capability_large_write, tvb, offset, 4, + ENC_LITTLE_ENDIAN); + + proto_tree_add_item( + subtree, hf_smb_unix_capability_encryption, tvb, offset, 4, + ENC_LITTLE_ENDIAN); + + proto_tree_add_item( + subtree, hf_smb_unix_capability_mandatory_crypto, tvb, offset, 4, + ENC_LITTLE_ENDIAN); + + proto_tree_add_item( + subtree, hf_smb_unix_capability_proxy, tvb, offset, 4, + ENC_LITTLE_ENDIAN); + + COUNT_BYTES_TRANS_SUBR(8); + + break; + } + + case 0x202: { /* SMB_QUERY_POSIX_WHOAMI */ + proto_tree *st_gids; + guint32 num_gids; + guint i; + proto_tree *st_sids; + int old_sid_offset; + guint32 num_sids; + guint32 sids_buflen; + + /* Mapping flags */ + CHECK_BYTE_COUNT_TRANS_SUBR(4); + proto_tree_add_item(tree, hf_smb_unix_whoami_mapflags, + tvb, offset, 4, ENC_LITTLE_ENDIAN); + COUNT_BYTES_TRANS_SUBR(4); + + /* Mapping flags mask */ + CHECK_BYTE_COUNT_TRANS_SUBR(4); + proto_tree_add_item(tree, hf_smb_unix_whoami_mapflags_mask, + tvb, offset, 4, ENC_LITTLE_ENDIAN); + COUNT_BYTES_TRANS_SUBR(4); + + /* primary UID */ + CHECK_BYTE_COUNT_TRANS_SUBR(8); + proto_tree_add_item(tree, hf_smb_unix_file_uid, + tvb, offset, 8, ENC_LITTLE_ENDIAN); + COUNT_BYTES_TRANS_SUBR(8); + + /* primary GID */ + CHECK_BYTE_COUNT_TRANS_SUBR(8); + proto_tree_add_item(tree, hf_smb_unix_file_gid, + tvb, offset, 8, ENC_LITTLE_ENDIAN); + COUNT_BYTES_TRANS_SUBR(8); + + /* number of supplementary GIDs */ + CHECK_BYTE_COUNT_TRANS_SUBR(4); + num_gids = tvb_get_letohl(tvb, offset); + proto_tree_add_item(tree, hf_smb_unix_whoami_num_supl_gids, + tvb, offset, 4, ENC_LITTLE_ENDIAN); + COUNT_BYTES_TRANS_SUBR(4); + + /* number of supplementary SIDs */ + CHECK_BYTE_COUNT_TRANS_SUBR(4); + num_sids = tvb_get_letohl(tvb, offset); + proto_tree_add_item(tree, hf_smb_unix_whoami_num_supl_sids, + tvb, offset, 4, ENC_LITTLE_ENDIAN); + COUNT_BYTES_TRANS_SUBR(4); + + /* supplementary SIDs buffer length */ + CHECK_BYTE_COUNT_TRANS_SUBR(4); + sids_buflen = tvb_get_letohl(tvb, offset); + proto_tree_add_item(tree, hf_smb_unix_whoami_sids_buflen, + tvb, offset, 4, ENC_LITTLE_ENDIAN); + COUNT_BYTES_TRANS_SUBR(4); + + /* pad / reserved (must be zero) */ + CHECK_BYTE_COUNT_TRANS_SUBR(4); + proto_tree_add_item(tree, hf_smb_reserved, tvb, offset, 4, ENC_NA); + COUNT_BYTES_TRANS_SUBR(4); + + + /* GIDs */ + st_gids = proto_tree_add_subtree(tree, tvb, offset, num_gids * 8, + ett_smb_unix_whoami_gids, NULL, "Supplementary UNIX GIDs"); + + for (i = 0; i < num_gids; i++) { + CHECK_BYTE_COUNT_TRANS_SUBR(8); + proto_tree_add_item(st_gids, hf_smb_unix_file_gid, + tvb, offset, 8, ENC_LITTLE_ENDIAN); + COUNT_BYTES_TRANS_SUBR(8); + } + + /* SIDs */ + st_sids = proto_tree_add_subtree(tree, tvb, offset, sids_buflen, + ett_smb_unix_whoami_sids, NULL, "List of SIDs"); + + for (i = 0; i < num_sids; i++) { + old_sid_offset = offset; + offset = dissect_nt_sid(tvb, offset, st_sids, "SID", NULL, -1); + CHECK_BYTE_COUNT_TRANS_SUBR(offset-old_sid_offset); + *bcp -= (offset - old_sid_offset); + } + + break; + } + + case 0x301: { /* MAC_QUERY_FS_INFO */ + static int * const support_flags[] = { + &hf_smb_mac_sup_access_ctrl, + &hf_smb_mac_sup_getset_comments, + &hf_smb_mac_sup_desktopdb_calls, + &hf_smb_mac_sup_unique_ids, + &hf_smb_mac_sup_streams, + NULL + }; + + /* Create time */ + CHECK_BYTE_COUNT_TRANS_SUBR(8); + offset = dissect_nt_64bit_time(tvb, tree, offset, hf_smb_create_time); + *bcp -= 8; + /* Modify Time */ + CHECK_BYTE_COUNT_TRANS_SUBR(8); + offset = dissect_nt_64bit_time(tvb, tree, offset, hf_smb_modify_time); + *bcp -= 8; + /* Backup Time */ + CHECK_BYTE_COUNT_TRANS_SUBR(8); + offset = dissect_nt_64bit_time(tvb, tree, offset, hf_smb_backup_time); + *bcp -= 8; + /* Allocation blocks */ + CHECK_BYTE_COUNT_TRANS_SUBR(4); + proto_tree_add_item(tree, hf_smb_mac_alloc_block_count, tvb, + offset, + 4, ENC_LITTLE_ENDIAN); + COUNT_BYTES_TRANS_SUBR(4); + /* Allocation Block Size */ + CHECK_BYTE_COUNT_TRANS_SUBR(4); + proto_tree_add_item(tree, hf_smb_mac_alloc_block_size, tvb, + offset, 4, ENC_LITTLE_ENDIAN); + COUNT_BYTES_TRANS_SUBR(4); + /* Free Block Count */ + CHECK_BYTE_COUNT_TRANS_SUBR(4); + proto_tree_add_item(tree, hf_smb_mac_free_block_count, tvb, + offset, 4, ENC_LITTLE_ENDIAN); + COUNT_BYTES_TRANS_SUBR(4); + /* Finder Info ... */ + CHECK_BYTE_COUNT_TRANS_SUBR(32); + proto_tree_add_bytes_format_value(tree, hf_smb_mac_fndrinfo, tvb, + offset, 32, NULL, + "%s", + tvb_format_text(pinfo->pool, tvb, offset, 32)); + COUNT_BYTES_TRANS_SUBR(32); + /* Number Files */ + CHECK_BYTE_COUNT_TRANS_SUBR(4); + proto_tree_add_item(tree, hf_smb_mac_root_file_count, tvb, + offset, 4, ENC_LITTLE_ENDIAN); + COUNT_BYTES_TRANS_SUBR(4); + /* Number of Root Directories */ + CHECK_BYTE_COUNT_TRANS_SUBR(4); + proto_tree_add_item(tree, hf_smb_mac_root_dir_count, tvb, + offset, 4, ENC_LITTLE_ENDIAN); + COUNT_BYTES_TRANS_SUBR(4); + /* Number of files */ + CHECK_BYTE_COUNT_TRANS_SUBR(4); + proto_tree_add_item(tree, hf_smb_mac_file_count, tvb, + offset, 4, ENC_LITTLE_ENDIAN); + COUNT_BYTES_TRANS_SUBR(4); + /* Dir Count */ + CHECK_BYTE_COUNT_TRANS_SUBR(4); + proto_tree_add_item(tree, hf_smb_mac_dir_count, tvb, + offset, 4, ENC_LITTLE_ENDIAN); + COUNT_BYTES_TRANS_SUBR(4); + /* Mac Support Flags */ + CHECK_BYTE_COUNT_TRANS_SUBR(4); + proto_tree_add_bitmask(tree, tvb, offset, hf_smb_mac_sup, ett_smb_mac_support_flags, support_flags, ENC_LITTLE_ENDIAN); + COUNT_BYTES_TRANS_SUBR(4); + break; + } + case 1006: /* QUERY_FS_QUOTA_INFO */ + offset = dissect_nt_quota(tvb, tree, offset, bcp); + break; + case 1007: /* SMB_FS_FULL_SIZE_INFORMATION */ + offset = dissect_qfsi_FS_FULL_SIZE_INFO(tvb, pinfo, tree, offset, bcp); + break; + case 1008: /* Query Object ID */ { + offset = dissect_qfsi_FS_OBJECTID_INFO(tvb, pinfo, tree, offset, bcp); + break; + } + } + + return offset; +} + +static int +dissect_transaction2_response_data(tvbuff_t *tvb, packet_info *pinfo, + proto_tree *parent_tree, smb_info_t *si) +{ + proto_item *item = NULL; + proto_tree *tree = NULL; + smb_transact2_info_t *t2i; + int count; + gboolean trunc = FALSE; + int offset = 0; + guint16 dc; + + dc = tvb_reported_length(tvb); + + DISSECTOR_ASSERT(si); + + if ((si->sip != NULL) && (si->sip->extra_info_type == SMB_EI_T2I)) + t2i = (smb_transact2_info_t *)si->sip->extra_info; + else + t2i = NULL; + + if (parent_tree) { + if ((t2i != NULL) && (t2i->subcmd != -1)) { + tree = proto_tree_add_subtree_format(parent_tree, tvb, offset, dc, + ett_smb_transaction_data, &item, "%s Data", + val_to_str_ext(t2i->subcmd, &trans2_cmd_vals_ext, + "Unknown (0x%02x)")); + } else { + tree = proto_tree_add_subtree(parent_tree, tvb, offset, dc, + ett_smb_transaction_data, &item, "Unknown Transaction2 Data"); + } + } + + if (t2i == NULL) { + offset += dc; + return offset; + } + switch(t2i->subcmd) { + case 0x0000: /*TRANS2_OPEN2*/ + /* XXX not implemented yet. See SNIA doc */ + break; + case 0x0001: /*TRANS2_FIND_FIRST2*/ + /* returned data */ + count = si->info_count; + + if (count == -1) { + break; + } + + if (count) { + col_append_str(pinfo->cinfo, COL_INFO, + ", Files:"); + } + + while (count--) { + offset = dissect_ff2_response_data(tvb, pinfo, tree, + offset, &dc, &trunc, si); + if (trunc) + break; + } + break; + case 0x0002: /*TRANS2_FIND_NEXT2*/ + /* returned data */ + count = si->info_count; + + if (count == -1) { + break; + } + if (count) { + col_append_str(pinfo->cinfo, COL_INFO, + ", Files:"); + } + + while (count--) { + offset = dissect_ff2_response_data(tvb, pinfo, tree, + offset, &dc, &trunc, si); + if (trunc) + break; + } + break; + case 0x0003: /*TRANS2_QUERY_FS_INFORMATION*/ + offset = dissect_qfsi_vals(tvb, pinfo, tree, offset, &dc, si); + break; + case 0x0004: /*TRANS2_SET_FS_INFORMATION*/ + offset = dissect_sfsi_response(tvb, pinfo, tree, offset, &dc, si); + break; + case 0x0005: /*TRANS2_QUERY_PATH_INFORMATION*/ + offset = dissect_qpi_loi_vals(tvb, pinfo, tree, item, offset, &dc, si); + break; + case 0x0006: /*TRANS2_SET_PATH_INFORMATION*/ + /* no data in this response */ + break; + case 0x0007: /*TRANS2_QUERY_FILE_INFORMATION*/ + /* identical to QUERY_PATH_INFO */ + offset = dissect_qpi_loi_vals(tvb, pinfo, tree, item, offset, &dc, si); + break; + case 0x0008: /*TRANS2_SET_FILE_INFORMATION*/ + /* no data in this response */ + break; + case 0x0009: /*TRANS2_FSCTL*/ + /* XXX don't know how to dissect this one (yet)*/ + + /* + * XXX - "Microsoft Networks SMB File Sharing Protocol + * Extensions Version 3.0, Document Version 1.11, + * July 19, 1990" says this contains a + * "File system specific return data block". + * (That means we may not be able to dissect it in any + * case.) + */ + break; + case 0x000a: /*TRANS2_IOCTL2*/ + /* XXX don't know how to dissect this one (yet)*/ + + /* + * XXX - "Microsoft Networks SMB File Sharing Protocol + * Extensions Version 3.0, Document Version 1.11, + * July 19, 1990" says this contains a + * "Device/function specific return data block". + * (That means we may not be able to dissect it in any + * case.) + */ + break; + case 0x000b: /*TRANS2_FIND_NOTIFY_FIRST*/ + /* XXX don't know how to dissect this one (yet)*/ + + /* + * XXX - "Microsoft Networks SMB File Sharing Protocol + * Extensions Version 3.0, Document Version 1.11, + * July 19, 1990" says this contains "the level + * dependent information about the changes which + * occurred". + */ + break; + case 0x000c: /*TRANS2_FIND_NOTIFY_NEXT*/ + /* XXX don't know how to dissect this one (yet)*/ + + /* + * XXX - "Microsoft Networks SMB File Sharing Protocol + * Extensions Version 3.0, Document Version 1.11, + * July 19, 1990" says this contains "the level + * dependent information about the changes which + * occurred". + */ + break; + case 0x000d: /*TRANS2_CREATE_DIRECTORY*/ + /* no data in this response */ + break; + case 0x000e: /*TRANS2_SESSION_SETUP*/ + /* XXX don't know how to dissect this one (yet)*/ + break; + case 0x0010: /*TRANS2_GET_DFS_REFERRAL*/ + offset = dissect_get_dfs_referral_data(tvb, pinfo, tree, offset, &dc, si->unicode); + break; + case 0x0011: /*TRANS2_REPORT_DFS_INCONSISTENCY*/ + /* the SNIA spec appears to say the response has no data */ + break; + case -1: + /* + * We don't know what the matching request was; don't + * bother putting anything else into the tree for the data. + */ + offset += dc; + dc = 0; + break; + } + + /* ooops there were data we didn't know how to process */ + if (dc != 0) { + proto_tree_add_item(tree, hf_smb_unknown, tvb, offset, dc, ENC_NA); + offset += dc; + } + + return offset; +} + + +static int +dissect_transaction2_response_parameters(tvbuff_t *tvb, packet_info *pinfo, proto_tree *parent_tree, smb_info_t *si) +{ + proto_item *item = NULL; + proto_tree *tree = NULL; + smb_transact2_info_t *t2i; + guint16 fid; + int lno; + int offset = 0; + int pc; + + pc = tvb_reported_length(tvb); + + DISSECTOR_ASSERT(si); + + if ((si->sip != NULL) && (si->sip->extra_info_type == SMB_EI_T2I)) + t2i = (smb_transact2_info_t *)si->sip->extra_info; + else + t2i = NULL; + + if (parent_tree) { + if ((t2i != NULL) && (t2i->subcmd != -1)) { + tree = proto_tree_add_subtree_format(parent_tree, tvb, offset, pc, + ett_smb_transaction_params, &item, "%s Parameters", + val_to_str_ext(t2i->subcmd, &trans2_cmd_vals_ext, + "Unknown (0x%02x)")); + } else { + tree = proto_tree_add_subtree(parent_tree, tvb, offset, pc, + ett_smb_transaction_params, &item, "Unknown Transaction2 Parameters"); + } + } + + if (t2i == NULL) { + offset += pc; + return offset; + } + switch(t2i->subcmd) { + case 0x00: /*TRANS2_OPEN2*/ + /* fid */ + fid = tvb_get_letohs(tvb, offset); + dissect_smb_fid(tvb, pinfo, tree, offset, 2, fid, TRUE, FALSE, FALSE, si); + offset += 2; + + /* + * XXX - Microsoft Networks SMB File Sharing Protocol + * Extensions Version 3.0, Document Version 1.11, + * July 19, 1990 says that the file attributes, create + * time (which it says is the last modification time), + * data size, granted access, file type, and IPC state + * are returned only if bit 0 is set in the open flags, + * and that the EA length is returned only if bit 3 + * is set in the open flags. Does that mean that, + * at least in that SMB dialect, those fields are not + * present in the reply parameters if the bits in + * question aren't set? + */ + + /* File Attributes */ + offset = dissect_file_attributes(tvb, tree, offset); + + /* create time */ + offset = dissect_smb_datetime(tvb, tree, offset, + hf_smb_create_time, + hf_smb_create_dos_date, hf_smb_create_dos_time, TRUE); + + /* data size */ + proto_tree_add_item(tree, hf_smb_data_size, tvb, offset, 4, ENC_LITTLE_ENDIAN); + offset += 4; + + /* granted access */ + offset = dissect_access(tvb, tree, offset, hf_smb_granted_access); + + /* File Type */ + proto_tree_add_item(tree, hf_smb_file_type, tvb, offset, 2, ENC_LITTLE_ENDIAN); + offset += 2; + + /* IPC State */ + offset = dissect_ipc_state(tvb, tree, offset, FALSE); + + /* open_action */ + offset = dissect_open_action(tvb, tree, offset); + + /* server unique file ID */ + proto_tree_add_item(tree, hf_smb_file_id, tvb, offset, 4, ENC_LITTLE_ENDIAN); + offset += 4; + + /* ea error offset, only a 16 bit integer here */ + proto_tree_add_item(tree, hf_smb_ea_error_offset, tvb, offset, 2, ENC_LITTLE_ENDIAN); + offset += 2; + + /* ea length */ + proto_tree_add_item(tree, hf_smb_ea_list_length, tvb, offset, 4, ENC_LITTLE_ENDIAN); + offset += 4; + + break; + case 0x01: /*TRANS2_FIND_FIRST2*/ + /* Find First2 information level */ + proto_tree_add_uint(tree, hf_smb_ff2_information_level, tvb, 0, 0, si->info_level); + + /* sid */ + proto_tree_add_item(tree, hf_smb_search_id, tvb, offset, 2, ENC_LITTLE_ENDIAN); + offset += 2; + + /* search count */ + si->info_count = tvb_get_letohs(tvb, offset); + proto_tree_add_uint(tree, hf_smb_search_count, tvb, offset, 2, si->info_count); + offset += 2; + + /* end of search */ + proto_tree_add_item(tree, hf_smb_end_of_search, tvb, offset, 2, ENC_LITTLE_ENDIAN); + offset += 2; + + /* ea error offset, only a 16 bit integer here */ + proto_tree_add_item(tree, hf_smb_ea_error_offset, tvb, offset, 2, ENC_LITTLE_ENDIAN); + offset += 2; + + /* last name offset */ + lno = tvb_get_letohs(tvb, offset); + proto_tree_add_uint(tree, hf_smb_last_name_offset, tvb, offset, 2, lno); + offset += 2; + + break; + case 0x02: /*TRANS2_FIND_NEXT2*/ + /* search count */ + si->info_count = tvb_get_letohs(tvb, offset); + proto_tree_add_uint(tree, hf_smb_search_count, tvb, offset, 2, si->info_count); + offset += 2; + + /* end of search */ + proto_tree_add_item(tree, hf_smb_end_of_search, tvb, offset, 2, ENC_LITTLE_ENDIAN); + offset += 2; + + /* ea_error_offset, only a 16 bit integer here*/ + proto_tree_add_item(tree, hf_smb_ea_error_offset, tvb, offset, 2, ENC_LITTLE_ENDIAN); + offset += 2; + + /* last name offset */ + lno = tvb_get_letohs(tvb, offset); + proto_tree_add_uint(tree, hf_smb_last_name_offset, tvb, offset, 2, lno); + offset += 2; + + break; + case 0x03: /*TRANS2_QUERY_FS_INFORMATION*/ + /* no parameter block here */ + break; + case 0x05: /*TRANS2_QUERY_PATH_INFORMATION*/ + /* ea_error_offset, only a 16 bit integer here*/ + proto_tree_add_item(tree, hf_smb_ea_error_offset, tvb, offset, 2, ENC_LITTLE_ENDIAN); + offset += 2; + + break; + case 0x06: /*TRANS2_SET_PATH_INFORMATION*/ + /* ea_error_offset, only a 16 bit integer here*/ + proto_tree_add_item(tree, hf_smb_ea_error_offset, tvb, offset, 2, ENC_LITTLE_ENDIAN); + offset += 2; + + break; + case 0x07: /*TRANS2_QUERY_FILE_INFORMATION*/ + /* ea_error_offset, only a 16 bit integer here*/ + proto_tree_add_item(tree, hf_smb_ea_error_offset, tvb, offset, 2, ENC_LITTLE_ENDIAN); + offset += 2; + + break; + case 0x08: /*TRANS2_SET_FILE_INFORMATION*/ + /* ea_error_offset, only a 16 bit integer here*/ + proto_tree_add_item(tree, hf_smb_ea_error_offset, tvb, offset, 2, ENC_LITTLE_ENDIAN); + offset += 2; + + break; + case 0x09: /*TRANS2_FSCTL*/ + /* XXX don't know how to dissect this one (yet)*/ + + /* + * XXX - "Microsoft Networks SMB File Sharing Protocol + * Extensions Version 3.0, Document Version 1.11, + * July 19, 1990" says this contains a + * "File system specific return parameter block". + * (That means we may not be able to dissect it in any + * case.) + */ + break; + case 0x0a: /*TRANS2_IOCTL2*/ + /* XXX don't know how to dissect this one (yet)*/ + + /* + * XXX - "Microsoft Networks SMB File Sharing Protocol + * Extensions Version 3.0, Document Version 1.11, + * July 19, 1990" says this contains a + * "Device/function specific return parameter block". + * (That means we may not be able to dissect it in any + * case.) + */ + break; + case 0x0b: /*TRANS2_FIND_NOTIFY_FIRST*/ + /* Find Notify information level */ + proto_tree_add_uint(tree, hf_smb_fn_information_level, tvb, 0, 0, si->info_level); + + /* Monitor handle */ + proto_tree_add_item(tree, hf_smb_monitor_handle, tvb, offset, 2, ENC_LITTLE_ENDIAN); + offset += 2; + + /* Change count */ + si->info_count = tvb_get_letohs(tvb, offset); + proto_tree_add_uint(tree, hf_smb_change_count, tvb, offset, 2, si->info_count); + offset += 2; + + /* ea_error_offset, only a 16 bit integer here*/ + proto_tree_add_item(tree, hf_smb_ea_error_offset, tvb, offset, 2, ENC_LITTLE_ENDIAN); + offset += 2; + + break; + case 0x0c: /*TRANS2_FIND_NOTIFY_NEXT*/ + /* Find Notify information level */ + proto_tree_add_uint(tree, hf_smb_fn_information_level, tvb, 0, 0, si->info_level); + + /* Change count */ + si->info_count = tvb_get_letohs(tvb, offset); + proto_tree_add_uint(tree, hf_smb_change_count, tvb, offset, 2, si->info_count); + offset += 2; + + /* ea_error_offset, only a 16 bit integer here*/ + proto_tree_add_item(tree, hf_smb_ea_error_offset, tvb, offset, 2, ENC_LITTLE_ENDIAN); + offset += 2; + + break; + case 0x0d: /*TRANS2_CREATE_DIRECTORY*/ + /* ea error offset, only a 16 bit integer here */ + proto_tree_add_item(tree, hf_smb_ea_error_offset, tvb, offset, 2, ENC_LITTLE_ENDIAN); + offset += 2; + + break; + case 0x0e: /*TRANS2_SESSION_SETUP*/ + /* XXX don't know how to dissect this one (yet)*/ + break; + case 0x10: /*TRANS2_GET_DFS_REFERRAL*/ + /* XXX don't know how to dissect this one (yet) see SNIA doc*/ + break; + case 0x11: /*TRANS2_REPORT_DFS_INCONSISTENCY*/ + /* XXX don't know how to dissect this one (yet) see SNIA doc*/ + break; + case -1: + /* + * We don't know what the matching request was; don't + * bother putting anything else into the tree for the data. + */ + offset += pc; + break; + } + + /* ooops there were data we didn't know how to process */ + if (offset < pc) { + proto_tree_add_item(tree, hf_smb_unknown, tvb, offset, pc-offset, ENC_NA); + offset += pc-offset; + } + return offset; +} + + +static int +dissect_transaction_response(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int offset, proto_tree *smb_tree _U_, smb_info_t *si) +{ + guint8 sc, wc; + guint16 od = 0, po = 0, pc = 0, pd = 0, dc = 0, dd = 0, td = 0, tp = 0; + smb_transact2_info_t *t2i = NULL; + guint16 bc; + int padcnt; + gboolean dissected_trans; + fragment_head *r_fd = NULL; + tvbuff_t *pd_tvb = NULL, *d_tvb = NULL, *p_tvb = NULL; + tvbuff_t *s_tvb = NULL, *sp_tvb = NULL; + gboolean save_fragmented; + proto_item *item; + + DISSECTOR_ASSERT(si); + + switch(si->cmd) { + case SMB_COM_TRANSACTION2: + /* transaction2 */ + if ((si->sip != NULL) && (si->sip->extra_info_type == SMB_EI_T2I)) { + t2i = (smb_transact2_info_t *)si->sip->extra_info; + } else + t2i = NULL; + if (t2i == NULL) { + /* + * We didn't see the matching request, so we don't + * know what type of transaction this is. + */ + proto_tree_add_uint_format_value(tree, hf_smb_trans2_subcmd, tvb, 0, 0, -1, + "<UNKNOWN> since request packet wasn't seen"); + col_append_str(pinfo->cinfo, COL_INFO, "<unknown>"); + } else { + si->info_level = t2i->info_level; + if (t2i->subcmd == -1) { + /* + * We didn't manage to extract the subcommand + * from the matching request (perhaps because + * the frame was short), so we don't know what + * type of transaction this is. + */ + proto_tree_add_uint_format_value(tree, hf_smb_trans2_subcmd, tvb, 0, 0, t2i->subcmd, + "<UNKNOWN> since transaction code wasn't found in request packet"); + col_append_str(pinfo->cinfo, COL_INFO, "<unknown>"); + } else { + proto_tree_add_uint(tree, hf_smb_trans2_subcmd, tvb, 0, 0, t2i->subcmd); + switch (t2i->subcmd) { + + case 0x0001: /* FIND_FIRST2 */ + if (t2i->info_level == -1) + item = proto_tree_add_uint_format_value(tree, hf_smb_ff2_information_level, tvb, 0, 0, t2i->info_level, + "<UNKNOWN> since information level wasn't found in request packet"); + else + item = proto_tree_add_uint(tree, hf_smb_ff2_information_level, tvb, 0, 0, t2i->info_level); + proto_item_set_generated(item); + if (t2i->name) { + item = proto_tree_add_string(tree, hf_smb_search_pattern, tvb, 0, 0, t2i->name); + proto_item_set_generated(item); + } + break; + + case 0x0005: /* QUERY_PATH_INFORMATION */ + if (t2i->info_level == -1) + item = proto_tree_add_uint_format_value(tree, hf_smb_qpi_loi, tvb, 0, 0, t2i->info_level, + "<UNKNOWN> since information level wasn't found in request packet"); + else + item = proto_tree_add_uint(tree, hf_smb_qpi_loi, tvb, 0, 0, t2i->info_level); + proto_item_set_generated(item); + if (t2i->name) { + item = proto_tree_add_string(tree, hf_smb_file_name, tvb, 0, 0, t2i->name); + proto_item_set_generated(item); + } + break; + + case 0x0007: /* QUERY_FILE_INFORMATION */ + if (t2i->info_level == -1) + item = proto_tree_add_uint_format_value(tree, hf_smb_qpi_loi, tvb, 0, 0, t2i->info_level, + "<UNKNOWN> since information level wasn't found in request packet"); + else + item = proto_tree_add_uint(tree, hf_smb_qpi_loi, tvb, 0, 0, t2i->info_level); + proto_item_set_generated(item); + break; + + case 0x0003: /* QUERY_FS_INFORMATION */ + if (t2i->info_level == -1) + item = proto_tree_add_uint_format_value(tree, hf_smb_qfsi_information_level, tvb, 0, 0, si->info_level, + "<UNKNOWN> since information level wasn't found in request packet"); + else + item = proto_tree_add_uint(tree, hf_smb_qfsi_information_level, tvb, 0, 0, si->info_level); + proto_item_set_generated(item); + break; + + case 0x0004: /* SET_FS_INFORMATION */ + if (t2i->info_level == -1) + item = proto_tree_add_uint_format_value(tree, hf_smb_sfsi_information_level, tvb, 0, 0, si->info_level, + "<UNKNOWN> since information level wasn't found in request packet"); + else + item = proto_tree_add_uint(tree, hf_smb_sfsi_information_level, tvb, 0, 0, si->info_level); + proto_item_set_generated(item); + break; + } + + col_append_fstr(pinfo->cinfo, COL_INFO, ", %s", + val_to_str_ext(t2i->subcmd, + &trans2_cmd_vals_ext, + "<unknown (0x%02x)>")); + } + } + break; + } + + WORD_COUNT; + + /* total param count, only a 16bit integer here */ + tp = tvb_get_letohs(tvb, offset); + proto_tree_add_uint(tree, hf_smb_total_param_count, tvb, offset, 2, tp); + offset += 2; + + /* total data count, only a 16 bit integer here */ + td = tvb_get_letohs(tvb, offset); + proto_tree_add_uint(tree, hf_smb_total_data_count, tvb, offset, 2, td); + offset += 2; + + /* 2 reserved bytes */ + proto_tree_add_item(tree, hf_smb_reserved, tvb, offset, 2, ENC_NA); + offset += 2; + + /* param count */ + pc = tvb_get_letohs(tvb, offset); + proto_tree_add_uint(tree, hf_smb_param_count16, tvb, offset, 2, pc); + offset += 2; + + /* param offset */ + po = tvb_get_letohs(tvb, offset); + proto_tree_add_uint(tree, hf_smb_param_offset16, tvb, offset, 2, po); + offset += 2; + + /* param disp */ + pd = tvb_get_letohs(tvb, offset); + proto_tree_add_uint(tree, hf_smb_param_disp16, tvb, offset, 2, pd); + offset += 2; + + /* data count */ + dc = tvb_get_letohs(tvb, offset); + proto_tree_add_uint(tree, hf_smb_data_count16, tvb, offset, 2, dc); + offset += 2; + + /* data offset */ + od = tvb_get_letohs(tvb, offset); + proto_tree_add_uint(tree, hf_smb_data_offset16, tvb, offset, 2, od); + offset += 2; + + /* data disp */ + dd = tvb_get_letohs(tvb, offset); + proto_tree_add_uint(tree, hf_smb_data_disp16, tvb, offset, 2, dd); + offset += 2; + + /* setup count */ + sc = tvb_get_guint8(tvb, offset); + proto_tree_add_uint(tree, hf_smb_setup_count, tvb, offset, 1, sc); + offset += 1; + + /* reserved byte */ + proto_tree_add_item(tree, hf_smb_reserved, tvb, offset, 1, ENC_NA); + offset += 1; + + + /* if there were any setup bytes, put them in a tvb for later */ + if (sc) { + if ((2*sc) > tvb_reported_length_remaining(tvb, offset)) { + s_tvb = tvb_new_subset_length_caplen(tvb, offset, tvb_reported_length_remaining(tvb, offset), 2*sc); + } else { + s_tvb = tvb_new_subset_length(tvb, offset, 2*sc); + } + sp_tvb = tvb_new_subset_remaining(tvb, offset); + } else { + s_tvb = NULL; + sp_tvb = NULL; + } + offset += 2*sc; + + + BYTE_COUNT; + + + /* reassembly of SMB Transaction data payload. + In this section we do reassembly of both the data and parameters + blocks of the SMB transaction command. + */ + save_fragmented = pinfo->fragmented; + /* do we need reassembly? */ + if ( (td != dc) || (tp != pc) ) { + /* oh yeah, either data or parameter section needs + reassembly + */ + pinfo->fragmented = TRUE; + if (smb_trans_reassembly) { + /* ...and we were told to do reassembly */ + if (pc) { + r_fd = smb_trans_defragment(tree, pinfo, tvb, + po, pc, pd, td+tp, si); + + } + if ((r_fd == NULL) && dc) { + r_fd = smb_trans_defragment(tree, pinfo, tvb, + od, dc, dd+tp, td+tp, si); + } + } + } + + /* if we got a reassembled fd structure from the reassembly routine we must + create pd_tvb from it + */ + if (r_fd) { + proto_item *frag_tree_item; + + pd_tvb = tvb_new_chain(tvb, r_fd->tvb_data); + add_new_data_source(pinfo, pd_tvb, "Reassembled SMB"); + show_fragment_tree(r_fd, &smb_frag_items, tree, pinfo, pd_tvb, &frag_tree_item); + } + + + if (pd_tvb) { + /* OK we have reassembled data, extract d_tvb and p_tvb from it */ + if (tp) { + p_tvb = tvb_new_subset_length(pd_tvb, 0, tp); + } + if (td) { + d_tvb = tvb_new_subset_length(pd_tvb, tp, td); + } + } else { + /* It was not reassembled. Do as best as we can. + * in this case we always try to dissect the stuff if + * data and param displacement is 0. i.e. for the first + * (and maybe only) packet. + */ + if ( (pd == 0) && (dd == 0) ) { + int min; + int reported_min; + min = MIN(pc, tvb_reported_length_remaining(tvb, po)); + reported_min = MIN(pc, tvb_reported_length_remaining(tvb, po)); + if (min && reported_min) { + p_tvb = tvb_new_subset_length_caplen(tvb, po, min, reported_min); + } + min = MIN(dc, tvb_reported_length_remaining(tvb, od)); + reported_min = MIN(dc, tvb_reported_length_remaining(tvb, od)); + if (min && reported_min) { + d_tvb = tvb_new_subset_length_caplen(tvb, od, min, reported_min); + } + /* + * A tvbuff containing the parameters + * and the data. + * XXX - check pc and dc as well? + */ + if (tvb_reported_length_remaining(tvb, po)) { + pd_tvb = tvb_new_subset_remaining(tvb, po); + } + } + } + + + + /* parameters */ + if (po > offset) { + /* We have some padding bytes. + */ + padcnt = po-offset; + if (padcnt > bc) + padcnt = bc; + proto_tree_add_item(tree, hf_smb_padding, tvb, offset, padcnt, ENC_NA); + COUNT_BYTES(padcnt); + } + if ((si->cmd == SMB_COM_TRANSACTION2) && p_tvb) { + /* TRANSACTION2 parameters*/ + dissect_transaction2_response_parameters(p_tvb, pinfo, tree, si); + } + COUNT_BYTES(pc); + + + /* data */ + if (od > offset) { + /* We have some initial padding bytes. + */ + padcnt = od-offset; + if (padcnt > bc) + padcnt = bc; + proto_tree_add_item(tree, hf_smb_padding, tvb, offset, padcnt, ENC_NA); + COUNT_BYTES(padcnt); + } + /* + * If the data count is bigger than the count of bytes + * remaining, clamp it so that the count of bytes remaining + * doesn't go negative. + */ + if (dc > bc) + dc = bc; + COUNT_BYTES(dc); + + + + /* from now on, everything is in separate tvbuffs so we don't count + the bytes with COUNT_BYTES any more. + neither do we reference offset any more (which by now points to the + first byte AFTER this PDU */ + + + if ((si->cmd == SMB_COM_TRANSACTION2) && d_tvb) { + /* TRANSACTION2 parameters*/ + dissect_transaction2_response_data(d_tvb, pinfo, tree, si); + } + + + if (si->cmd == SMB_COM_TRANSACTION) { + smb_transact_info_t *tri; + + dissected_trans = FALSE; + if ((si->sip != NULL) && (si->sip->extra_info_type == SMB_EI_TRI)) + tri = (smb_transact_info_t *)si->sip->extra_info; + else + tri = NULL; + if (tri != NULL) { + switch(tri->subcmd) { + + case TRANSACTION_PIPE: + /* This function is safe to call for + s_tvb == sp_tvb == NULL, i.e. if we don't + know them at this point. + It's also safe to call if "p_tvb" + or "d_tvb" are null. + */ + if ( pd_tvb) { + dissected_trans = dissect_pipe_smb( + sp_tvb, s_tvb, pd_tvb, p_tvb, + d_tvb, NULL, pinfo, top_tree_global, si); + } + break; + + case TRANSACTION_MAILSLOT: + /* This one should be safe to call + even if s_tvb and sp_tvb is NULL + */ + if (d_tvb) { + dissected_trans = dissect_mailslot_smb( + sp_tvb, s_tvb, d_tvb, NULL, pinfo, + top_tree_global, si); + } + break; + } + } + if (!dissected_trans) { + /* This one is safe to call for s_tvb == p_tvb == d_tvb == NULL */ + dissect_trans_data(s_tvb, p_tvb, d_tvb, tree); + } + } + + + if ( (p_tvb == 0) && (d_tvb == 0) ) { + col_append_str(pinfo->cinfo, COL_INFO, + "[transact continuation]"); + } + + pinfo->fragmented = save_fragmented; + END_OF_SMB + + return offset; +} + + +static int +dissect_find_notify_close(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, int offset, proto_tree *smb_tree _U_, smb_info_t *si _U_) +{ + guint8 wc; + guint16 bc; + + WORD_COUNT; + + /* Monitor handle */ + proto_tree_add_item(tree, hf_smb_monitor_handle, tvb, offset, 2, ENC_LITTLE_ENDIAN); + offset += 2; + + BYTE_COUNT; + + END_OF_SMB + + return offset; +} + +/* XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX + END Transaction/Transaction2 Primary and secondary requests + XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX */ + + +static int +dissect_unknown(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, int offset, proto_tree *smb_tree _U_, smb_info_t *si _U_) +{ + guint8 wc; + guint16 bc; + + WORD_COUNT; + + if (wc != 0) { + proto_tree_add_item(tree, hf_smb_word_parameters, tvb, offset, wc*2, ENC_NA); + offset += wc*2; + } + + BYTE_COUNT; + + if (bc != 0) { + proto_tree_add_item(tree, hf_smb_byte_parameters, tvb, offset, bc, ENC_NA); + offset += bc; + bc = 0; + } + + END_OF_SMB + + return offset; +} + +typedef struct _smb_function { + int (*request)(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int offset, proto_tree *smb_tree, smb_info_t *si); + int (*response)(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int offset, proto_tree *smb_tree, smb_info_t *si); +} smb_function; + +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}, + /* 0x03 Create File*/ {dissect_create_file_request , dissect_create_file_response}, + /* 0x04 Close File*/ {dissect_close_file_request , dissect_empty}, + /* 0x05 Flush File*/ {dissect_flush_file_request , dissect_empty}, + /* 0x06 Delete File*/ {dissect_delete_file_request , dissect_empty}, + /* 0x07 Rename File*/ {dissect_rename_file_request , dissect_rename_file_response}, + /* 0x08 Query Info*/ {dissect_query_information_request , dissect_query_information_response}, + /* 0x09 Set Info*/ {dissect_set_information_request , dissect_empty}, + /* 0x0a Read File*/ {dissect_read_file_request , dissect_read_file_response}, + /* 0x0b Write File*/ {dissect_write_file_request , dissect_write_file_response}, + /* 0x0c Lock Byte Range*/ {dissect_lock_request , dissect_empty}, + /* 0x0d Unlock Byte Range*/ {dissect_lock_request , dissect_empty}, + /* 0x0e Create Temp*/ {dissect_create_temporary_request , dissect_create_temporary_response}, + /* 0x0f Create New*/ {dissect_create_file_request , dissect_create_new_response}, + + /* 0x10 Check Dir*/ {dissect_old_dir_request , dissect_empty}, + /* 0x11 Process Exit*/ {dissect_empty , dissect_empty}, + /* 0x12 Seek File*/ {dissect_seek_file_request , dissect_seek_file_response}, + /* 0x13 Lock And Read*/ {dissect_read_file_request , dissect_lock_and_read_response}, + /* 0x14 Write And Unlock*/ {dissect_write_file_request , dissect_write_file_response}, + /* 0x15 */ {dissect_unknown , dissect_unknown}, + /* 0x16 */ {dissect_unknown , dissect_unknown}, + /* 0x17 */ {dissect_unknown , dissect_unknown}, + /* 0x18 */ {dissect_unknown , dissect_unknown}, + /* 0x19 */ {dissect_unknown , dissect_unknown}, + /* 0x1a Read Raw*/ {dissect_read_raw_request , dissect_unknown}, + /* 0x1b Read MPX*/ {dissect_read_mpx_request , dissect_read_mpx_response}, + /* 0x1c Read MPX Secondary*/ {dissect_unknown , dissect_unknown}, + /* 0x1d Write Raw*/ {dissect_write_raw_request , dissect_write_raw_response}, + /* 0x1e Write MPX*/ {dissect_write_mpx_request , dissect_write_mpx_response}, + /* 0x1f Write MPX Secondary*/ {dissect_unknown , dissect_unknown}, + + /* 0x20 Write Complete*/ {dissect_unknown , dissect_write_and_close_response}, + /* 0x21 */ {dissect_unknown , dissect_unknown}, + /* 0x22 Set Info2*/ {dissect_set_information2_request , dissect_empty}, + /* 0x23 Query Info2*/ {dissect_query_information2_request , dissect_query_information2_response}, + /* 0x24 Locking And X*/ {dissect_locking_andx_request , dissect_locking_andx_response}, + /* 0x25 Transaction*/ {dissect_transaction_request , dissect_transaction_response}, + /* 0x26 Transaction Secondary*/ {dissect_transaction_request , dissect_unknown}, /*This SMB has no response */ + /* 0x27 IOCTL*/ {dissect_unknown , dissect_unknown}, + /* 0x28 IOCTL Secondary*/ {dissect_unknown , dissect_unknown}, + /* 0x29 Copy File*/ {dissect_copy_request , dissect_move_copy_response}, + /* 0x2a Move File*/ {dissect_move_request , dissect_move_copy_response}, + /* 0x2b Echo*/ {dissect_echo_request , dissect_echo_response}, + /* 0x2c Write And Close*/ {dissect_write_and_close_request , dissect_write_and_close_response}, + /* 0x2d Open And X*/ {dissect_open_andx_request , dissect_open_andx_response}, + /* 0x2e Read And X*/ {dissect_read_andx_request , dissect_read_andx_response}, + /* 0x2f Write And X*/ {dissect_write_andx_request , dissect_write_andx_response}, + + /* 0x30 */ {dissect_unknown , dissect_unknown}, + /* 0x31 Close And Tree Disconnect */ {dissect_close_file_request , dissect_empty}, + /* 0x32 Transaction2*/ {dissect_transaction_request , dissect_transaction_response}, + /* 0x33 Transaction2 Secondary*/ {dissect_transaction_request , dissect_unknown}, /*This SMB has no response */ + /* 0x34 Find Close2*/ {dissect_sid , dissect_empty}, + /* 0x35 Find Notify Close*/ {dissect_find_notify_close , dissect_empty}, + /* 0x36 */ {dissect_unknown, dissect_unknown}, + /* 0x37 */ {dissect_unknown, dissect_unknown}, + /* 0x38 */ {dissect_unknown, dissect_unknown}, + /* 0x39 */ {dissect_unknown, dissect_unknown}, + /* 0x3a */ {dissect_unknown, dissect_unknown}, + /* 0x3b */ {dissect_unknown, dissect_unknown}, + /* 0x3c */ {dissect_unknown, dissect_unknown}, + /* 0x3d */ {dissect_unknown, dissect_unknown}, + /* 0x3e */ {dissect_unknown, dissect_unknown}, + /* 0x3f */ {dissect_unknown, dissect_unknown}, + + /* 0x40 */ {dissect_unknown, dissect_unknown}, + /* 0x41 */ {dissect_unknown, dissect_unknown}, + /* 0x42 */ {dissect_unknown, dissect_unknown}, + /* 0x43 */ {dissect_unknown, dissect_unknown}, + /* 0x44 */ {dissect_unknown, dissect_unknown}, + /* 0x45 */ {dissect_unknown, dissect_unknown}, + /* 0x46 */ {dissect_unknown, dissect_unknown}, + /* 0x47 */ {dissect_unknown, dissect_unknown}, + /* 0x48 */ {dissect_unknown, dissect_unknown}, + /* 0x49 */ {dissect_unknown, dissect_unknown}, + /* 0x4a */ {dissect_unknown, dissect_unknown}, + /* 0x4b */ {dissect_unknown, dissect_unknown}, + /* 0x4c */ {dissect_unknown, dissect_unknown}, + /* 0x4d */ {dissect_unknown, dissect_unknown}, + /* 0x4e */ {dissect_unknown, dissect_unknown}, + /* 0x4f */ {dissect_unknown, dissect_unknown}, + + /* 0x50 */ {dissect_unknown, dissect_unknown}, + /* 0x51 */ {dissect_unknown, dissect_unknown}, + /* 0x52 */ {dissect_unknown, dissect_unknown}, + /* 0x53 */ {dissect_unknown, dissect_unknown}, + /* 0x54 */ {dissect_unknown, dissect_unknown}, + /* 0x55 */ {dissect_unknown, dissect_unknown}, + /* 0x56 */ {dissect_unknown, dissect_unknown}, + /* 0x57 */ {dissect_unknown, dissect_unknown}, + /* 0x58 */ {dissect_unknown, dissect_unknown}, + /* 0x59 */ {dissect_unknown, dissect_unknown}, + /* 0x5a */ {dissect_unknown, dissect_unknown}, + /* 0x5b */ {dissect_unknown, dissect_unknown}, + /* 0x5c */ {dissect_unknown, dissect_unknown}, + /* 0x5d */ {dissect_unknown, dissect_unknown}, + /* 0x5e */ {dissect_unknown, dissect_unknown}, + /* 0x5f */ {dissect_unknown, dissect_unknown}, + + /* 0x60 */ {dissect_unknown, dissect_unknown}, + /* 0x61 */ {dissect_unknown, dissect_unknown}, + /* 0x62 */ {dissect_unknown, dissect_unknown}, + /* 0x63 */ {dissect_unknown, dissect_unknown}, + /* 0x64 */ {dissect_unknown, dissect_unknown}, + /* 0x65 */ {dissect_unknown, dissect_unknown}, + /* 0x66 */ {dissect_unknown, dissect_unknown}, + /* 0x67 */ {dissect_unknown, dissect_unknown}, + /* 0x68 */ {dissect_unknown, dissect_unknown}, + /* 0x69 */ {dissect_unknown, dissect_unknown}, + /* 0x6a */ {dissect_unknown, dissect_unknown}, + /* 0x6b */ {dissect_unknown, dissect_unknown}, + /* 0x6c */ {dissect_unknown, dissect_unknown}, + /* 0x6d */ {dissect_unknown, dissect_unknown}, + /* 0x6e */ {dissect_unknown, dissect_unknown}, + /* 0x6f */ {dissect_unknown, dissect_unknown}, + + /* 0x70 Tree Connect*/ {dissect_tree_connect_request , dissect_tree_connect_response}, + /* 0x71 Tree Disconnect*/ {dissect_empty , dissect_empty}, + /* 0x72 Negotiate Protocol*/ {dissect_negprot_request , dissect_negprot_response}, + /* 0x73 Session Setup And X*/ {dissect_session_setup_andx_request , dissect_session_setup_andx_response}, + /* 0x74 Logoff And X*/ {dissect_empty_andx , dissect_empty_andx}, + /* 0x75 Tree Connect And X*/ {dissect_tree_connect_andx_request , dissect_tree_connect_andx_response}, + /* 0x76 */ {dissect_unknown, dissect_unknown}, + /* 0x77 */ {dissect_unknown, dissect_unknown}, + /* 0x78 */ {dissect_unknown, dissect_unknown}, + /* 0x79 */ {dissect_unknown, dissect_unknown}, + /* 0x7a */ {dissect_unknown, dissect_unknown}, + /* 0x7b */ {dissect_unknown, dissect_unknown}, + /* 0x7c */ {dissect_unknown, dissect_unknown}, + /* 0x7d */ {dissect_unknown, dissect_unknown}, + /* 0x7e */ {dissect_unknown, dissect_unknown}, + /* 0x7f */ {dissect_unknown, dissect_unknown}, + + /* 0x80 Query Info Disk*/ {dissect_empty , dissect_query_information_disk_response}, + /* 0x81 Search Dir*/ {dissect_search_dir_request , dissect_search_dir_response}, + /* 0x82 Find*/ {dissect_find_request , dissect_find_response}, + /* 0x83 Find Unique*/ {dissect_find_request , dissect_find_response}, + /* 0x84 Find Close*/ {dissect_find_close_request , dissect_find_close_response}, + /* 0x85 */ {dissect_unknown, dissect_unknown}, + /* 0x86 */ {dissect_unknown, dissect_unknown}, + /* 0x87 */ {dissect_unknown, dissect_unknown}, + /* 0x88 */ {dissect_unknown, dissect_unknown}, + /* 0x89 */ {dissect_unknown, dissect_unknown}, + /* 0x8a */ {dissect_unknown, dissect_unknown}, + /* 0x8b */ {dissect_unknown, dissect_unknown}, + /* 0x8c */ {dissect_unknown, dissect_unknown}, + /* 0x8d */ {dissect_unknown, dissect_unknown}, + /* 0x8e */ {dissect_unknown, dissect_unknown}, + /* 0x8f */ {dissect_unknown, dissect_unknown}, + + /* 0x90 */ {dissect_unknown, dissect_unknown}, + /* 0x91 */ {dissect_unknown, dissect_unknown}, + /* 0x92 */ {dissect_unknown, dissect_unknown}, + /* 0x93 */ {dissect_unknown, dissect_unknown}, + /* 0x94 */ {dissect_unknown, dissect_unknown}, + /* 0x95 */ {dissect_unknown, dissect_unknown}, + /* 0x96 */ {dissect_unknown, dissect_unknown}, + /* 0x97 */ {dissect_unknown, dissect_unknown}, + /* 0x98 */ {dissect_unknown, dissect_unknown}, + /* 0x99 */ {dissect_unknown, dissect_unknown}, + /* 0x9a */ {dissect_unknown, dissect_unknown}, + /* 0x9b */ {dissect_unknown, dissect_unknown}, + /* 0x9c */ {dissect_unknown, dissect_unknown}, + /* 0x9d */ {dissect_unknown, dissect_unknown}, + /* 0x9e */ {dissect_unknown, dissect_unknown}, + /* 0x9f */ {dissect_unknown, dissect_unknown}, + + /* 0xa0 NT Transaction*/ {dissect_nt_transaction_request , dissect_nt_transaction_response}, + /* 0xa1 NT Trans secondary*/ {dissect_nt_transaction_request , dissect_nt_transaction_response}, + /* 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 NT Rename*/ {dissect_nt_rename_file_request , dissect_empty}, + /* 0xa6 */ {dissect_unknown, dissect_unknown}, + /* 0xa7 */ {dissect_unknown, dissect_unknown}, + /* 0xa8 */ {dissect_unknown, dissect_unknown}, + /* 0xa9 */ {dissect_unknown, dissect_unknown}, + /* 0xaa */ {dissect_unknown, dissect_unknown}, + /* 0xab */ {dissect_unknown, dissect_unknown}, + /* 0xac */ {dissect_unknown, dissect_unknown}, + /* 0xad */ {dissect_unknown, dissect_unknown}, + /* 0xae */ {dissect_unknown, dissect_unknown}, + /* 0xaf */ {dissect_unknown, dissect_unknown}, + + /* 0xb0 */ {dissect_unknown, dissect_unknown}, + /* 0xb1 */ {dissect_unknown, dissect_unknown}, + /* 0xb2 */ {dissect_unknown, dissect_unknown}, + /* 0xb3 */ {dissect_unknown, dissect_unknown}, + /* 0xb4 */ {dissect_unknown, dissect_unknown}, + /* 0xb5 */ {dissect_unknown, dissect_unknown}, + /* 0xb6 */ {dissect_unknown, dissect_unknown}, + /* 0xb7 */ {dissect_unknown, dissect_unknown}, + /* 0xb8 */ {dissect_unknown, dissect_unknown}, + /* 0xb9 */ {dissect_unknown, dissect_unknown}, + /* 0xba */ {dissect_unknown, dissect_unknown}, + /* 0xbb */ {dissect_unknown, dissect_unknown}, + /* 0xbc */ {dissect_unknown, dissect_unknown}, + /* 0xbd */ {dissect_unknown, dissect_unknown}, + /* 0xbe */ {dissect_unknown, dissect_unknown}, + /* 0xbf */ {dissect_unknown, dissect_unknown}, + + /* 0xc0 Open Print File*/ {dissect_open_print_file_request , dissect_open_print_file_response}, + /* 0xc1 Write Print File*/ {dissect_write_print_file_request , dissect_empty}, + /* 0xc2 Close Print File*/ {dissect_close_print_file_request , dissect_empty}, + /* 0xc3 Get Print Queue*/ {dissect_get_print_queue_request , dissect_get_print_queue_response}, + /* 0xc4 */ {dissect_unknown, dissect_unknown}, + /* 0xc5 */ {dissect_unknown, dissect_unknown}, + /* 0xc6 */ {dissect_unknown, dissect_unknown}, + /* 0xc7 */ {dissect_unknown, dissect_unknown}, + /* 0xc8 */ {dissect_unknown, dissect_unknown}, + /* 0xc9 */ {dissect_unknown, dissect_unknown}, + /* 0xca */ {dissect_unknown, dissect_unknown}, + /* 0xcb */ {dissect_unknown, dissect_unknown}, + /* 0xcc */ {dissect_unknown, dissect_unknown}, + /* 0xcd */ {dissect_unknown, dissect_unknown}, + /* 0xce */ {dissect_unknown, dissect_unknown}, + /* 0xcf */ {dissect_unknown, dissect_unknown}, + + /* 0xd0 Send Single Block Message*/ {dissect_send_single_block_message_request , dissect_empty}, + /* 0xd1 Send Broadcast Message*/ {dissect_send_single_block_message_request , dissect_empty}, + /* 0xd2 Forward User Name*/ {dissect_forwarded_name , dissect_empty}, + /* 0xd3 Cancel Forward*/ {dissect_forwarded_name , dissect_empty}, + /* 0xd4 Get Machine Name*/ {dissect_empty , dissect_get_machine_name_response}, + /* 0xd5 Send Start of Multi-block Message*/ {dissect_send_multi_block_message_start_request , dissect_message_group_id}, + /* 0xd6 Send End of Multi-block Message*/ {dissect_message_group_id , dissect_empty}, + /* 0xd7 Send Text of Multi-block Message*/ {dissect_send_multi_block_message_text_request , dissect_empty}, + /* 0xd8 SMBreadbulk*/ {dissect_unknown , dissect_unknown}, + /* 0xd9 SMBwritebulk*/ {dissect_unknown , dissect_unknown}, + /* 0xda SMBwritebulkdata*/ {dissect_unknown , dissect_unknown}, + /* 0xdb */ {dissect_unknown, dissect_unknown}, + /* 0xdc */ {dissect_unknown, dissect_unknown}, + /* 0xdd */ {dissect_unknown, dissect_unknown}, + /* 0xde */ {dissect_unknown, dissect_unknown}, + /* 0xdf */ {dissect_unknown, dissect_unknown}, + + /* 0xe0 */ {dissect_unknown, dissect_unknown}, + /* 0xe1 */ {dissect_unknown, dissect_unknown}, + /* 0xe2 */ {dissect_unknown, dissect_unknown}, + /* 0xe3 */ {dissect_unknown, dissect_unknown}, + /* 0xe4 */ {dissect_unknown, dissect_unknown}, + /* 0xe5 */ {dissect_unknown, dissect_unknown}, + /* 0xe6 */ {dissect_unknown, dissect_unknown}, + /* 0xe7 */ {dissect_unknown, dissect_unknown}, + /* 0xe8 */ {dissect_unknown, dissect_unknown}, + /* 0xe9 */ {dissect_unknown, dissect_unknown}, + /* 0xea */ {dissect_unknown, dissect_unknown}, + /* 0xeb */ {dissect_unknown, dissect_unknown}, + /* 0xec */ {dissect_unknown, dissect_unknown}, + /* 0xed */ {dissect_unknown, dissect_unknown}, + /* 0xee */ {dissect_unknown, dissect_unknown}, + /* 0xef */ {dissect_unknown, dissect_unknown}, + + /* 0xf0 */ {dissect_unknown, dissect_unknown}, + /* 0xf1 */ {dissect_unknown, dissect_unknown}, + /* 0xf2 */ {dissect_unknown, dissect_unknown}, + /* 0xf3 */ {dissect_unknown, dissect_unknown}, + /* 0xf4 */ {dissect_unknown, dissect_unknown}, + /* 0xf5 */ {dissect_unknown, dissect_unknown}, + /* 0xf6 */ {dissect_unknown, dissect_unknown}, + /* 0xf7 */ {dissect_unknown, dissect_unknown}, + /* 0xf8 */ {dissect_unknown, dissect_unknown}, + /* 0xf9 */ {dissect_unknown, dissect_unknown}, + /* 0xfa */ {dissect_unknown, dissect_unknown}, + /* 0xfb */ {dissect_unknown, dissect_unknown}, + /* 0xfc */ {dissect_unknown, dissect_unknown}, + /* 0xfd */ {dissect_unknown, dissect_unknown}, + /* 0xfe */ {dissect_unknown, dissect_unknown}, + /* 0xff */ {dissect_unknown, dissect_unknown}, +}; + +static int +dissect_smb_command(tvbuff_t *tvb, packet_info *pinfo, int offset, proto_tree *smb_tree, guint8 cmd, gboolean first_pdu, smb_info_t *si) +{ + smb_saved_info_t *sip; + + DISSECTOR_ASSERT(si); + + if (cmd != 0xff) { + proto_item *cmd_item; + proto_tree *cmd_tree; + int (*dissector)(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int offset, proto_tree *smb_tree, smb_info_t *si); + + if (first_pdu) { + col_append_fstr(pinfo->cinfo, COL_INFO, + "%s %s", + val_to_str_ext(cmd, &smb_cmd_vals_ext, "Unknown (0x%02x)"), + (si->request)? "Request" : "Response"); + } else { + col_append_fstr(pinfo->cinfo, COL_INFO, + "; %s", + val_to_str_ext(cmd, &smb_cmd_vals_ext, "Unknown (0x%02x)")); + } + + cmd_tree = proto_tree_add_subtree_format(smb_tree, tvb, offset, -1, + ett_smb_command, &cmd_item, "%s %s (0x%02x)", + val_to_str_ext_const(cmd, &smb_cmd_vals_ext, "Unknown"), + (si->request)?"Request":"Response", + cmd); + + /* we track FIDs on a per transaction basis. + if this was a request and the fid was seen in a reply + we add a "generated" fid tree for this pdu and v.v. + */ + sip = si->sip; + if (sip && sip->fid) { + if ( (si->request && (!sip->fid_seen_in_request)) + || ((!si->request) && sip->fid_seen_in_request) ) { + dissect_smb_fid(tvb, pinfo, cmd_tree, offset, 0, sip->fid, FALSE, FALSE, TRUE, si); + } + } + + dissector = (si->request) ? + smb_dissector[cmd].request : smb_dissector[cmd].response; + + offset = (*dissector)(tvb, pinfo, cmd_tree, offset, smb_tree, si); + + if (!tvb_offset_exists(tvb, offset-1)) { + THROW(ReportedBoundsError); + } + proto_item_set_end(cmd_item, tvb, offset); + } + return offset; +} + +static const value_string smb_cmd_vals[] = { + { 0x00, "Create Directory" }, + { 0x01, "Delete Directory" }, + { 0x02, "Open" }, + { 0x03, "Create" }, + { 0x04, "Close" }, + { 0x05, "Flush" }, + { 0x06, "Delete" }, + { 0x07, "Rename" }, + { 0x08, "Query Information" }, + { 0x09, "Set Information" }, + { 0x0A, "Read" }, + { 0x0B, "Write" }, + { 0x0C, "Lock Byte Range" }, + { 0x0D, "Unlock Byte Range" }, + { 0x0E, "Create Temp" }, + { 0x0F, "Create New" }, + { 0x10, "Check Directory" }, + { 0x11, "Process Exit" }, + { 0x12, "Seek" }, + { 0x13, "Lock And Read" }, + { 0x14, "Write And Unlock" }, + { 0x15, "unknown-0x15" }, + { 0x16, "unknown-0x16" }, + { 0x17, "unknown-0x17" }, + { 0x18, "unknown-0x18" }, + { 0x19, "unknown-0x19" }, + { 0x1A, "Read Raw" }, + { 0x1B, "Read MPX" }, + { 0x1C, "Read MPX Secondary" }, + { 0x1D, "Write Raw" }, + { 0x1E, "Write MPX" }, + { 0x1F, "Write MPX Secondary" }, + { 0x20, "Write Complete" }, + + /* + * To quote + * + * http://msdn.microsoft.com/en-us/library/ee442098.aspx + * + * "This command was introduced in the NT LAN Manager dialect, and + * was reserved but not implemented. + * + * Clients SHOULD NOT send requests using this command code, and + * servers receiving requests with this command code SHOULD return + * STATUS_NOT_IMPLEMENTED (ERRDOS/ERRbadfunc)." + */ + { 0x21, "Query Server (reserved)" }, + + { 0x22, "Set Information2" }, + { 0x23, "Query Information2" }, + { 0x24, "Locking AndX" }, + { 0x25, "Trans" }, + { 0x26, "Trans Secondary" }, + { 0x27, "IOCTL" }, + { 0x28, "IOCTL Secondary" }, + { 0x29, "Copy" }, + { 0x2A, "Move" }, + { 0x2B, "Echo" }, + { 0x2C, "Write And Close" }, + { 0x2D, "Open AndX" }, + { 0x2E, "Read AndX" }, + { 0x2F, "Write AndX" }, + + /* + * To quote + * + * http://msdn.microsoft.com/en-us/library/ee442127.aspx + * + * "This command was reserved but not implemented. It was also never + * defined. It is listed in [SNIA], but it is not defined in that + * document and does not appear in any other references. + * + * Clients SHOULD NOT send requests using this command code, and + * servers receiving requests with this command code SHOULD return + * STATUS_NOT_IMPLEMENTED (ERRDOC/ERRbadfunc)." + */ + { 0x30, "New File Size (reserved)" }, + + { 0x31, "Close And Tree Disconnect" }, + { 0x32, "Trans2" }, + { 0x33, "Trans2 Secondary" }, + { 0x34, "Find Close2" }, + { 0x35, "Find Notify Close" }, + { 0x70, "Tree Connect" }, + { 0x71, "Tree Disconnect" }, + { 0x72, "Negotiate Protocol" }, + { 0x73, "Session Setup AndX" }, + { 0x74, "Logoff AndX" }, + { 0x75, "Tree Connect AndX" }, + { 0x80, "Query Information Disk" }, + { 0x81, "Search" }, + { 0x82, "Find" }, + { 0x83, "Find Unique" }, + { 0x84, "Find Close" }, + { 0xA0, "NT Trans" }, + { 0xA1, "NT Trans Secondary" }, + { 0xA2, "NT Create AndX" }, + { 0xA3, "unknown-0xA3" }, + { 0xA4, "NT Cancel" }, + { 0xA5, "NT Rename" }, + { 0xC0, "Open Print File" }, + { 0xC1, "Write Print File" }, + { 0xC2, "Close Print File" }, + { 0xC3, "Get Print Queue" }, + { 0xD0, "Send Single Block Message" }, + { 0xD1, "Send Broadcast Message" }, + { 0xD2, "Forward User Name" }, + { 0xD3, "Cancel Forward" }, + { 0xD4, "Get Machine Name" }, + { 0xD5, "Send Start of Multi-block Message" }, + { 0xD6, "Send End of Multi-block Message" }, + { 0xD7, "Send Text of Multi-block Message" }, + { 0xD8, "SMBreadbulk" }, + { 0xD9, "SMBwritebulk" }, + { 0xDA, "SMBwritebulkdata" }, + { 0xFE, "SMBinvalid" }, + { 0x00, NULL }, +}; +value_string_ext smb_cmd_vals_ext = VALUE_STRING_EXT_INIT(smb_cmd_vals); + + +static void +free_hash_tables(gpointer ctarg, gpointer user_data _U_) +{ + conv_tables_t *ct = (conv_tables_t *)ctarg; + + if (ct->unmatched) + g_hash_table_destroy(ct->unmatched); + if (ct->matched) + g_hash_table_destroy(ct->matched); + if (ct->primaries) + g_hash_table_destroy(ct->primaries); + if (ct->tid_service) + g_hash_table_destroy(ct->tid_service); + g_slist_free(ct->GSL_fid_info); + g_free(ct); +} + +static void +smb_cleanup(void) +{ + if (conv_tables) { + g_slist_foreach(conv_tables, free_hash_tables, NULL); + g_slist_free(conv_tables); + conv_tables = NULL; + } +} + +static const value_string errcls_types[] = { + { SMB_SUCCESS, "Success"}, + { SMB_ERRDOS, "DOS Error"}, + { SMB_ERRSRV, "Server Error"}, + { SMB_ERRHRD, "Hardware Error"}, + { SMB_ERRCMD, "Command Error - Not an SMB format command"}, + { 0, NULL } +}; + +/* Error codes for the ERRSRV class */ + +#define SRV_errors_VALUE_STRING_LIST(XXX) \ + XXX( SMBE_SRV_error, 1, "Non specific error code") \ + XXX( SMBE_SRV_badpw, 2, "Bad password") \ + XXX( SMBE_SRV_badtype, 3, "Reserved") \ + XXX( SMBE_SRV_access, 4, "No permissions to perform the requested operation") \ + XXX( SMBE_SRV_invnid, 5, "TID invalid") \ + XXX( SMBE_SRV_invnetname, 6, "Invalid network name. Service not found") \ + XXX( SMBE_SRV_invdevice, 7, "Invalid device") \ + XXX( SMBE_SRV_unknownsmb, 22, "Unknown SMB, from NT 3.5 response") \ + XXX( SMBE_SRV_qfull, 49, "Print queue full") \ + XXX( SMBE_SRV_qtoobig, 50, "Queued item too big") \ + XXX( SMBE_SRV_qeof, 51, "EOF in print queue dump") \ + XXX( SMBE_SRV_invpfid, 52, "Invalid print file in smb_fid") \ + XXX( SMBE_SRV_smbcmd, 64, "Unrecognised command") \ + XXX( SMBE_SRV_srverror, 65, "SMB server internal error") \ + XXX( SMBE_SRV_filespecs, 67, "Fid and pathname invalid combination") \ + XXX( SMBE_SRV_badlink, 68, "Bad link in request ???") \ + XXX( SMBE_SRV_badpermits, 69, "Access specified for a file is not valid") \ + XXX( SMBE_SRV_badpid, 70, "Bad process id in request") \ + XXX( SMBE_SRV_setattrmode, 71, "Attribute mode invalid") \ + XXX( SMBE_SRV_paused, 81, "Message server paused") \ + XXX( SMBE_SRV_msgoff, 82, "Not receiving messages") \ + XXX( SMBE_SRV_noroom, 83, "No room for message") \ + XXX( SMBE_SRV_rmuns, 87, "Too many remote usernames") \ + XXX( SMBE_SRV_timeout, 88, "Operation timed out") \ + XXX( SMBE_SRV_noresource, 89, "No resources currently available for request.") \ + XXX( SMBE_SRV_toomanyuids, 90, "Too many userids") \ + XXX( SMBE_SRV_baduid, 91, "Bad userid") \ + XXX( SMBE_SRV_useMPX, 250, "Temporarily unable to use raw mode, use MPX mode") \ + XXX( SMBE_SRV_useSTD, 251, "Temporarily unable to use raw mode, use standard mode") \ + XXX( SMBE_SRV_contMPX, 252, "Resume MPX mode") \ + XXX( SMBE_SRV_badPW, 253, "Bad Password???") \ + XXX( SMBE_SRV_nosupport, 0xFFFF, "Operation not supported") + +#if 0 /* Values not needed */ +VALUE_STRING_ENUM(SRV_errors); +#endif +VALUE_STRING_ARRAY(SRV_errors); +static value_string_ext SRV_errors_ext = VALUE_STRING_EXT_INIT(SRV_errors); + + +/* Error codes for the ERRHRD class */ + +#define HRD_errors_VALUE_STRING_LIST(XXX) \ + XXX( SMBE_HRD_nowrite, 19, "Read only media") \ + XXX( SMBE_HRD_badunit, 20, "Unknown device") \ + XXX( SMBE_HRD_notready, 21, "Drive not ready") \ + XXX( SMBE_HRD_badcmd, 22, "Unknown command") \ + XXX( SMBE_HRD_data, 23, "Data (CRC) error") \ + XXX( SMBE_HRD_badreq, 24, "Bad request structure length") \ + XXX( SMBE_HRD_seek, 25, "Seek error") \ + XXX( SMBE_HRD_badmedia, 26, "Unknown media type") \ + XXX( SMBE_HRD_badsector, 27, "Sector not found") \ + XXX( SMBE_HRD_nopaper, 28, "Printer out of paper") \ + XXX( SMBE_HRD_write, 29, "Write fault") \ + XXX( SMBE_HRD_read, 30, "Read fault") \ + XXX( SMBE_HRD_general, 31, "General failure") \ + /* -- (really part of ERRDOS class ??) -- */ \ + XXX( SMBE_HRD_badshare, 32, "An open conflicts with an existing open") \ + XXX( SMBE_HRD_lock, 33, "Lock conflict/invalid mode, or unlock of another process's lock") \ + /* -- --*/ \ + XXX( SMBE_HRD_wrongdisk, 34, "The wrong disk was found in a drive") \ + XXX( SMBE_HRD_FCBunavail, 35, "No FCBs are available to process request") \ + XXX( SMBE_HRD_sharebufexc, 36, "A sharing buffer has been exceeded") \ + XXX( SMBE_HRD_diskfull, 39, "Disk full???") + +#if 0 /* Values not needed */ +VALUE_STRING_ENUM(HRD_errors); +#endif +VALUE_STRING_ARRAY(HRD_errors); +static value_string_ext HRD_errors_ext = VALUE_STRING_EXT_INIT(HRD_errors); + +static const char *decode_smb_error(guint8 errcls, guint16 errcode) +{ + + switch (errcls) { + + case SMB_SUCCESS: + + return("No Error"); /* No error ??? */ + + case SMB_ERRDOS: + + return(val_to_str_ext(errcode, &DOS_errors_ext, "Unknown DOS error (%x)")); + + case SMB_ERRSRV: + + return(val_to_str_ext(errcode, &SRV_errors_ext, "Unknown SRV error (%x)")); + + case SMB_ERRHRD: + + return(val_to_str_ext(errcode, &HRD_errors_ext, "Unknown HRD error (%x)")); + + default: + + return("Unknown error class!"); + + } + +} + +static const true_false_string tfs_smb_flags_lock = { + "Lock&Read, Write&Unlock are supported", + "Lock&Read, Write&Unlock are not supported" +}; +static const true_false_string tfs_smb_flags_receive_buffer = { + "Receive buffer has been posted", + "Receive buffer has not been posted" +}; +static const true_false_string tfs_smb_flags_caseless = { + "Path names are caseless", + "Path names are case sensitive" +}; +static const true_false_string tfs_smb_flags_canon = { + "Pathnames are canonicalized", + "Pathnames are not canonicalized" +}; +static const true_false_string tfs_smb_flags_oplock = { + "OpLock requested/granted", + "OpLock not requested/granted" +}; +static const true_false_string tfs_smb_flags_notify = { + "Notify client on all modifications", + "Notify client only on open" +}; +static const true_false_string tfs_smb_flags_response = { + "Message is a response to the client/redirector", + "Message is a request to the server" +}; + +static int +dissect_smb_flags(tvbuff_t *tvb, proto_tree *parent_tree, int offset) +{ + static int * const flags[] = { + &hf_smb_flags_response, + &hf_smb_flags_notify, + &hf_smb_flags_oplock, + &hf_smb_flags_canon, + &hf_smb_flags_caseless, + &hf_smb_flags_receive_buffer, + &hf_smb_flags_lock, + NULL + }; + + proto_tree_add_bitmask(parent_tree, tvb, offset, hf_smb_flags, ett_smb_flags, flags, ENC_NA); + offset += 1; + + return offset; +} + + + +static const true_false_string tfs_smb_flags2_long_names_allowed = { + "Long file names are allowed in the response", + "Long file names are not allowed in the response" +}; +static const true_false_string tfs_smb_flags2_ea = { + "Extended attributes are supported", + "Extended attributes are not supported" +}; +static const true_false_string tfs_smb_flags2_sec_sig = { + "Security signatures are supported", + "Security signatures are not supported" +}; +static const true_false_string tfs_smb_flags2_compressed = { + "Compression is requested", + "Compression is not requested" +}; +static const true_false_string tfs_smb_flags2_sec_sig_required = { + "Security signatures are required", + "Security signatures are not required" +}; +static const true_false_string tfs_smb_flags2_long_names_used = { + "Path names in request are long file names", + "Path names in request are not long file names" +}; +static const true_false_string tfs_smb_flags2_reparse_path = { + "The request uses a @GMT reparse path", + "The request does not use a @GMT reparse path" +}; +static const true_false_string tfs_smb_flags2_esn = { + "Extended security negotiation is supported", + "Extended security negotiation is not supported" +}; +static const true_false_string tfs_smb_flags2_dfs = { + "Resolve pathnames with Dfs", + "Don't resolve pathnames with Dfs" +}; +static const true_false_string tfs_smb_flags2_roe = { + "Permit reads if execute-only", + "Don't permit reads if execute-only" +}; +static const true_false_string tfs_smb_flags2_nt_error = { + "Error codes are NT error codes", + "Error codes are DOS error codes" +}; +static const true_false_string tfs_smb_flags2_string = { + "Strings are Unicode", + "Strings are ASCII" +}; +static int +dissect_smb_flags2(tvbuff_t *tvb, proto_tree *parent_tree, int offset) +{ + static int * const flags[] = { + &hf_smb_flags2_string, + &hf_smb_flags2_nt_error, + &hf_smb_flags2_roe, + &hf_smb_flags2_dfs, + &hf_smb_flags2_esn, + &hf_smb_flags2_reparse_path, + &hf_smb_flags2_long_names_used, + &hf_smb_flags2_sec_sig_required, + &hf_smb_flags2_compressed, + &hf_smb_flags2_sec_sig, + &hf_smb_flags2_ea, + &hf_smb_flags2_long_names_allowed, + NULL + }; + + proto_tree_add_bitmask(parent_tree, tvb, offset, hf_smb_flags2, ett_smb_flags2, flags, ENC_LITTLE_ENDIAN); + offset += 2; + + return offset; +} + + + +#define SMB_FLAGS_DIRN 0x80 + + +static int +dissect_smb(tvbuff_t *tvb, packet_info *pinfo, proto_tree *parent_tree, void* data _U_) +{ + int offset = 0; + proto_item *item; + proto_tree *tree, *htree; + proto_item *tmp_item = NULL; + guint8 flags; + guint16 flags2; + smb_info_t *si; + smb_saved_info_t *sip = NULL; + smb_saved_info_key_t key; + smb_saved_info_key_t *new_key; + guint8 errclass = 0; + guint16 errcode = 0; + guint32 pid_mid; + conversation_t *conversation; + nstime_t t, deltat; + + si = wmem_new0(wmem_packet_scope(), smb_info_t); + + top_tree_global = parent_tree; + + col_set_str(pinfo->cinfo, COL_PROTOCOL, "SMB"); + col_clear(pinfo->cinfo, COL_INFO); + + /* start off using the local variable, we will allocate a new one if we + need to*/ + si->cmd = tvb_get_guint8(tvb, offset+4); + flags = tvb_get_guint8(tvb, offset+9); + /* + * XXX - in some SMB-over-OSI-transport and SMB-over-Vines traffic, + * the direction flag appears never to be set, even for what appear + * to be replies. Do some SMB servers fail to set that flag, + * under the assumption that the client knows it's a reply because + * it received it? + */ + si->request = !(flags&SMB_FLAGS_DIRN); + flags2 = tvb_get_letohs(tvb, offset+10); + if (flags2 & 0x8000) { + si->unicode = TRUE; /* Mark them as Unicode */ + } else { + 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; + + item = proto_tree_add_item(parent_tree, proto_smb, tvb, offset, + -1, ENC_NA); + tree = proto_item_add_subtree(item, ett_smb); + + htree = proto_tree_add_subtree(tree, tvb, offset, 32, + ett_smb_hdr, NULL, "SMB Header"); + + + proto_tree_add_uint_format_value(htree, hf_smb_server_component, tvb, offset, 4, tvb_get_letohl(tvb, offset), "SMB"); + offset += 4; /* Skip the marker */ + + /* find which conversation we are part of and get the tables for that + conversation*/ + conversation = find_or_create_conversation(pinfo); + /* see if we already have the smb data for this conversation */ + si->ct = (conv_tables_t *)conversation_get_proto_data(conversation, proto_smb); + if (!si->ct) { + /* No, not yet. create it and attach it to the conversation */ + si->ct = g_new(conv_tables_t, 1); + + 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, + smb_saved_info_equal_unmatched); + /* We used the same key format as the unmatched entries */ + si->ct->primaries = 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); + si->ct->raw_ntlmssp = 0; + + si->ct->fid_tree = wmem_tree_new(wmem_file_scope()); + si->ct->tid_tree = wmem_tree_new(wmem_file_scope()); + si->ct->uid_tree = wmem_tree_new(wmem_file_scope()); + /* Initialize the GSL_fid_info for this ct */ + si->ct->GSL_fid_info = NULL; + conversation_add_proto_data(conversation, proto_smb, si->ct); + } + + 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 don't 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 */ + /* 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 + responses to this packet. For continuations, any later + responses we see really just belong to the original request. + Anyway, we want to remember this packet somehow and + remember which original request it is associated with so + we can say nice things such as "This is a Cancellation to + the request in frame x", but we don't want the + request/response matching to get messed up. + + The only thing we do in this case is trying to find which original + request we match with and insert an entry for this "special" + request for later reference. We continue to reference the original + requests smb_saved_info_t but we don't touch it or change anything + in it. + */ + + si->unidir = TRUE; /*we don't expect an answer to this one*/ + + if (!pinfo->fd->visited) { + /* try to find which original call we match and if we + find it add us to the matched table. Don't touch + anything else since we don't want this one to mess + up the request/response matching. We still consider + the initial call the real request and this is only + some sort of continuation. + */ + /* we only check the unmatched table and assume that the + last seen MID matching ours is the right one. + This can fail but is better than nothing + */ + sip = (smb_saved_info_t *)g_hash_table_lookup(si->ct->unmatched, GUINT_TO_POINTER(pid_mid)); + if (sip != NULL) { + new_key = wmem_new(wmem_file_scope(), smb_saved_info_key_t); + new_key->frame = pinfo->num; + new_key->pid_mid = pid_mid; + g_hash_table_insert(si->ct->matched, new_key, + sip); + } else { + if ((si->cmd == SMB_COM_TRANSACTION_SECONDARY) || + (si->cmd == SMB_COM_TRANSACTION2_SECONDARY) || + (si->cmd == SMB_COM_NT_TRANSACT_SECONDARY)) { + sip = (smb_saved_info_t *)g_hash_table_lookup(si->ct->primaries, GUINT_TO_POINTER(pid_mid)); + } + } + } else { + /* we have seen this packet before; check the + matching table + */ + key.frame = pinfo->num; + key.pid_mid = pid_mid; + sip = (smb_saved_info_t *)g_hash_table_lookup(si->ct->matched, &key); + if (sip == NULL) { + /* + We didn't find it. + Too bad, unfortunately there is not really much we can + do now since this means that we never saw the initial + request. + */ + } + } + + + if (sip && sip->frame_req) { + switch(si->cmd) { + case SMB_COM_NT_CANCEL: + tmp_item = proto_tree_add_uint(htree, hf_smb_cancel_to, + tvb, 0, 0, sip->frame_req); + proto_item_set_generated(tmp_item); + break; + case SMB_COM_TRANSACTION_SECONDARY: + case SMB_COM_TRANSACTION2_SECONDARY: + case SMB_COM_NT_TRANSACT_SECONDARY: + tmp_item = proto_tree_add_uint(htree, hf_smb_continuation_to, + tvb, 0, 0, sip->frame_req); + proto_item_set_generated(tmp_item); + break; + } + } else { + switch(si->cmd) { + case SMB_COM_NT_CANCEL: + proto_tree_add_uint_format_value(htree, hf_smb_cancel_to, tvb, 0, 0, 0, "<unknown frame>"); + break; + case SMB_COM_TRANSACTION_SECONDARY: + case SMB_COM_TRANSACTION2_SECONDARY: + case SMB_COM_NT_TRANSACT_SECONDARY: + proto_tree_add_uint_format_value(htree, hf_smb_continuation_to, tvb, 0, 0, 0, "<unknown frame>"); + break; + } + } + } else { /* normal bidirectional request or response */ + si->unidir = FALSE; + + if (!pinfo->fd->visited) { + /* first see if we find an unmatched smb "equal" to + the current one + */ + sip = (smb_saved_info_t *)g_hash_table_lookup(si->ct->unmatched, GUINT_TO_POINTER(pid_mid)); + if (sip != NULL) { + gboolean cmd_match = FALSE; + + /* + * Make sure the SMB we found was the + * same command, or a different command + * that's another valid type of reply + * to that command. + */ + if (si->cmd == sip->cmd) { + cmd_match = TRUE; + } + else if (si->cmd == SMB_COM_NT_CANCEL) { + cmd_match = TRUE; + } + else if ((si->cmd == SMB_COM_TRANSACTION_SECONDARY) + && (sip->cmd == SMB_COM_TRANSACTION)) { + cmd_match = TRUE; + } + 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) + && (sip->cmd == SMB_COM_NT_TRANSACT)) { + cmd_match = TRUE; + } + + if ( (si->request) || (!cmd_match) ) { + /* We are processing an SMB request but there was already + another "identical" smb request we had not matched yet. + This must mean that either we have a retransmission or that the + response to the previous one was lost and the client has reused + the MID for this conversation. In either case it's not much more + we can do than forget the old request and concentrate on the + present one instead. + + We also do this cleanup if we see that the cmd in the original + request in sip->cmd is not compatible with the current cmd. + This is to prevent matching errors such as if there were two + SMBs of different cmds but with identical MID and PID values and + if wireshark lost the first reply and the second request. + */ + g_hash_table_remove(si->ct->unmatched, GUINT_TO_POINTER(pid_mid)); + sip = NULL; /* XXX should free it as well */ + } else { + /* we have found a response to some + request we have seen earlier. + What we do now depends on whether + this is the first response to that + request we see (id frame_res == 0) or + if it's a response to a request + for which we've seen an earlier + response that's continued. + */ + if ((sip->frame_res == 0) || + (sip->flags & SMB_SIF_IS_CONTINUED)) { + /* OK, it is the first response + we have seen to this packet, + or it's a continuation of + a response we've seen. */ + sip->frame_res = pinfo->num; + new_key = wmem_new(wmem_file_scope(), smb_saved_info_key_t); + new_key->frame = sip->frame_res; + new_key->pid_mid = pid_mid; + g_hash_table_insert(si->ct->matched, new_key, sip); + /* We remove the entry for unmatched since we have found a match. + * We have to do this since the MID value wraps so quickly (effective only 10 bits) + * and if there is packetloss in the trace (maybe due to large holes + * created by a sniffer device not being able to keep up + * with the line rate. + * There is a real possibility that the following would occur which is painful : + * 1, -> Request MID:5 + * 2, <- Response MID:5 + * 3, -> Request MID:5 (missing from capture) + * 4, <- Response MID:5 + * We DON'T want #4 to be presented as a response to #1 + */ + g_hash_table_remove(si->ct->unmatched, GUINT_TO_POINTER(pid_mid)); + } else { + /* We have already seen another response to this MID. + Since the MID in reality is only something like 10 bits + this probably means that we just have a MID that is being + reused due to the small MID space and that this is a new + command we did not see the original request for. + */ + sip = NULL; + } + } + } else { + if ((si->cmd == SMB_COM_TRANSACTION) || + (si->cmd == SMB_COM_TRANSACTION2) || + (si->cmd == SMB_COM_NT_TRANSACT)) { + sip = (smb_saved_info_t *)g_hash_table_lookup(si->ct->primaries, GUINT_TO_POINTER(pid_mid)); + } + } + if (si->request) { + sip = wmem_new(wmem_file_scope(), smb_saved_info_t); + sip->frame_req = pinfo->num; + sip->frame_res = 0; + sip->req_time = pinfo->abs_ts; + sip->flags = 0; + if (g_hash_table_lookup(si->ct->tid_service, GUINT_TO_POINTER(si->tid)) + == (void *)TID_IPC) { + sip->flags |= SMB_SIF_TID_IS_IPC; + } + sip->cmd = si->cmd; + sip->extra_info = NULL; + sip->extra_info_type = SMB_EI_NONE; + sip->fid = 0; + sip->fid_seen_in_request = 0; + g_hash_table_insert(si->ct->unmatched, GUINT_TO_POINTER(pid_mid), sip); + new_key = wmem_new(wmem_file_scope(), smb_saved_info_key_t); + new_key->frame = sip->frame_req; + new_key->pid_mid = pid_mid; + g_hash_table_insert(si->ct->matched, new_key, sip); + + /* If it is a TRANSACT cmd, insert in hash */ + if ((si->cmd == SMB_COM_TRANSACTION) || + (si->cmd == SMB_COM_TRANSACTION2) || + (si->cmd == SMB_COM_NT_TRANSACT)) { + g_hash_table_insert(si->ct->primaries, GUINT_TO_POINTER(pid_mid), sip); + } + } + } else { + /* we have seen this packet before; check the + matching table. + If we haven't yet seen the reply, we won't + find the info for it; we don't need it, as + we only use it to save information, and, as + we've seen this packet before, we've already + saved the information. + */ + key.frame = pinfo->num; + key.pid_mid = pid_mid; + sip = (smb_saved_info_t *)g_hash_table_lookup(si->ct->matched, &key); + } + } + + /* + * Pass the "sip" on to subdissectors through "si". + */ + si->sip = sip; + + if (sip != NULL) { + /* + * Put in fields for the frame number of the frame to which + * 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 (sip->frame_res != 0) { + tmp_item = proto_tree_add_uint(htree, hf_smb_response_in, tvb, 0, 0, sip->frame_res); + proto_item_set_generated(tmp_item); + } + } else { + if (sip->frame_req != 0) { + tmp_item = proto_tree_add_uint(htree, hf_smb_response_to, tvb, 0, 0, sip->frame_req); + proto_item_set_generated(tmp_item); + t = pinfo->abs_ts; + nstime_delta(&deltat, &t, &sip->req_time); + tmp_item = proto_tree_add_time(htree, hf_smb_time, tvb, + 0, 0, &deltat); + proto_item_set_generated(tmp_item); + } + } + } + + /* smb command */ + proto_tree_add_uint(htree, hf_smb_cmd, tvb, offset, 1, si->cmd); + offset += 1; + + if (flags2 & 0x4000) { + /* handle NT 32 bit error code */ + + si->nt_status = tvb_get_letohl(tvb, offset); + + proto_tree_add_item(htree, hf_smb_nt_status, tvb, offset, 4, + ENC_LITTLE_ENDIAN); + offset += 4; + + } else { + /* handle DOS error code & class */ + errclass = tvb_get_guint8(tvb, offset); + proto_tree_add_uint(htree, hf_smb_error_class, tvb, offset, 1, + errclass); + offset += 1; + + /* reserved byte */ + proto_tree_add_item(htree, hf_smb_reserved, tvb, offset, 1, ENC_NA); + offset += 1; + + /* error code */ + /* XXX - the type of this field depends on the value of + * "errcls", so there is isn't a single value_string array + * fo it, so there can't be a single field for it. + */ + errcode = tvb_get_letohs(tvb, offset); + proto_tree_add_uint_format_value(htree, hf_smb_error_code, tvb, + offset, 2, errcode, "%s", + decode_smb_error(errclass, errcode)); + offset += 2; + } + + /* flags */ + offset = dissect_smb_flags(tvb, htree, offset); + + /* flags2 */ + offset = dissect_smb_flags2(tvb, htree, offset); + + /* + * The document at + * + * http://www.samba.org/samba/ftp/specs/smbpub.txt + * + * (a text version of "Microsoft Networks SMB FILE SHARING + * PROTOCOL, Document Version 6.0p") says that: + * + * the first 2 bytes of these 12 bytes are, for NT Create and X, + * the "High Part of PID"; + * + * the next four bytes are reserved; + * + * the next four bytes are, for SMB-over-IPX (with no + * NetBIOS involved) two bytes of Session ID and two bytes + * of SequenceNumber. + * + * Network Monitor 2.x dissects the four bytes before the Session ID + * as a "Key", and the two bytes after the SequenceNumber as + * a "Group ID". + * + * The "High Part of PID" has been seen in calls other than NT + * Create and X, although most of them appear to be I/O on DCE RPC + * pipes opened with the NT Create and X in question. + */ + proto_tree_add_item(htree, hf_smb_pid_high, tvb, offset, 2, ENC_LITTLE_ENDIAN); + offset += 2; + + if ((pinfo->ptype == PT_IPX) && + ((pinfo->match_uint == IPX_SOCKET_NWLINK_SMB_SERVER) || + (pinfo->match_uint == IPX_SOCKET_NWLINK_SMB_REDIR) || + (pinfo->match_uint == IPX_SOCKET_NWLINK_SMB_MESSENGER))) { + /* + * This is SMB-over-IPX. + * XXX - do we have to worry about "sequenced commands", + * as per the Samba document? They say that for + * "unsequenced commands" (with a sequence number of 0), + * the Mid must be unique, but perhaps the Mid doesn't + * have to be unique for sequenced commands. In at least + * one capture with SMB-over-IPX, however, the Mids + * are unique even for sequenced commands. + */ + /* Key */ + proto_tree_add_item(htree, hf_smb_key, tvb, offset, 4, + ENC_LITTLE_ENDIAN); + offset += 4; + + /* Session ID */ + proto_tree_add_item(htree, hf_smb_session_id, tvb, offset, 2, + ENC_LITTLE_ENDIAN); + offset += 2; + + /* Sequence number */ + proto_tree_add_item(htree, hf_smb_sequence_num, tvb, offset, 2, + ENC_LITTLE_ENDIAN); + offset += 2; + + /* Group ID */ + proto_tree_add_item(htree, hf_smb_group_id, tvb, offset, 2, + ENC_LITTLE_ENDIAN); + offset += 2; + } else { + /* + * According to http://ubiqx.org/cifs/SMB.html#SMB.4.2.1 + * and http://ubiqx.org/cifs/SMB.html#SMB.5.5.1 the 8 + * bytes after the "High part of PID" are an 8-byte + * signature ... + */ + proto_tree_add_item(htree, hf_smb_sig, tvb, offset, 8, ENC_NA); + offset += 8; + + proto_tree_add_item(htree, hf_smb_reserved, tvb, offset, 2, ENC_NA); + offset += 2; + } + + /* TID + * TreeConnectAndX(0x75) is special, here it is the mere fact of + * having a response that means that the share was mapped and we + * need to track it + */ + if (!pinfo->fd->visited && (si->cmd == 0x75) && !si->request) { + offset = dissect_smb_tid(tvb, pinfo, htree, offset, (guint16)si->tid, TRUE, FALSE, si); + } else { + offset = dissect_smb_tid(tvb, pinfo, htree, offset, (guint16)si->tid, FALSE, FALSE, si); + } + + /* PID */ + proto_tree_add_uint(htree, hf_smb_pid, tvb, offset, 2, si->pid); + offset += 2; + + /* UID */ + offset = dissect_smb_uid(tvb, htree, offset, si); + + /* MID */ + proto_tree_add_uint(htree, hf_smb_mid, tvb, offset, 2, si->mid); + offset += 2; + + /* tap the packet before the dissectors are called so we still get + the tap listener called even if there is an exception. + */ + tap_queue_packet(smb_tap, pinfo, si); + dissect_smb_command(tvb, pinfo, offset, tree, si->cmd, TRUE, si); + + /* Append error info from this packet to info string. */ + if (!si->request) { + if (flags2 & 0x4000) { + /* + * The status is an NT status code; was there + * an error? + */ + if ((si->nt_status & 0xC0000000) == 0xC0000000) { + /* + * Yes. + */ + col_append_fstr( + pinfo->cinfo, COL_INFO, ", Error: %s", + val_to_str_ext(si->nt_status, &NT_errors_ext, + "Unknown (0x%08X)")); + } + } else { + /* + * The status is a DOS error class and code; was + * there an error? + */ + if (errclass != SMB_SUCCESS) { + /* + * Yes. + */ + col_append_fstr( + pinfo->cinfo, COL_INFO, ", Error: %s", + decode_smb_error(errclass, errcode)); + } + } + } + return tvb_captured_length(tvb); +} + +static gboolean +dissect_smb_heur(tvbuff_t *tvb, packet_info *pinfo, proto_tree *parent_tree, void *data _U_) +{ + /* must check that this really is a smb packet */ + if (tvb_reported_length(tvb) < 4) + return FALSE; + + if ( (tvb_get_guint8(tvb, 0) != 0xff) + || (tvb_get_guint8(tvb, 1) != 'S') + || (tvb_get_guint8(tvb, 2) != 'M') + || (tvb_get_guint8(tvb, 3) != 'B') ) { + return FALSE; + } + + dissect_smb(tvb, pinfo, parent_tree, data); + return TRUE; +} + +void +proto_register_smb(void) +{ + static hf_register_info hf[] = { + { &hf_smb_cmd, + { "SMB Command", "smb.cmd", FT_UINT8, BASE_HEX|BASE_EXT_STRING, + &smb_cmd_vals_ext, 0x0, NULL, HFILL }}, + + { &hf_smb_andxcmd, + { "AndXCommand", "smb.cmd", FT_UINT8, BASE_HEX|BASE_EXT_STRING, + &smb_cmd_vals_ext, 0x0, NULL, HFILL }}, + + { &hf_smb_trans2_subcmd, + { "Subcommand", "smb.trans2.cmd", FT_UINT16, BASE_HEX|BASE_EXT_STRING, + &trans2_cmd_vals_ext, 0, "Subcommand for TRANSACTION2", HFILL }}, + + { &hf_smb_nt_trans_subcmd, + { "Function", "smb.nt.function", FT_UINT16, BASE_DEC|BASE_EXT_STRING, + &nt_cmd_vals_ext, 0, "Function for NT Transaction", HFILL }}, + + { &hf_smb_word_count, + { "Word Count (WCT)", "smb.wct", FT_UINT8, BASE_DEC, + NULL, 0x0, "Word Count, count of parameter words", HFILL }}, + + { &hf_smb_byte_count, + { "Byte Count (BCC)", "smb.bcc", FT_UINT16, BASE_DEC, + NULL, 0x0, "Byte Count, count of data bytes", HFILL }}, + + { &hf_smb_response_to, + { "Response to", "smb.response_to", FT_FRAMENUM, BASE_NONE, + NULL, 0, "This packet is a response to the packet in this frame", HFILL }}, + + { &hf_smb_time, + { "Time from request", "smb.time", FT_RELATIVE_TIME, BASE_NONE, + NULL, 0, "Time between Request and Response for SMB cmds", HFILL }}, + + { &hf_smb_response_in, + { "Response in", "smb.response_in", FT_FRAMENUM, BASE_NONE, + NULL, 0, "The response to this packet is in this packet", HFILL }}, + + { &hf_smb_continuation_to, + { "Continuation to", "smb.continuation_to", FT_FRAMENUM, BASE_NONE, + NULL, 0, "This packet is a continuation to the packet in this frame", HFILL }}, + + { &hf_smb_nt_status, + { "NT Status", "smb.nt_status", FT_UINT32, BASE_HEX | BASE_EXT_STRING, + &NT_errors_ext, 0, "NT Status code", HFILL }}, + + { &hf_smb_error_class, + { "Error Class", "smb.error_class", FT_UINT8, BASE_HEX, + VALS(errcls_types), 0, "DOS Error Class", HFILL }}, + + { &hf_smb_error_code, + { "Error Code", "smb.error_code", FT_UINT16, BASE_HEX, + NULL, 0, "DOS Error Code", HFILL }}, + + { &hf_smb_reserved, + { "Reserved", "smb.reserved", FT_BYTES, BASE_NONE, + NULL, 0, "Reserved bytes, must be zero", HFILL }}, + + { &hf_smb_sig, + { "Signature", "smb.signature", FT_BYTES, BASE_NONE, + NULL, 0, "Signature bytes", HFILL }}, + + { &hf_smb_key, + { "Key", "smb.key", FT_UINT32, BASE_HEX, + NULL, 0, "SMB-over-IPX Key", HFILL }}, + + { &hf_smb_session_id, + { "Session ID", "smb.sessid", FT_UINT16, BASE_DEC, + NULL, 0, "SMB-over-IPX Session ID", HFILL }}, + + { &hf_smb_sequence_num, + { "Sequence Number", "smb.sequence_num", FT_UINT16, BASE_DEC, + NULL, 0, "SMB-over-IPX Sequence Number", HFILL }}, + + { &hf_smb_group_id, + { "Group ID", "smb.group_id", FT_UINT16, BASE_DEC, + NULL, 0, "SMB-over-IPX Group ID", HFILL }}, + + { &hf_smb_pid, + { "Process ID", "smb.pid", FT_UINT16, BASE_DEC, + NULL, 0, NULL, HFILL }}, + + { &hf_smb_pid_high, + { "Process ID High", "smb.pid.high", FT_UINT16, BASE_DEC, + NULL, 0, "Process ID High Bytes", HFILL }}, + + { &hf_smb_tid, + { "Tree ID", "smb.tid", FT_UINT16, BASE_DEC, + NULL, 0, NULL, HFILL }}, + + { &hf_smb_uid, + { "User ID", "smb.uid", FT_UINT16, BASE_DEC, + NULL, 0, NULL, HFILL }}, + + { &hf_smb_mid, + { "Multiplex ID", "smb.mid", FT_UINT16, BASE_DEC, + NULL, 0, NULL, HFILL }}, + + { &hf_smb_flags, + { "Flags", "smb.flags", FT_UINT8, BASE_HEX, + NULL, 0x0, NULL, HFILL }}, + + { &hf_smb_flags_lock, + { "Lock and Read", "smb.flags.lock", FT_BOOLEAN, 8, + TFS(&tfs_smb_flags_lock), 0x01, "Are Lock&Read and Write&Unlock operations supported?", HFILL }}, + + { &hf_smb_flags_receive_buffer, + { "Receive Buffer Posted", "smb.flags.receive_buffer", FT_BOOLEAN, 8, + TFS(&tfs_smb_flags_receive_buffer), 0x02, "Have receive buffers been reported?", HFILL }}, + + { &hf_smb_flags_caseless, + { "Case Sensitivity", "smb.flags.caseless", FT_BOOLEAN, 8, + TFS(&tfs_smb_flags_caseless), 0x08, "Are pathnames caseless or casesensitive?", HFILL }}, + + { &hf_smb_flags_canon, + { "Canonicalized Pathnames", "smb.flags.canon", FT_BOOLEAN, 8, + TFS(&tfs_smb_flags_canon), 0x10, "Are pathnames canonicalized?", HFILL }}, + + { &hf_smb_flags_oplock, + { "Oplocks", "smb.flags.oplock", FT_BOOLEAN, 8, + TFS(&tfs_smb_flags_oplock), 0x20, "Is an oplock requested/granted?", HFILL }}, + + { &hf_smb_flags_notify, + { "Notify", "smb.flags.notify", FT_BOOLEAN, 8, + TFS(&tfs_smb_flags_notify), 0x40, "Notify on open or all?", HFILL }}, + + { &hf_smb_flags_response, + { "Request/Response", "smb.flags.response", FT_BOOLEAN, 8, + TFS(&tfs_smb_flags_response), 0x80, "Is this a request or a response?", HFILL }}, + + { &hf_smb_flags2, + { "Flags2", "smb.flags2", FT_UINT16, BASE_HEX, + NULL, 0x0, NULL, HFILL }}, + + { &hf_smb_flags2_long_names_allowed, + { "Long Names Allowed", "smb.flags2.long_names_allowed", FT_BOOLEAN, 16, + TFS(&tfs_smb_flags2_long_names_allowed), 0x0001, "Are long file names allowed in the response?", HFILL }}, + + { &hf_smb_flags2_ea, + { "Extended Attributes", "smb.flags2.ea", FT_BOOLEAN, 16, + TFS(&tfs_smb_flags2_ea), 0x0002, "Are extended attributes supported?", HFILL }}, + + { &hf_smb_flags2_sec_sig, + { "Security Signatures", "smb.flags2.sec_sig", FT_BOOLEAN, 16, + TFS(&tfs_smb_flags2_sec_sig), 0x0004, "Are security signatures supported?", HFILL }}, + + { &hf_smb_flags2_compressed, + { "Compressed", "smb.flags2.compressed", FT_BOOLEAN, 16, + TFS(&tfs_smb_flags2_compressed), 0x0008, "Is compression requested?", HFILL }}, + + { &hf_smb_flags2_sec_sig_required, + { "Security Signatures Required", "smb.flags2.sec_sig_required", FT_BOOLEAN, 16, + TFS(&tfs_smb_flags2_sec_sig_required), 0x0010, "Are security signatures required?", HFILL }}, + + { &hf_smb_flags2_long_names_used, + { "Long Names Used", "smb.flags2.long_names_used", FT_BOOLEAN, 16, + TFS(&tfs_smb_flags2_long_names_used), 0x0040, "Are pathnames in this request long file names?", HFILL }}, + + { &hf_smb_flags2_reparse_path, + { "Reparse Path", "smb.flags2.reparse_path", FT_BOOLEAN, 16, + TFS(&tfs_smb_flags2_reparse_path), 0x0400, "The request uses a @GMT reparse path", HFILL }}, + + { &hf_smb_flags2_esn, + { "Extended Security Negotiation", "smb.flags2.esn", FT_BOOLEAN, 16, + TFS(&tfs_smb_flags2_esn), 0x0800, "Is extended security negotiation supported?", HFILL }}, + + { &hf_smb_flags2_dfs, + { "Dfs", "smb.flags2.dfs", FT_BOOLEAN, 16, + TFS(&tfs_smb_flags2_dfs), 0x1000, "Can pathnames be resolved using Dfs?", HFILL }}, + + { &hf_smb_flags2_roe, + { "Execute-only Reads", "smb.flags2.roe", FT_BOOLEAN, 16, + TFS(&tfs_smb_flags2_roe), 0x2000, "Will reads be allowed for execute-only files?", HFILL }}, + + { &hf_smb_flags2_nt_error, + { "Error Code Type", "smb.flags2.nt_error", FT_BOOLEAN, 16, + TFS(&tfs_smb_flags2_nt_error), 0x4000, "Are error codes NT or DOS format?", HFILL }}, + + { &hf_smb_flags2_string, + { "Unicode Strings", "smb.flags2.string", FT_BOOLEAN, 16, + TFS(&tfs_smb_flags2_string), 0x8000, "Are strings ASCII or Unicode?", HFILL }}, + + { &hf_smb_buffer_format, + { "Buffer Format", "smb.buffer_format", FT_UINT8, BASE_DEC, + VALS(buffer_format_vals), 0x0, "Buffer Format, type of buffer", HFILL }}, + + { &hf_smb_dialect, + { "Dialect", "smb.dialect", FT_STRING, BASE_NONE, + NULL, 0x0, NULL, HFILL }}, + + { &hf_smb_dialect_name, + { "Name", "smb.dialect.name", FT_STRING, BASE_NONE, + NULL, 0, "Name of dialect", HFILL }}, + + { &hf_smb_dialect_index, + { "Selected Index", "smb.dialect.index", FT_UINT16, BASE_DEC, + NULL, 0, "Index of selected dialect", HFILL }}, + + { &hf_smb_max_trans_buf_size, + { "Max Buffer Size", "smb.max_bufsize", FT_UINT32, BASE_DEC, + NULL, 0, "Maximum transmit buffer size", HFILL }}, + + { &hf_smb_max_mpx_count, + { "Max Mpx Count", "smb.max_mpx_count", FT_UINT16, BASE_DEC, + NULL, 0, "Maximum pending multiplexed requests", HFILL }}, + + { &hf_smb_max_vcs_num, + { "Max VCs", "smb.max_vcs", FT_UINT16, BASE_DEC, + NULL, 0, "Maximum VCs between client and server", HFILL }}, + + { &hf_smb_session_key, + { "Session Key", "smb.session_key", FT_UINT32, BASE_HEX, + NULL, 0, "Unique token identifying this session", HFILL }}, + + { &hf_smb_server_timezone, + { "Server Time Zone", "smb.server_timezone", FT_INT16, BASE_DEC, + NULL, 0, "Current timezone at server.", HFILL }}, + + { &hf_smb_challenge_length, + { "Challenge Length", "smb.challenge_length", FT_UINT16, BASE_DEC, + NULL, 0, "Challenge_length (must be 0 if not LM2.1 dialect)", HFILL }}, + + { &hf_smb_challenge, + { "Challenge", "smb.challenge", FT_BYTES, BASE_NONE, + NULL, 0, "Challenge Data (for LM2.1 dialect)", HFILL }}, + + { &hf_smb_primary_domain, + { "Primary Domain", "smb.primary_domain", FT_STRING, BASE_NONE, + NULL, 0, "The server's primary domain", HFILL }}, + + { &hf_smb_server, + { "Server", "smb.server", FT_STRING, BASE_NONE, + NULL, 0, "The name of the DC/server", HFILL }}, + + { &hf_smb_max_raw_buf_size, + { "Max Raw Buffer", "smb.max_raw", FT_UINT32, BASE_DEC, + NULL, 0, "Maximum raw buffer size", HFILL }}, + + { &hf_smb_server_guid, + { "Server GUID", "smb.server_guid", FT_GUID, BASE_NONE, + NULL, 0, "Globally unique identifier for this server", HFILL }}, + + { &hf_smb_volume_guid, + { "Volume GUID", "smb.volume_guid", FT_GUID, BASE_NONE, + NULL, 0, "Globally unique identifier for this volume", HFILL }}, + + { &hf_smb_security_blob_len, + { "Security Blob Length", "smb.security_blob_len", FT_UINT16, BASE_DEC, + NULL, 0, NULL, HFILL }}, + + { &hf_smb_security_blob, + { "Security Blob", "smb.security_blob", FT_BYTES, BASE_NONE, + NULL, 0, NULL, HFILL }}, + + { &hf_smb_sm16, + { "Security Mode", "smb.sm", FT_UINT16, BASE_HEX, + NULL, 0x0, NULL, HFILL }}, + + { &hf_smb_sm_mode16, + { "Mode", "smb.sm.mode", FT_BOOLEAN, 16, + TFS(&tfs_sm_mode), SECURITY_MODE_MODE, "User or Share security mode?", HFILL }}, + + { &hf_smb_sm_password16, + { "Password", "smb.sm.password", FT_BOOLEAN, 16, + TFS(&tfs_sm_password), SECURITY_MODE_PASSWORD, "Encrypted or plaintext passwords?", HFILL }}, + + { &hf_smb_sm, + { "Security Mode", "smb.sm", FT_UINT8, BASE_HEX, + NULL, 0x0, NULL, HFILL }}, + + { &hf_smb_sm_mode, + { "Mode", "smb.sm.mode", FT_BOOLEAN, 8, + TFS(&tfs_sm_mode), SECURITY_MODE_MODE, "User or Share security mode?", HFILL }}, + + { &hf_smb_sm_password, + { "Password", "smb.sm.password", FT_BOOLEAN, 8, + TFS(&tfs_sm_password), SECURITY_MODE_PASSWORD, "Encrypted or plaintext passwords?", HFILL }}, + + { &hf_smb_sm_signatures, + { "Signatures", "smb.sm.signatures", FT_BOOLEAN, 8, + TFS(&tfs_sm_signatures), SECURITY_MODE_SIGNATURES, "Are security signatures enabled?", HFILL }}, + + { &hf_smb_sm_sig_required, + { "Sig Req", "smb.sm.sig_required", FT_BOOLEAN, 8, + TFS(&tfs_sm_sig_required), SECURITY_MODE_SIG_REQUIRED, "Are security signatures required?", HFILL }}, + + { &hf_smb_rm, + { "Raw Mode", "smb.rm", FT_UINT16, BASE_HEX, + NULL, 0x0, NULL, HFILL }}, + + { &hf_smb_rm_read, + { "Read Raw", "smb.rm.read", FT_BOOLEAN, 16, + TFS(&tfs_rm_read), RAWMODE_READ, "Is Read Raw supported?", HFILL }}, + + { &hf_smb_rm_write, + { "Write Raw", "smb.rm.write", FT_BOOLEAN, 16, + TFS(&tfs_rm_write), RAWMODE_WRITE, "Is Write Raw supported?", HFILL }}, + + { &hf_smb_server_date_time, + { "Server Date and Time", "smb.server_date_time", FT_ABSOLUTE_TIME, ABSOLUTE_TIME_LOCAL, + NULL, 0, "Current date and time at server", HFILL }}, + + { &hf_smb_server_smb_date, + { "Server Date", "smb.server_date_time.smb_date", FT_UINT16, BASE_HEX, + NULL, 0, "Current date at server, SMB_DATE format", HFILL }}, + + { &hf_smb_server_smb_time, + { "Server Time", "smb.server_date_time.smb_time", FT_UINT16, BASE_HEX, + NULL, 0, "Current time at server, SMB_TIME format", HFILL }}, + + { &hf_smb_server_cap, + { "Capabilities", "smb.server_cap", FT_UINT32, BASE_HEX, + NULL, 0x0, NULL, HFILL }}, + + { &hf_smb_server_cap_raw_mode, + { "Raw Mode", "smb.server_cap.raw_mode", FT_BOOLEAN, 32, + TFS(&tfs_server_cap_raw_mode), SERVER_CAP_RAW_MODE, "Are Raw Read and Raw Write supported?", HFILL }}, + + { &hf_smb_server_cap_mpx_mode, + { "MPX Mode", "smb.server_cap.mpx_mode", FT_BOOLEAN, 32, + TFS(&tfs_server_cap_mpx_mode), SERVER_CAP_MPX_MODE, "Are Read Mpx and Write Mpx supported?", HFILL }}, + + { &hf_smb_server_cap_unicode, + { "Unicode", "smb.server_cap.unicode", FT_BOOLEAN, 32, + TFS(&tfs_server_cap_unicode), SERVER_CAP_UNICODE, "Are Unicode strings supported?", HFILL }}, + + { &hf_smb_server_cap_large_files, + { "Large Files", "smb.server_cap.large_files", FT_BOOLEAN, 32, + TFS(&tfs_server_cap_large_files), SERVER_CAP_LARGE_FILES, "Are large files (>4GB) supported?", HFILL }}, + + { &hf_smb_server_cap_nt_smbs, + { "NT SMBs", "smb.server_cap.nt_smbs", FT_BOOLEAN, 32, + TFS(&tfs_server_cap_nt_smbs), SERVER_CAP_NT_SMBS, "Are NT SMBs supported?", HFILL }}, + + { &hf_smb_server_cap_rpc_remote_apis, + { "RPC Remote APIs", "smb.server_cap.rpc_remote_apis", FT_BOOLEAN, 32, + TFS(&tfs_server_cap_rpc_remote_apis), SERVER_CAP_RPC_REMOTE_APIS, "Are RPC Remote APIs supported?", HFILL }}, + + { &hf_smb_server_cap_nt_status, + { "NT Status Codes", "smb.server_cap.nt_status", FT_BOOLEAN, 32, + TFS(&tfs_server_cap_nt_status), SERVER_CAP_STATUS32, "Are NT Status Codes supported?", HFILL }}, + + { &hf_smb_server_cap_level_ii_oplocks, + { "Level 2 Oplocks", "smb.server_cap.level_2_oplocks", FT_BOOLEAN, 32, + TFS(&tfs_server_cap_level_ii_oplocks), SERVER_CAP_LEVEL_II_OPLOCKS, "Are Level 2 oplocks supported?", HFILL }}, + + { &hf_smb_server_cap_lock_and_read, + { "Lock and Read", "smb.server_cap.lock_and_read", FT_BOOLEAN, 32, + TFS(&tfs_server_cap_lock_and_read), SERVER_CAP_LOCK_AND_READ, "Is Lock and Read supported?", HFILL }}, + + { &hf_smb_server_cap_nt_find, + { "NT Find", "smb.server_cap.nt_find", FT_BOOLEAN, 32, + TFS(&tfs_server_cap_nt_find), SERVER_CAP_NT_FIND, "Is NT Find supported?", HFILL }}, + + { &hf_smb_server_cap_dfs, + { "Dfs", "smb.server_cap.dfs", FT_BOOLEAN, 32, + TFS(&tfs_server_cap_dfs), SERVER_CAP_DFS, "Is Dfs supported?", HFILL }}, + + { &hf_smb_server_cap_infolevel_passthru, + { "Infolevel Passthru", "smb.server_cap.infolevel_passthru", FT_BOOLEAN, 32, + TFS(&tfs_server_cap_infolevel_passthru), SERVER_CAP_INFOLEVEL_PASSTHRU, "Is NT information level request passthrough supported?", HFILL }}, + + { &hf_smb_server_cap_large_readx, + { "Large ReadX", "smb.server_cap.large_readx", FT_BOOLEAN, 32, + TFS(&tfs_server_cap_large_readx), SERVER_CAP_LARGE_READX, "Is Large Read andX supported?", HFILL }}, + + { &hf_smb_server_cap_large_writex, + { "Large WriteX", "smb.server_cap.large_writex", FT_BOOLEAN, 32, + TFS(&tfs_server_cap_large_writex), SERVER_CAP_LARGE_WRITEX, "Is Large Write andX supported?", HFILL }}, + + { &hf_smb_server_cap_lwio, + { "LWIO", "smb.server_cap.lwio", FT_BOOLEAN, 32, + TFS(&tfs_server_cap_lwio), SERVER_CAP_LWIO, + "Is IOCTL/FSCTL supported", HFILL }}, + + { &hf_smb_server_cap_unix, + { "UNIX", "smb.server_cap.unix", FT_BOOLEAN, 32, + TFS(&tfs_server_cap_unix), SERVER_CAP_UNIX , "Are UNIX extensions supported?", HFILL }}, + + { &hf_smb_server_cap_compressed_data, + { "Compressed Data", "smb.server_cap.compressed_data", FT_BOOLEAN, 32, + TFS(&tfs_server_cap_compressed_data), SERVER_CAP_COMPRESSED_DATA, "Is compressed data transfer supported?", HFILL }}, + + { &hf_smb_server_cap_dynamic_reauth, + { "Dynamic Reauth", "smb.server_cap.dynamic_reauth", FT_BOOLEAN, 32, + TFS(&tfs_server_cap_dynamic_reauth), SERVER_CAP_DYNAMIC_REAUTH, + "Is dynamic reauth supported?", HFILL }}, + + { &hf_smb_server_cap_extended_security, + { "Extended Security", "smb.server_cap.extended_security", FT_BOOLEAN, 32, + TFS(&tfs_server_cap_extended_security), SERVER_CAP_EXTENDED_SECURITY, "Are Extended security exchanges supported?", HFILL }}, + + { &hf_smb_system_time, + { "System Time", "smb.system.time", FT_ABSOLUTE_TIME, ABSOLUTE_TIME_LOCAL, + NULL, 0, NULL, HFILL }}, + + { &hf_smb_unknown, + { "Unknown Data", "smb.unknown_data", FT_BYTES, BASE_NONE, + NULL, 0, "Unknown Data. Should be implemented by someone", HFILL }}, + + { &hf_smb_dir_name, + { "Directory", "smb.dir_name", FT_STRING, BASE_NONE, + NULL, 0, "SMB Directory Name", HFILL }}, + + { &hf_smb_echo_count, + { "Echo Count", "smb.echo.count", FT_UINT16, BASE_DEC, + NULL, 0, "Number of times to echo data back", HFILL }}, + + { &hf_smb_echo_data, + { "Echo Data", "smb.echo.data", FT_BYTES, BASE_NONE, + NULL, 0, "Data for SMB Echo Request/Response", HFILL }}, + + { &hf_smb_echo_seq_num, + { "Echo Seq Num", "smb.echo.seq_num", FT_UINT16, BASE_DEC, + NULL, 0, "Sequence number for this echo response", HFILL }}, + + { &hf_smb_max_buf_size, + { "Max Buffer", "smb.max_buf", FT_UINT16, BASE_DEC, + NULL, 0, "Max client buffer size", HFILL }}, + + { &hf_smb_path, + { "Path", "smb.path", FT_STRING, BASE_NONE, + NULL, 0, "Path. Server name and share name", HFILL }}, + + { &hf_smb_service, + { "Service", "smb.service", FT_STRING, BASE_NONE, + NULL, 0, "Service name", HFILL }}, + + { &hf_smb_password, + { "Password", "smb.password", FT_BYTES, BASE_NONE, + NULL, 0, NULL, HFILL }}, + + { &hf_smb_ansi_password, + { "ANSI Password", "smb.ansi_password", FT_BYTES, BASE_NONE, + NULL, 0, NULL, HFILL }}, + + { &hf_smb_unicode_password, + { "Unicode Password", "smb.unicode_password", FT_BYTES, BASE_NONE, + NULL, 0, NULL, HFILL }}, + + { &hf_smb_move_flags, + { "Flags", "smb.move.flags", FT_UINT16, BASE_HEX, + NULL, 0x0, NULL, HFILL }}, + + { &hf_smb_move_flags_file, + { "Must be file", "smb.move.flags.file", FT_BOOLEAN, 16, + TFS(&tfs_mf_file), 0x0001, "Must target be a file?", HFILL }}, + + { &hf_smb_move_flags_dir, + { "Must be directory", "smb.move.flags.dir", FT_BOOLEAN, 16, + TFS(&tfs_mf_dir), 0x0002, "Must target be a directory?", HFILL }}, + + { &hf_smb_move_flags_verify, + { "Verify writes", "smb.move.flags.verify", FT_BOOLEAN, 16, + TFS(&tfs_mf_verify), 0x0010, "Verify all writes?", HFILL }}, + + { &hf_smb_files_moved, + { "Files Moved", "smb.files_moved", FT_UINT16, BASE_DEC, + NULL, 0, "Number of files moved", HFILL }}, + + { &hf_smb_copy_flags, + { "Flags", "smb.copy.flags", FT_UINT16, BASE_HEX, + NULL, 0x0, NULL, HFILL }}, + + { &hf_smb_copy_flags_file, + { "Must be file", "smb.copy.flags.file", FT_BOOLEAN, 16, + TFS(&tfs_mf_file), 0x0001, "Must target be a file?", HFILL }}, + + { &hf_smb_copy_flags_dir, + { "Must be directory", "smb.copy.flags.dir", FT_BOOLEAN, 16, + TFS(&tfs_mf_dir), 0x0002, "Must target be a directory?", HFILL }}, + + { &hf_smb_copy_flags_dest_mode, + { "Destination mode", "smb.copy.flags.dest_mode", FT_BOOLEAN, 16, + TFS(&tfs_cf_mode), 0x0004, "Is destination in ASCII?", HFILL }}, + + { &hf_smb_copy_flags_source_mode, + { "Source mode", "smb.copy.flags.source_mode", FT_BOOLEAN, 16, + TFS(&tfs_cf_mode), 0x0008, "Is source in ASCII?", HFILL }}, + + { &hf_smb_copy_flags_verify, + { "Verify writes", "smb.copy.flags.verify", FT_BOOLEAN, 16, + TFS(&tfs_mf_verify), 0x0010, "Verify all writes?", HFILL }}, + + { &hf_smb_copy_flags_tree_copy, + { "Tree copy", "smb.copy.flags.tree_copy", FT_BOOLEAN, 16, + TFS(&tfs_cf_tree_copy), 0x0020, "Is copy a tree copy?", HFILL }}, + + { &hf_smb_copy_flags_ea_action, + { "EA action if EAs not supported on dest", "smb.copy.flags.ea_action", FT_BOOLEAN, 16, + TFS(&tfs_cf_ea_action), 0x0040, "Fail copy if source file has EAs and dest doesn't support EAs?", HFILL }}, + + { &hf_smb_count, + { "Count", "smb.count", FT_UINT32, BASE_DEC, + NULL, 0, "Count number of items/bytes", HFILL }}, + + { &hf_smb_count_low, + { "Count Low", "smb.count_low", FT_UINT16, BASE_DEC, + NULL, 0, "Count number of items/bytes, Low 16 bits", HFILL }}, + + { &hf_smb_count_high, + { "Count High (multiply with 64K)", "smb.count_high", FT_UINT16, BASE_DEC, + NULL, 0, "Count number of items/bytes, High 16 bits", HFILL }}, + + { &hf_smb_file_name, + { "File Name", "smb.file", FT_STRING, BASE_NONE, + NULL, 0, NULL, HFILL }}, + + { &hf_smb_open_function, + { "Open Function", "smb.open.function", FT_UINT16, BASE_HEX, + NULL, 0x0, NULL, HFILL }}, + + { &hf_smb_open_function_create, + { "Create", "smb.open.function.create", FT_BOOLEAN, 16, + TFS(&tfs_of_create), 0x0010, "Create file if it doesn't exist?", HFILL }}, + + { &hf_smb_open_function_open, + { "Open", "smb.open.function.open", FT_UINT16, BASE_DEC, + VALS(of_open), 0x0003, "Action to be taken on open if file exists", HFILL }}, + + { &hf_smb_fid, + { "FID", "smb.fid", FT_UINT16, BASE_HEX, + NULL, 0, "FID: File ID", HFILL }}, + + { &hf_smb_file_attr_16bit, + { "File Attributes", "smb.file_attribute", FT_UINT16, BASE_HEX, + NULL, 0x0, NULL, HFILL }}, + + { &hf_smb_file_attr_8bit, + { "File Attributes", "smb.file_attribute", FT_UINT8, BASE_HEX, + NULL, 0x0, NULL, HFILL }}, + + { &hf_smb_file_attr_read_only_16bit, + { "Read Only", "smb.file_attribute.read_only", FT_BOOLEAN, 16, + TFS(&tfs_file_attribute_read_only), SMB_FILE_ATTRIBUTE_READ_ONLY, "READ ONLY file attribute", HFILL }}, + + { &hf_smb_file_attr_read_only_8bit, + { "Read Only", "smb.file_attribute.read_only", FT_BOOLEAN, 8, + TFS(&tfs_file_attribute_read_only), SMB_FILE_ATTRIBUTE_READ_ONLY, "READ ONLY file attribute", HFILL }}, + + { &hf_smb_file_attr_hidden_16bit, + { "Hidden", "smb.file_attribute.hidden", FT_BOOLEAN, 16, + TFS(&tfs_file_attribute_hidden), SMB_FILE_ATTRIBUTE_HIDDEN, "HIDDEN file attribute", HFILL }}, + + { &hf_smb_file_attr_hidden_8bit, + { "Hidden", "smb.file_attribute.hidden", FT_BOOLEAN, 8, + TFS(&tfs_file_attribute_hidden), SMB_FILE_ATTRIBUTE_HIDDEN, "HIDDEN file attribute", HFILL }}, + + { &hf_smb_file_attr_system_16bit, + { "System", "smb.file_attribute.system", FT_BOOLEAN, 16, + TFS(&tfs_file_attribute_system), SMB_FILE_ATTRIBUTE_SYSTEM, "SYSTEM file attribute", HFILL }}, + + { &hf_smb_file_attr_system_8bit, + { "System", "smb.file_attribute.system", FT_BOOLEAN, 8, + TFS(&tfs_file_attribute_system), SMB_FILE_ATTRIBUTE_SYSTEM, "SYSTEM file attribute", HFILL }}, + + { &hf_smb_file_attr_volume_16bit, + { "Volume ID", "smb.file_attribute.volume", FT_BOOLEAN, 16, + TFS(&tfs_file_attribute_volume), SMB_FILE_ATTRIBUTE_VOLUME, "VOLUME file attribute", HFILL }}, + + { &hf_smb_file_attr_volume_8bit, + { "Volume ID", "smb.file_attribute.volume", FT_BOOLEAN, 8, + TFS(&tfs_file_attribute_volume), SMB_FILE_ATTRIBUTE_VOLUME, "VOLUME ID file attribute", HFILL }}, + + { &hf_smb_file_attr_directory_16bit, + { "Directory", "smb.file_attribute.directory", FT_BOOLEAN, 16, + TFS(&tfs_file_attribute_directory), SMB_FILE_ATTRIBUTE_DIRECTORY, "DIRECTORY file attribute", HFILL }}, + + { &hf_smb_file_attr_directory_8bit, + { "Directory", "smb.file_attribute.directory", FT_BOOLEAN, 8, + TFS(&tfs_file_attribute_directory), SMB_FILE_ATTRIBUTE_DIRECTORY, "DIRECTORY file attribute", HFILL }}, + + { &hf_smb_file_attr_archive_16bit, + { "Archive", "smb.file_attribute.archive", FT_BOOLEAN, 16, + TFS(&tfs_file_attribute_archive), SMB_FILE_ATTRIBUTE_ARCHIVE, "ARCHIVE file attribute", HFILL }}, + + { &hf_smb_file_attr_archive_8bit, + { "Archive", "smb.file_attribute.archive", FT_BOOLEAN, 8, + TFS(&tfs_file_attribute_archive), SMB_FILE_ATTRIBUTE_ARCHIVE, "ARCHIVE file attribute", HFILL }}, + +#if 0 + { &hf_smb_file_attr_device, + { "Device", "smb.file_attribute.device", FT_BOOLEAN, 16, + TFS(&tfs_file_attribute_device), SMB_FILE_ATTRIBUTE_DEVICE, "Is this file a device?", HFILL }}, + + { &hf_smb_file_attr_normal, + { "Normal", "smb.file_attribute.normal", FT_BOOLEAN, 16, + TFS(&tfs_file_attribute_normal), SMB_FILE_ATTRIBUTE_NORMAL, "Is this a normal file?", HFILL }}, + + { &hf_smb_file_attr_temporary, + { "Temporary", "smb.file_attribute.temporary", FT_BOOLEAN, 16, + TFS(&tfs_file_attribute_temporary), SMB_FILE_ATTRIBUTE_TEMPORARY, "Is this a temporary file?", HFILL }}, + + { &hf_smb_file_attr_sparse, + { "Sparse", "smb.file_attribute.sparse", FT_BOOLEAN, 16, + TFS(&tfs_file_attribute_sparse), SMB_FILE_ATTRIBUTE_SPARSE, "Is this a sparse file?", HFILL }}, + + { &hf_smb_file_attr_reparse, + { "Reparse Point", "smb.file_attribute.reparse", FT_BOOLEAN, 16, + TFS(&tfs_file_attribute_reparse), SMB_FILE_ATTRIBUTE_REPARSE, "Does this file have an associated reparse point?", HFILL }}, + + { &hf_smb_file_attr_compressed, + { "Compressed", "smb.file_attribute.compressed", FT_BOOLEAN, 16, + TFS(&tfs_file_attribute_compressed), SMB_FILE_ATTRIBUTE_COMPRESSED, "Is this file compressed?", HFILL }}, + + { &hf_smb_file_attr_offline, + { "Offline", "smb.file_attribute.offline", FT_BOOLEAN, 16, + TFS(&tfs_file_attribute_offline), SMB_FILE_ATTRIBUTE_OFFLINE, "Is this file offline?", HFILL }}, + + { &hf_smb_file_attr_not_content_indexed, + { "Content Indexed", "smb.file_attribute.not_content_indexed", FT_BOOLEAN, 16, + TFS(&tfs_file_attribute_not_content_indexed), SMB_FILE_ATTRIBUTE_NOT_CONTENT_INDEXED, "May this file be indexed by the content indexing service", HFILL }}, + + { &hf_smb_file_attr_encrypted, + { "Encrypted", "smb.file_attribute.encrypted", FT_BOOLEAN, 16, + TFS(&tfs_file_attribute_encrypted), SMB_FILE_ATTRIBUTE_ENCRYPTED, "Is this file encrypted?", HFILL }}, +#endif + + { &hf_smb_file_size, + { "File Size", "smb.file_size", FT_UINT32, BASE_DEC, + NULL, 0, NULL, HFILL }}, + + { &hf_smb_search_attribute, + { "Search Attributes", "smb.search.attribute", FT_UINT16, BASE_HEX, + NULL, 0x0, NULL, HFILL }}, + + { &hf_smb_search_attribute_read_only, + { "Read Only", "smb.search.attribute.read_only", FT_BOOLEAN, 16, + TFS(&tfs_search_attribute_read_only), SMB_FILE_ATTRIBUTE_READ_ONLY, "READ ONLY search attribute", HFILL }}, + + { &hf_smb_search_attribute_hidden, + { "Hidden", "smb.search.attribute.hidden", FT_BOOLEAN, 16, + TFS(&tfs_search_attribute_hidden), SMB_FILE_ATTRIBUTE_HIDDEN, "HIDDEN search attribute", HFILL }}, + + { &hf_smb_search_attribute_system, + { "System", "smb.search.attribute.system", FT_BOOLEAN, 16, + TFS(&tfs_search_attribute_system), SMB_FILE_ATTRIBUTE_SYSTEM, "SYSTEM search attribute", HFILL }}, + + { &hf_smb_search_attribute_volume, + { "Volume ID", "smb.search.attribute.volume", FT_BOOLEAN, 16, + TFS(&tfs_search_attribute_volume), SMB_FILE_ATTRIBUTE_VOLUME, "VOLUME ID search attribute", HFILL }}, + + { &hf_smb_search_attribute_directory, + { "Directory", "smb.search.attribute.directory", FT_BOOLEAN, 16, + TFS(&tfs_search_attribute_directory), SMB_FILE_ATTRIBUTE_DIRECTORY, "DIRECTORY search attribute", HFILL }}, + + { &hf_smb_search_attribute_archive, + { "Archive", "smb.search.attribute.archive", FT_BOOLEAN, 16, + TFS(&tfs_search_attribute_archive), SMB_FILE_ATTRIBUTE_ARCHIVE, "ARCHIVE search attribute", HFILL }}, + + { &hf_smb_access_mode, + { "Access Mode", "smb.access.mode", FT_UINT16, BASE_DEC, + VALS(da_access_vals), 0x0007, NULL, HFILL }}, + + { &hf_smb_access_sharing, + { "Sharing Mode", "smb.access.sharing", FT_UINT16, BASE_DEC, + VALS(da_sharing_vals), 0x0070, NULL, HFILL }}, + + { &hf_smb_access_locality, + { "Locality", "smb.access.locality", FT_UINT16, BASE_DEC, + VALS(da_locality_vals), 0x0700, "Locality of reference", HFILL }}, + + { &hf_smb_access_caching, + { "Caching", "smb.access.caching", FT_BOOLEAN, 16, + TFS(&tfs_da_caching), 0x1000, "Caching mode?", HFILL }}, + + { &hf_smb_desired_access, + { "Desired Access", "smb.access.desired", FT_UINT16, BASE_HEX, + NULL, 0x0, NULL, HFILL }}, + + { &hf_smb_granted_access, + { "Granted Access", "smb.access.granted", FT_UINT16, BASE_HEX, + NULL, 0x0, NULL, HFILL }}, + + { &hf_smb_access_writetru, + { "Writethrough", "smb.access.writethrough", FT_BOOLEAN, 16, + TFS(&tfs_da_writetru), 0x4000, "Writethrough mode?", HFILL }}, + + { &hf_smb_create_time, + { "Created", "smb.create.time", FT_ABSOLUTE_TIME, ABSOLUTE_TIME_LOCAL, + NULL, 0, "Creation Time", HFILL }}, + + { &hf_smb_modify_time, + { "Modified", "smb.modify.time", FT_ABSOLUTE_TIME, ABSOLUTE_TIME_LOCAL, + NULL, 0, "Modification Time", HFILL }}, + + { &hf_smb_backup_time, + { "Backed-up", "smb.backup.time", FT_ABSOLUTE_TIME, ABSOLUTE_TIME_LOCAL, + NULL, 0, "Backup time", HFILL}}, + + { &hf_smb_mac_alloc_block_count, + { "Allocation Block Count", "smb.alloc.count", FT_UINT32, BASE_DEC, + NULL, 0, NULL, HFILL}}, + + { &hf_smb_mac_alloc_block_size, + { "Allocation Block Count", "smb.alloc.size", FT_UINT32, BASE_DEC, + NULL, 0, "Allocation Block Size", HFILL}}, + + { &hf_smb_mac_free_block_count, + { "Free Block Count", "smb.free_block.count", FT_UINT32, BASE_DEC, + NULL, 0, NULL, HFILL}}, + + { &hf_smb_mac_root_file_count, + { "Root File Count", "smb.root.file.count", FT_UINT32, BASE_DEC, + NULL, 0, NULL, HFILL}}, + + { &hf_smb_mac_root_dir_count, + { "Root Directory Count", "smb.root.dir.count", FT_UINT32, BASE_DEC, + NULL, 0, NULL, HFILL}}, + + { &hf_smb_mac_file_count, + { "Root File Count", "smb.file.count", FT_UINT32, BASE_DEC, + NULL, 0, "File Count", HFILL}}, + + { &hf_smb_mac_dir_count, + { "Root Directory Count", "smb.dir.count", FT_UINT32, BASE_DEC, + NULL, 0, "Directory Count", HFILL}}, + + { &hf_smb_mac_sup, + { "Mac Support Flags", "smb.mac", FT_UINT32, BASE_HEX, + NULL, 0x0, NULL, HFILL }}, + + { &hf_smb_mac_sup_access_ctrl, + { "Mac Access Control", "smb.mac.access_control", FT_BOOLEAN, 32, + TFS(&tfs_smb_mac_access_ctrl), 0x00000010, "Are Mac Access Control Supported", HFILL }}, + + { &hf_smb_mac_sup_getset_comments, + { "Get Set Comments", "smb.mac.get_set_comments", FT_BOOLEAN, 32, + TFS(&tfs_smb_mac_getset_comments), 0x00000020, "Are Mac Get Set Comments supported?", HFILL }}, + + { &hf_smb_mac_sup_desktopdb_calls, + { "Desktop DB Calls", "smb.mac.desktop_db_calls", FT_BOOLEAN, 32, + TFS(&tfs_smb_mac_desktopdb_calls), 0x00000040, "Are Macintosh Desktop DB Calls Supported?", HFILL }}, + + { &hf_smb_mac_sup_unique_ids, + { "Macintosh Unique IDs", "smb.mac.uids", FT_BOOLEAN, 32, + TFS(&tfs_smb_mac_unique_ids), 0x00000080, "Are Unique IDs supported", HFILL }}, + + { &hf_smb_mac_sup_streams, + { "Mac Streams", "smb.mac.streams_support", FT_BOOLEAN, 32, + TFS(&tfs_smb_mac_streams), 0x00000100, "Are Mac Extensions and streams supported?", HFILL }}, + + { &hf_smb_create_dos_date, + { "Create Date", "smb.create.smb.date", FT_UINT16, BASE_HEX, + NULL, 0, "Create Date, SMB_DATE format", HFILL }}, + + { &hf_smb_create_dos_time, + { "Create Time", "smb.create.smb.time", FT_UINT16, BASE_HEX, + NULL, 0, "Create Time, SMB_TIME format", HFILL }}, + + { &hf_smb_last_write_time, + { "Last Write", "smb.last_write.time", FT_ABSOLUTE_TIME, ABSOLUTE_TIME_LOCAL, + NULL, 0, "Time this file was last written to", HFILL }}, + + { &hf_smb_last_write_dos_date, + { "Last Write Date", "smb.last_write.smb.date", FT_UINT16, BASE_HEX, + NULL, 0, "Last Write Date, SMB_DATE format", HFILL }}, + + { &hf_smb_last_write_dos_time, + { "Last Write Time", "smb.last_write.smb.time", FT_UINT16, BASE_HEX, + NULL, 0, "Last Write Time, SMB_TIME format", HFILL }}, + + { &hf_smb_old_file_name, + { "Old File Name", "smb.old_file", FT_STRING, BASE_NONE, + NULL, 0, "Old File Name (When renaming a file)", HFILL }}, + + { &hf_smb_offset, + { "Offset", "smb.offset", FT_UINT32, BASE_DEC, + NULL, 0, "Offset in file", HFILL }}, + + { &hf_smb_remaining, + { "Remaining", "smb.remaining", FT_UINT32, BASE_DEC, + NULL, 0, "Remaining number of bytes", HFILL }}, + + { &hf_smb_padding, + { "Padding", "smb.padding", FT_BYTES, BASE_NONE, + NULL, 0, "Padding or unknown data", HFILL }}, + + { &hf_smb_file_data, + { "File Data", "smb.file_data", FT_BYTES, BASE_NONE, + NULL, 0, "Data read/written to the file", HFILL }}, + +#if 0 + { &hf_smb_raw_ea_data, + { "EA Data", "smb.ea_data", FT_BYTES, BASE_NONE, + NULL, 0, "Data in EA list", HFILL }}, +#endif + + { &hf_smb_mac_fndrinfo, + { "Finder Info", "smb.mac.finderinfo", FT_BYTES, BASE_NONE, + NULL, 0, NULL, HFILL}}, + + { &hf_smb_total_data_len, + { "Total Data Length", "smb.total_data_len", FT_UINT16, BASE_DEC, + NULL, 0, "Total length of data", HFILL }}, + + { &hf_smb_data_len, + { "Data Length", "smb.data_len", FT_UINT16, BASE_DEC, + NULL, 0, "Length of data", HFILL }}, + + { &hf_smb_data_len_low, + { "Data Length Low", "smb.data_len_low", FT_UINT16, BASE_DEC, + NULL, 0, "Length of data, Low 16 bits", HFILL }}, + + { &hf_smb_data_len_high, + { "Data Length High (multiply with 64K)", "smb.data_len_high", FT_UINT16, BASE_DEC, + NULL, 0, "Length of data, High 16 bits", HFILL }}, + + { &hf_smb_seek_mode, + { "Seek Mode", "smb.seek_mode", FT_UINT16, BASE_DEC, + VALS(seek_mode_vals), 0, "Seek Mode, what type of seek", HFILL }}, + + { &hf_smb_access_time, + { "Last Access", "smb.access.time", FT_ABSOLUTE_TIME, ABSOLUTE_TIME_LOCAL, + NULL, 0, "Last Access Time", HFILL }}, + + { &hf_smb_access_dos_date, + { "Last Access Date", "smb.access.smb.date", FT_UINT16, BASE_HEX, + NULL, 0, "Last Access Date, SMB_DATE format", HFILL }}, + + { &hf_smb_access_dos_time, + { "Last Access Time", "smb.access.smb.time", FT_UINT16, BASE_HEX, + NULL, 0, "Last Access Time, SMB_TIME format", HFILL }}, + + { &hf_smb_data_size, + { "Data Size", "smb.data_size", FT_UINT32, BASE_DEC, + NULL, 0, NULL, HFILL }}, + + { &hf_smb_alloc_size, + { "Allocation Size", "smb.alloc_size", FT_UINT32, BASE_DEC, + NULL, 0, "Number of bytes to reserve on create or truncate", HFILL }}, + + { &hf_smb_max_count, + { "Max Count", "smb.maxcount", FT_UINT16, BASE_DEC, + NULL, 0, "Maximum Count", HFILL }}, + + { &hf_smb_max_count_low, + { "Max Count Low", "smb.maxcount_low", FT_UINT16, BASE_DEC, + NULL, 0, "Maximum Count, Low 16 bits", HFILL }}, + + { &hf_smb_max_count_high, + { "Max Count High (multiply with 64K)", "smb.maxcount_high", FT_UINT16, BASE_DEC, + NULL, 0, "Maximum Count, High 16 bits", HFILL }}, + + { &hf_smb_min_count, + { "Min Count", "smb.mincount", FT_UINT16, BASE_DEC, + NULL, 0, "Minimum Count", HFILL }}, + + { &hf_smb_timeout, + { "Timeout", "smb.timeout", FT_UINT32, BASE_DEC, + NULL, 0, "Timeout in milliseconds", HFILL }}, + + { &hf_smb_high_offset, + { "High Offset", "smb.offset_high", FT_UINT32, BASE_DEC, + NULL, 0, "High 32 Bits Of File Offset", HFILL }}, + + { &hf_smb_units, + { "Total Units", "smb.units", FT_UINT16, BASE_DEC, + NULL, 0, "Total number of units at server", HFILL }}, + + { &hf_smb_bpu, + { "Blocks Per Unit", "smb.bpu", FT_UINT16, BASE_DEC, + NULL, 0, "Blocks per unit at server", HFILL }}, + + { &hf_smb_blocksize, + { "Block Size", "smb.blocksize", FT_UINT16, BASE_DEC, + NULL, 0, "Block size (in bytes) at server", HFILL }}, + + { &hf_smb_freeunits, + { "Free Units", "smb.free_units", FT_UINT16, BASE_DEC, + NULL, 0, "Number of free units at server", HFILL }}, + + { &hf_smb_data_offset, + { "Data Offset", "smb.data_offset", FT_UINT16, BASE_DEC, + NULL, 0, NULL, HFILL }}, + + { &hf_smb_dcm, + { "Data Compaction Mode", "smb.dcm", FT_UINT16, BASE_DEC, + NULL, 0, NULL, HFILL }}, + + { &hf_smb_request_mask, + { "Request Mask", "smb.request.mask", FT_UINT32, BASE_HEX, + NULL, 0, "Connectionless mode mask", HFILL }}, + + { &hf_smb_response_mask, + { "Response Mask", "smb.response.mask", FT_UINT32, BASE_HEX, + NULL, 0, "Connectionless mode mask", HFILL }}, + + { &hf_smb_search_id, + { "Search ID", "smb.search_id", FT_UINT16, BASE_HEX, + NULL, 0, "Search ID, handle for find operations", HFILL }}, + + { &hf_smb_write_mode, + { "Write Mode", "smb.write.mode", FT_UINT16, BASE_HEX, + NULL, 0x0, NULL, HFILL }}, + + { &hf_smb_write_mode_write_through, + { "Write Through", "smb.write.mode.write_through", FT_BOOLEAN, 16, + TFS(&tfs_write_mode_write_through), WRITE_MODE_WRITE_THROUGH, "Write through mode requested?", HFILL }}, + + { &hf_smb_write_mode_return_remaining, + { "Return Remaining", "smb.write.mode.return_remaining", FT_BOOLEAN, 16, + TFS(&tfs_write_mode_return_remaining), WRITE_MODE_RETURN_REMAINING, "Return remaining data responses?", HFILL }}, + + { &hf_smb_write_mode_raw, + { "Write Raw", "smb.write.mode.raw", FT_BOOLEAN, 16, + TFS(&tfs_write_mode_raw), WRITE_MODE_RAW, "Use WriteRawNamedPipe?", HFILL }}, + + { &hf_smb_write_mode_message_start, + { "Message Start", "smb.write.mode.message_start", FT_BOOLEAN, 16, + TFS(&tfs_write_mode_message_start), WRITE_MODE_MESSAGE_START, "Is this the start of a message?", HFILL }}, + + { &hf_smb_write_mode_connectionless, + { "Connectionless", "smb.write.mode.connectionless", FT_BOOLEAN, 16, + TFS(&tfs_write_mode_connectionless), WRITE_MODE_CONNECTIONLESS, "Connectionless mode requested?", HFILL }}, + + { &hf_smb_resume_key_len, + { "Resume Key Length", "smb.resume.key_len", FT_UINT16, BASE_DEC, + NULL, 0, NULL, HFILL }}, + + { &hf_smb_resume_find_id, + { "Find ID", "smb.resume.find_id", FT_UINT8, BASE_HEX, + NULL, 0, "Handle for Find operation", HFILL }}, + + { &hf_smb_resume_server_cookie, + { "Server Cookie", "smb.resume.server.cookie", FT_BYTES, BASE_NONE, + NULL, 0, "Cookie, must not be modified by the client", HFILL }}, + + { &hf_smb_resume_client_cookie, + { "Client Cookie", "smb.resume.client.cookie", FT_BYTES, BASE_NONE, + NULL, 0, "Cookie, must not be modified by the server", HFILL }}, + + { &hf_smb_andxoffset, + { "AndXOffset", "smb.andxoffset", FT_UINT16, BASE_DEC, + NULL, 0, "Offset to next command in this SMB packet", HFILL }}, + + { &hf_smb_lock_type, + { "Lock Type", "smb.lock.type", FT_UINT8, BASE_HEX, + NULL, 0x0, NULL, HFILL }}, + + { &hf_smb_lock_type_large, + { "Large Files", "smb.lock.type.large", FT_BOOLEAN, 8, + TFS(&tfs_lock_type_large), 0x10, "Large file locking requested?", HFILL }}, + + { &hf_smb_lock_type_cancel, + { "Cancel", "smb.lock.type.cancel", FT_BOOLEAN, 8, + TFS(&tfs_lock_type_cancel), 0x08, "Cancel outstanding lock requests?", HFILL }}, + + { &hf_smb_lock_type_change, + { "Change", "smb.lock.type.change", FT_BOOLEAN, 8, + TFS(&tfs_lock_type_change), 0x04, "Change type of lock?", HFILL }}, + + { &hf_smb_lock_type_oplock, + { "Oplock Break", "smb.lock.type.oplock_release", FT_BOOLEAN, 8, + TFS(&tfs_lock_type_oplock), 0x02, "Is this a notification of, or a response to, an oplock break?", HFILL }}, + + { &hf_smb_lock_type_shared, + { "Shared", "smb.lock.type.shared", FT_BOOLEAN, 8, + TFS(&tfs_lock_type_shared), 0x01, "Shared or exclusive lock requested?", HFILL }}, + + { &hf_smb_locking_ol, + { "Oplock Level", "smb.locking.oplock.level", FT_UINT8, BASE_DEC, + VALS(locking_ol_vals), 0, "Level of existing oplock at client (if any)", HFILL }}, + + { &hf_smb_number_of_locks, + { "Number of Locks", "smb.locking.num_locks", FT_UINT16, BASE_DEC, + NULL, 0, "Number of lock requests in this request", HFILL }}, + + { &hf_smb_number_of_unlocks, + { "Number of Unlocks", "smb.locking.num_unlocks", FT_UINT16, BASE_DEC, + NULL, 0, "Number of unlock requests in this request", HFILL }}, + + { &hf_smb_lock_long_length, + { "Length", "smb.lock.length", FT_UINT64, BASE_DEC, + NULL, 0, "Length of lock/unlock region", HFILL }}, + + { &hf_smb_lock_long_offset, + { "Offset", "smb.lock.offset", FT_UINT64, BASE_DEC, + NULL, 0, "Offset in the file of lock/unlock region", HFILL }}, + + { &hf_smb_file_type, + { "File Type", "smb.file_type", FT_UINT16, BASE_DEC, + VALS(filetype_vals), 0, "Type of file", HFILL }}, + + { &hf_smb_ipc_state, + { "IPC State", "smb.ipc_state", FT_UINT16, BASE_HEX, + NULL, 0x0, NULL, HFILL }}, + + { &hf_smb_ipc_state_nonblocking, + { "Nonblocking", "smb.ipc_state.nonblocking", FT_BOOLEAN, 16, + TFS(&tfs_ipc_state_nonblocking), 0x8000, "Is I/O to this pipe nonblocking?", HFILL }}, + + { &hf_smb_ipc_state_endpoint, + { "Endpoint", "smb.ipc_state.endpoint", FT_UINT16, BASE_DEC, + VALS(ipc_state_endpoint_vals), 0x4000, "Which end of the pipe this is", HFILL }}, + + { &hf_smb_ipc_state_pipe_type, + { "Pipe Type", "smb.ipc_state.pipe_type", FT_UINT16, BASE_DEC, + VALS(ipc_state_pipe_type_vals), 0x0c00, "What type of pipe this is", HFILL }}, + + { &hf_smb_ipc_state_read_mode, + { "Read Mode", "smb.ipc_state.read_mode", FT_UINT16, BASE_DEC, + VALS(ipc_state_read_mode_vals), 0x0300, "How this pipe should be read", HFILL }}, + + { &hf_smb_ipc_state_icount, + { "Icount", "smb.ipc_state.icount", FT_UINT16, BASE_DEC, + NULL, 0x00FF, "Count to control pipe instancing", HFILL }}, + + { &hf_smb_server_fid, + { "Server FID", "smb.server_fid", FT_UINT32, BASE_HEX, + NULL, 0, "Server unique File ID", HFILL }}, + + { &hf_smb_open_flags, + { "Flags", "smb.open.flags", FT_UINT16, BASE_HEX, + NULL, 0x0, NULL, HFILL }}, + + { &hf_smb_open_flags_add_info, + { "Additional Info", "smb.open.flags.add_info", FT_BOOLEAN, 16, + TFS(&tfs_open_flags_add_info), 0x0001, "Additional Information Requested?", HFILL }}, + + { &hf_smb_open_flags_ex_oplock, + { "Exclusive Oplock", "smb.open.flags.ex_oplock", FT_BOOLEAN, 16, + TFS(&tfs_open_flags_ex_oplock), 0x0002, "Exclusive Oplock Requested?", HFILL }}, + + { &hf_smb_open_flags_batch_oplock, + { "Batch Oplock", "smb.open.flags.batch_oplock", FT_BOOLEAN, 16, + TFS(&tfs_open_flags_batch_oplock), 0x0004, "Batch Oplock Requested?", HFILL }}, + + { &hf_smb_open_flags_ealen, + { "Total EA Len", "smb.open.flags.ealen", FT_BOOLEAN, 16, + TFS(&tfs_open_flags_ealen), 0x0008, "Total EA Len Requested?", HFILL }}, + + { &hf_smb_open_action, + { "Action", "smb.open.action", FT_UINT16, BASE_HEX, + NULL, 0x0, NULL, HFILL }}, + + { &hf_smb_open_action_open, + { "Open Action", "smb.open.action.open", FT_UINT16, BASE_DEC, + VALS(oa_open_vals), 0x0003, "Open Action, how the file was opened", HFILL }}, + + { &hf_smb_open_action_lock, + { "Exclusive Open", "smb.open.action.lock", FT_BOOLEAN, 16, + TFS(&tfs_oa_lock), 0x8000, "Is this file opened by another user?", HFILL }}, + + { &hf_smb_vc_num, + { "VC Number", "smb.vc", FT_UINT16, BASE_DEC, + NULL, 0, NULL, HFILL }}, + + { &hf_smb_password_len, + { "Password Length", "smb.pwlen", FT_UINT16, BASE_DEC, + NULL, 0, "Length of password", HFILL }}, + + { &hf_smb_ansi_password_len, + { "ANSI Password Length", "smb.ansi_pwlen", FT_UINT16, BASE_DEC, + NULL, 0, "Length of ANSI password", HFILL }}, + + { &hf_smb_unicode_password_len, + { "Unicode Password Length", "smb.unicode_pwlen", FT_UINT16, BASE_DEC, + NULL, 0, "Length of Unicode password", HFILL }}, + + { &hf_smb_account, + { "Account", "smb.account", FT_STRING, BASE_NONE, + NULL, 0, "Account, username", HFILL }}, + + { &hf_smb_os, + { "Native OS", "smb.native_os", FT_STRING, BASE_NONE, + NULL, 0, "Which OS we are running", HFILL }}, + + { &hf_smb_lanman, + { "Native LAN Manager", "smb.native_lanman", FT_STRING, BASE_NONE, + NULL, 0, "Which LANMAN protocol we are running", HFILL }}, + + { &hf_smb_setup_action, + { "Action", "smb.setup.action", FT_UINT16, BASE_HEX, + NULL, 0x0, NULL, HFILL }}, + + { &hf_smb_setup_action_guest, + { "Guest", "smb.setup.action.guest", FT_BOOLEAN, 16, + TFS(&tfs_setup_action_guest), 0x0001, "Client logged in as GUEST?", HFILL }}, + + { &hf_smb_fs, + { "Native File System", "smb.native_fs", FT_STRING, BASE_NONE, + NULL, 0, NULL, HFILL }}, + + { &hf_smb_connect_flags, + { "Flags", "smb.connect.flags", FT_UINT16, BASE_HEX, + NULL, 0x0, NULL, HFILL }}, + + { &hf_smb_connect_flags_dtid, + { "Disconnect TID", "smb.connect.flags.dtid", FT_BOOLEAN, 16, + TFS(&tfs_disconnect_tid), 0x0001, "Disconnect TID?", HFILL }}, + + { &hf_smb_connect_flags_ext_sig, + { "Extended Signature", "smb.connect.flags.extendedsig", FT_BOOLEAN, 16, + TFS(&tfs_extended_signature), 0x0004, "Extended signature?", HFILL }}, + + { &hf_smb_connect_flags_ext_resp, + { "Extended Response", "smb.connect.flags.extendedresp", FT_BOOLEAN, 16, + TFS(&tfs_extended_response), 0x0008, "Extended response?", HFILL }}, + + { &hf_smb_connect_support, + { "Optional Support", "smb.connect.support", FT_UINT16, BASE_HEX, + NULL, 0x0, NULL, HFILL }}, + + { &hf_smb_connect_support_search, + { "Search Bits", "smb.connect.support.search", FT_BOOLEAN, 16, + TFS(&tfs_connect_support_search), 0x0001, "Exclusive Search Bits supported?", HFILL }}, + + { &hf_smb_connect_support_in_dfs, + { "In Dfs", "smb.connect.support.dfs", FT_BOOLEAN, 16, + TFS(&tfs_connect_support_in_dfs), 0x0002, "Is this in a Dfs tree?", HFILL }}, + + { &hf_smb_connect_support_csc_mask_vals, + { "CSC Mask", "smb.connect.support.cscmask", FT_UINT16, BASE_DEC, + VALS(connect_support_csc_mask_vals), 0x000c, "CSC mask?", HFILL }}, + + { &hf_smb_connect_support_uniquefilename, + { "Unique File Name", "smb.connect.support.uniqfilename", FT_BOOLEAN, 16, + TFS(&tfs_connect_support_uniquefilename), 0x0010, "Unique file name supported?", HFILL }}, + + { &hf_smb_connect_support_extended_signature, + { "Extended Signatures", "smb.connect.support.extendedsig", FT_BOOLEAN, 16, + TFS(&tfs_connect_support_extended_signature), 0x0020, "Extended signatures?", HFILL }}, + + { &hf_smb_max_setup_count, + { "Max Setup Count", "smb.msc", FT_UINT8, BASE_DEC, + NULL, 0, "Maximum number of setup words to return", HFILL }}, + + { &hf_smb_total_param_count, + { "Total Parameter Count", "smb.tpc", FT_UINT32, BASE_DEC, + NULL, 0, "Total number of parameter bytes", HFILL }}, + + { &hf_smb_total_data_count, + { "Total Data Count", "smb.tdc", FT_UINT32, BASE_DEC, + NULL, 0, "Total number of data bytes", HFILL }}, + + { &hf_smb_max_param_count, + { "Max Parameter Count", "smb.mpc", FT_UINT32, BASE_DEC, + NULL, 0, "Maximum number of parameter bytes to return", HFILL }}, + + { &hf_smb_max_data_count, + { "Max Data Count", "smb.mdc", FT_UINT32, BASE_DEC, + NULL, 0, "Maximum number of data bytes to return", HFILL }}, + + { &hf_smb_param_disp16, + { "Parameter Displacement", "smb.pd", FT_UINT16, BASE_DEC, + NULL, 0, "Displacement of these parameter bytes", HFILL }}, + + { &hf_smb_param_count16, + { "Parameter Count", "smb.pc", FT_UINT16, BASE_DEC, + NULL, 0, "Number of parameter bytes in this buffer", HFILL }}, + + { &hf_smb_param_offset16, + { "Parameter Offset", "smb.po", FT_UINT16, BASE_DEC, + NULL, 0, "Offset (from header start) to parameters", HFILL }}, + + { &hf_smb_param_disp32, + { "Parameter Displacement", "smb.pd", FT_UINT32, BASE_DEC, + NULL, 0, "Displacement of these parameter bytes", HFILL }}, + + { &hf_smb_param_count32, + { "Parameter Count", "smb.pc", FT_UINT32, BASE_DEC, + NULL, 0, "Number of parameter bytes in this buffer", HFILL }}, + + { &hf_smb_param_offset32, + { "Parameter Offset", "smb.po", FT_UINT32, BASE_DEC, + NULL, 0, "Offset (from header start) to parameters", HFILL }}, + + { &hf_smb_data_count16, + { "Data Count", "smb.dc", FT_UINT16, BASE_DEC, + NULL, 0, "Number of data bytes in this buffer", HFILL }}, + + { &hf_smb_data_disp16, + { "Data Displacement", "smb.data_disp", FT_UINT16, BASE_DEC, + NULL, 0, NULL, HFILL }}, + + { &hf_smb_data_offset16, + { "Data Offset", "smb.data_offset", FT_UINT16, BASE_DEC, + NULL, 0, NULL, HFILL }}, + + { &hf_smb_data_count32, + { "Data Count", "smb.dc", FT_UINT32, BASE_DEC, + NULL, 0, "Number of data bytes in this buffer", HFILL }}, + + { &hf_smb_data_disp32, + { "Data Displacement", "smb.data_disp", FT_UINT32, BASE_DEC, + NULL, 0, NULL, HFILL }}, + + { &hf_smb_data_offset32, + { "Data Offset", "smb.data_offset", FT_UINT32, BASE_DEC, + NULL, 0, NULL, HFILL }}, + + { &hf_smb_setup_count, + { "Setup Count", "smb.sc", FT_UINT8, BASE_DEC, + NULL, 0, "Number of setup words in this buffer", HFILL }}, + + { &hf_smb_nt_ioctl_isfsctl, + { "IsFSctl", "smb.nt.ioctl.isfsctl", FT_UINT8, BASE_DEC, + VALS(nt_ioctl_isfsctl_vals), 0, "Is this a device IOCTL (FALSE) or FS Control (TRUE)", HFILL }}, + + { &hf_smb_nt_ioctl_flags_completion_filter, + { "Completion Filter", "smb.nt.ioctl.completion_filter", FT_UINT8, BASE_HEX, + NULL, 0x0, NULL, HFILL }}, + + { &hf_smb_nt_ioctl_flags_root_handle, + { "Root Handle", "smb.nt.ioctl.flags.root_handle", FT_BOOLEAN, 8, + TFS(&tfs_nt_ioctl_flags_root_handle), NT_IOCTL_FLAGS_ROOT_HANDLE, "Apply to this share or root Dfs share", HFILL }}, + + { &hf_smb_nt_notify_action, + { "Action", "smb.nt.notify.action", FT_UINT32, BASE_DEC, + VALS(nt_notify_action_vals), 0, "Which action caused this notify response", HFILL }}, + + { &hf_smb_nt_notify_watch_tree, + { "Watch Tree", "smb.nt.notify.watch_tree", FT_UINT8, BASE_DEC, + VALS(watch_tree_vals), 0, "Should Notify watch subdirectories also?", HFILL }}, + + + { &hf_smb_nt_notify_completion_filter, + { "Completion Filter", "smb.nt.notify.completion_filter", FT_UINT32, BASE_HEX, + NULL, 0x0, NULL, HFILL }}, + { &hf_smb_nt_notify_file_name, + { "File Name Change", "smb.nt.notify.file_name", FT_BOOLEAN, 32, + TFS(&tfs_nt_notify_file_name), NT_NOTIFY_FILE_NAME, "Notify on changes to file name", HFILL }}, + + { &hf_smb_nt_notify_dir_name, + { "Directory Name Change", "smb.nt.notify.dir_name", FT_BOOLEAN, 32, + TFS(&tfs_nt_notify_dir_name), NT_NOTIFY_DIR_NAME, "Notify on changes to directory name", HFILL }}, + + { &hf_smb_nt_notify_attributes, + { "Attribute Change", "smb.nt.notify.attributes", FT_BOOLEAN, 32, + TFS(&tfs_nt_notify_attributes), NT_NOTIFY_ATTRIBUTES, "Notify on changes to attributes", HFILL }}, + + { &hf_smb_nt_notify_size, + { "Size Change", "smb.nt.notify.size", FT_BOOLEAN, 32, + TFS(&tfs_nt_notify_size), NT_NOTIFY_SIZE, "Notify on changes to size", HFILL }}, + + { &hf_smb_nt_notify_last_write, + { "Last Write Change", "smb.nt.notify.last_write", FT_BOOLEAN, 32, + TFS(&tfs_nt_notify_last_write), NT_NOTIFY_LAST_WRITE, "Notify on changes to last write", HFILL }}, + + { &hf_smb_nt_notify_last_access, + { "Last Access Change", "smb.nt.notify.last_access", FT_BOOLEAN, 32, + TFS(&tfs_nt_notify_last_access), NT_NOTIFY_LAST_ACCESS, "Notify on changes to last access", HFILL }}, + + { &hf_smb_nt_notify_creation, + { "Created Change", "smb.nt.notify.creation", FT_BOOLEAN, 32, + TFS(&tfs_nt_notify_creation), NT_NOTIFY_CREATION, "Notify on changes to creation time", HFILL }}, + + { &hf_smb_nt_notify_ea, + { "EA Change", "smb.nt.notify.ea", FT_BOOLEAN, 32, + TFS(&tfs_nt_notify_ea), NT_NOTIFY_EA, "Notify on changes to Extended Attributes", HFILL }}, + + { &hf_smb_nt_notify_security, + { "Security Change", "smb.nt.notify.security", FT_BOOLEAN, 32, + TFS(&tfs_nt_notify_security), NT_NOTIFY_SECURITY, "Notify on changes to security settings", HFILL }}, + + { &hf_smb_nt_notify_stream_name, + { "Stream Name Change", "smb.nt.notify.stream_name", FT_BOOLEAN, 32, + TFS(&tfs_nt_notify_stream_name), NT_NOTIFY_STREAM_NAME, "Notify on changes to stream name?", HFILL }}, + + { &hf_smb_nt_notify_stream_size, + { "Stream Size Change", "smb.nt.notify.stream_size", FT_BOOLEAN, 32, + TFS(&tfs_nt_notify_stream_size), NT_NOTIFY_STREAM_SIZE, "Notify on changes of stream size", HFILL }}, + + { &hf_smb_nt_notify_stream_write, + { "Stream Write", "smb.nt.notify.stream_write", FT_BOOLEAN, 32, + TFS(&tfs_nt_notify_stream_write), NT_NOTIFY_STREAM_WRITE, "Notify on stream write?", HFILL }}, + + + { &hf_smb_root_dir_fid, + { "Root FID", "smb.rfid", FT_UINT32, BASE_HEX, + NULL, 0, "Open is relative to this FID (if nonzero)", HFILL }}, + + { &hf_smb_alloc_size64, + { "Allocation Size", "smb.alloc_size64", FT_UINT64, BASE_DEC, + NULL, 0, "Number of bytes to reserve on create or truncate", HFILL }}, + + { &hf_smb_nt_create_disposition, + { "Disposition", "smb.create.disposition", FT_UINT32, BASE_DEC, + VALS(create_disposition_vals), 0, "Create disposition, what to do if the file does/does not exist", HFILL }}, + + { &hf_smb_sd_length, + { "SD Length", "smb.sd.length", FT_UINT32, BASE_DEC, + NULL, 0, "Total length of security descriptor", HFILL }}, + + { &hf_smb_ea_list_length, + { "EA List Length", "smb.ea.list_length", FT_UINT32, BASE_DEC, + NULL, 0, "Total length of extended attributes", HFILL }}, + + { &hf_smb_ea_flags, + { "EA Flags", "smb.ea.flags", FT_UINT8, BASE_HEX, + NULL, 0, NULL, HFILL }}, + + { &hf_smb_ea_name_length, + { "EA Name Length", "smb.ea.name_length", FT_UINT8, BASE_DEC, + NULL, 0, NULL, HFILL }}, + + { &hf_smb_ea_data_length, + { "EA Data Length", "smb.ea.data_length", FT_UINT16, BASE_DEC, + NULL, 0, NULL, HFILL }}, + + { &hf_smb_ea_name, + { "EA Name", "smb.ea.name", FT_STRING, BASE_NONE, + NULL, 0, NULL, HFILL }}, + + { &hf_smb_ea_data, + { "EA Data", "smb.ea.data", FT_BYTES, BASE_NONE|BASE_SHOW_ASCII_PRINTABLE, + NULL, 0, NULL, HFILL }}, + + { &hf_smb_file_name_len, + { "File Name Len", "smb.file_name_len", FT_UINT32, BASE_DEC, + NULL, 0, "Length of File Name", HFILL }}, + + { &hf_smb_nt_impersonation_level, + { "Impersonation", "smb.impersonation.level", FT_UINT32, BASE_DEC, + VALS(impersonation_level_vals), 0, "Impersonation level", HFILL }}, + + { &hf_smb_nt_security_flags, + { "Security Flags", "smb.security.flags", FT_UINT8, BASE_HEX, + NULL, 0x0, NULL, HFILL }}, + + { &hf_smb_nt_security_flags_context_tracking, + { "Context Tracking", "smb.security.flags.context_tracking", FT_BOOLEAN, 8, + TFS(&tfs_nt_security_flags_context_tracking), 0x01, "Is security tracking static or dynamic?", HFILL }}, + + { &hf_smb_nt_security_flags_effective_only, + { "Effective Only", "smb.security.flags.effective_only", FT_BOOLEAN, 8, + TFS(&tfs_nt_security_flags_effective_only), 0x02, "Are only enabled or all aspects uf the users SID available?", HFILL }}, + + { &hf_smb_nt_access_mask_generic_read, + { "Generic Read", "smb.access.generic_read", FT_BOOLEAN, 32, + TFS(&tfs_nt_access_mask_generic_read), 0x80000000, "Is generic read allowed for this object?", HFILL }}, + + { &hf_smb_nt_access_mask_generic_write, + { "Generic Write", "smb.access.generic_write", FT_BOOLEAN, 32, + TFS(&tfs_nt_access_mask_generic_write), 0x40000000, "Is generic write allowed for this object?", HFILL }}, + + { &hf_smb_nt_access_mask_generic_execute, + { "Generic Execute", "smb.access.generic_execute", FT_BOOLEAN, 32, + TFS(&tfs_nt_access_mask_generic_execute), 0x20000000, "Is generic execute allowed for this object?", HFILL }}, + + { &hf_smb_nt_access_mask_generic_all, + { "Generic All", "smb.access.generic_all", FT_BOOLEAN, 32, + TFS(&tfs_nt_access_mask_generic_all), 0x10000000, "Is generic all allowed for this attribute", HFILL }}, + + { &hf_smb_nt_access_mask_maximum_allowed, + { "Maximum Allowed", "smb.access.maximum_allowed", FT_BOOLEAN, 32, + TFS(&tfs_nt_access_mask_maximum_allowed), 0x02000000, "?", HFILL }}, + + { &hf_smb_nt_access_mask_system_security, + { "System Security", "smb.access.system_security", FT_BOOLEAN, 32, + TFS(&tfs_nt_access_mask_system_security), 0x01000000, "Access to a system ACL?", HFILL }}, + + { &hf_smb_nt_access_mask_synchronize, + { "Synchronize", "smb.access.synchronize", FT_BOOLEAN, 32, + TFS(&tfs_nt_access_mask_synchronize), 0x00100000, "Windows NT: synchronize access", HFILL }}, + + { &hf_smb_nt_access_mask_write_owner, + { "Write Owner", "smb.access.write_owner", FT_BOOLEAN, 32, + TFS(&tfs_nt_access_mask_write_owner), 0x00080000, "Can owner write to the object?", HFILL }}, + + { &hf_smb_nt_access_mask_write_dac, + { "Write DAC", "smb.access.write_dac", FT_BOOLEAN, 32, + TFS(&tfs_nt_access_mask_write_dac), 0x00040000, "Is write allowed to the owner group or ACLs?", HFILL }}, + + { &hf_smb_nt_access_mask_read_control, + { "Read Control", "smb.access.read_control", FT_BOOLEAN, 32, + TFS(&tfs_nt_access_mask_read_control), 0x00020000, "Are reads allowed of owner, group and ACL data of the SID?", HFILL }}, + + { &hf_smb_nt_access_mask_delete, + { "Delete", "smb.access.delete", FT_BOOLEAN, 32, + TFS(&tfs_nt_access_mask_delete), 0x00010000, "Can object be deleted", HFILL }}, + + { &hf_smb_nt_access_mask_write_attributes, + { "Write Attributes", "smb.access.write_attributes", FT_BOOLEAN, 32, + TFS(&tfs_nt_access_mask_write_attributes), 0x00000100, "Can object's attributes be written", HFILL }}, + + { &hf_smb_nt_access_mask_read_attributes, + { "Read Attributes", "smb.access.read_attributes", FT_BOOLEAN, 32, + TFS(&tfs_nt_access_mask_read_attributes), 0x00000080, "Can object's attributes be read", HFILL }}, + + { &hf_smb_nt_access_mask_delete_child, + { "Delete Child", "smb.access.delete_child", FT_BOOLEAN, 32, + TFS(&tfs_nt_access_mask_delete_child), 0x00000040, "Can object's subdirectories be deleted", HFILL }}, + + /* + * "Execute" for files, "traverse" for directories. + */ + { &hf_smb_nt_access_mask_execute, + { "Execute", "smb.access.execute", FT_BOOLEAN, 32, + TFS(&tfs_nt_access_mask_execute), 0x00000020, "Can object be executed (if file) or traversed (if directory)", HFILL }}, + + { &hf_smb_nt_access_mask_write_ea, + { "Write EA", "smb.access.write_ea", FT_BOOLEAN, 32, + TFS(&tfs_nt_access_mask_write_ea), 0x00000010, "Can object's extended attributes be written", HFILL }}, + + { &hf_smb_nt_access_mask_read_ea, + { "Read EA", "smb.access.read_ea", FT_BOOLEAN, 32, + TFS(&tfs_nt_access_mask_read_ea), 0x00000008, "Can object's extended attributes be read", HFILL }}, + + /* + * "Append data" for files, "add subdirectory" for directories, + * "create pipe instance" for named pipes. + */ + { &hf_smb_nt_access_mask_append, + { "Append", "smb.access.append", FT_BOOLEAN, 32, + TFS(&tfs_nt_access_mask_append), 0x00000004, "Can object's contents be appended to", HFILL }}, + + /* + * "Write data" for files and pipes, "add file" for directory. + */ + { &hf_smb_nt_access_mask_write, + { "Write", "smb.access.write", FT_BOOLEAN, 32, + TFS(&tfs_nt_access_mask_write), 0x00000002, "Can object's contents be written", HFILL }}, + + /* + * "Read data" for files and pipes, "list directory" for directory. + */ + { &hf_smb_nt_access_mask_read, + { "Read", "smb.access.read", FT_BOOLEAN, 32, + TFS(&tfs_nt_access_mask_read), 0x00000001, "Can object's contents be read", HFILL }}, + + { &hf_smb_nt_create_bits_oplock, + { "Exclusive Oplock", "smb.nt.create.oplock", FT_BOOLEAN, 32, + TFS(&tfs_nt_create_bits_oplock), 0x00000002, "Is an oplock requested", HFILL }}, + + { &hf_smb_nt_create_bits_boplock, + { "Batch Oplock", "smb.nt.create.batch_oplock", FT_BOOLEAN, 32, + TFS(&tfs_nt_create_bits_boplock), 0x00000004, "Is a batch oplock requested?", HFILL }}, + + { &hf_smb_nt_create_bits_dir, + { "Create Directory", "smb.nt.create.dir", FT_BOOLEAN, 32, + TFS(&tfs_nt_create_bits_dir), 0x00000008, "Must target of open be a directory?", HFILL }}, + + { &hf_smb_nt_create_bits_ext_resp, + { "Extended Response", "smb.nt.create.ext", FT_BOOLEAN, 32, + TFS(&tfs_nt_create_bits_ext_resp), 0x00000010, "Extended response required?", HFILL }}, + + { &hf_smb_nt_create_options_directory_file, + { "Directory", "smb.nt.create_options.directory", FT_BOOLEAN, 32, + TFS(&tfs_nt_create_options_directory), 0x00000001, "Should file being opened/created be a directory?", HFILL }}, + + { &hf_smb_nt_create_options_write_through, + { "Write Through", "smb.nt.create_options.write_through", FT_BOOLEAN, 32, + TFS(&tfs_nt_create_options_write_through), 0x00000002, "Should writes to the file write buffered data out before completing?", HFILL }}, + + { &hf_smb_nt_create_options_sequential_only, + { "Sequential Only", "smb.nt.create_options.sequential_only", FT_BOOLEAN, 32, + TFS(&tfs_nt_create_options_sequential_only), 0x00000004, "Will access to this file only be sequential?", HFILL }}, + + { &hf_smb_nt_create_options_no_intermediate_buffering, + { "Intermediate Buffering", "smb.nt.create_options.intermediate_buffering", FT_BOOLEAN, 32, + TFS(&tfs_nt_create_options_no_intermediate_buffering), 0x00000008, "Is intermediate buffering allowed?", HFILL }}, + + { &hf_smb_nt_create_options_sync_io_alert, + { "Sync I/O Alert", "smb.nt.create_options.sync_io_alert", FT_BOOLEAN, 32, + TFS(&tfs_nt_create_options_sync_io_alert), 0x00000010, "All operations are performed synchronous", HFILL}}, + + { &hf_smb_nt_create_options_sync_io_nonalert, + { "Sync I/O Nonalert", "smb.nt.create_options.sync_io_nonalert", FT_BOOLEAN, 32, + TFS(&tfs_nt_create_options_sync_io_nonalert), 0x00000020, "All operations are synchronous and may block", HFILL}}, + + { &hf_smb_nt_create_options_non_directory_file, + { "Non-Directory", "smb.nt.create_options.non_directory", FT_BOOLEAN, 32, + TFS(&tfs_nt_create_options_non_directory), 0x00000040, "Should file being opened/created be a non-directory?", HFILL }}, + + { &hf_smb_nt_create_options_create_tree_connection, + { "Create Tree Connection", "smb.nt.create_options.create_tree_connection", FT_BOOLEAN, 32, + TFS(&tfs_nt_create_options_create_tree_connection), 0x00000080, "Create Tree Connection flag", HFILL }}, + + { &hf_smb_nt_create_options_complete_if_oplocked, + { "Complete If Oplocked", "smb.nt.create_options.complete_if_oplocked", FT_BOOLEAN, 32, + TFS(&tfs_nt_create_options_complete_if_oplocked), 0x00000100, "Complete if oplocked flag", HFILL }}, + + { &hf_smb_nt_create_options_no_ea_knowledge, + { "No EA Knowledge", "smb.nt.create_options.no_ea_knowledge", FT_BOOLEAN, 32, + TFS(&tfs_nt_create_options_no_ea_knowledge), 0x00000200, "Does the client not understand extended attributes?", HFILL }}, + + { &hf_smb_nt_create_options_eight_dot_three_only, + { "8.3 Only", "smb.nt.create_options.eight_dot_three_only", FT_BOOLEAN, 32, + TFS(&tfs_nt_create_options_eight_dot_three_only), 0x00000400, "Does the client understand only 8.3 filenames?", HFILL }}, + + { &hf_smb_nt_create_options_random_access, + { "Random Access", "smb.nt.create_options.random_access", FT_BOOLEAN, 32, + TFS(&tfs_nt_create_options_random_access), 0x00000800, "Will the client be accessing the file randomly?", HFILL }}, + + { &hf_smb_nt_create_options_delete_on_close, + { "Delete On Close", "smb.nt.create_options.delete_on_close", FT_BOOLEAN, 32, + TFS(&tfs_nt_create_options_delete_on_close), 0x00001000, "Should the file be deleted when closed?", HFILL }}, + { &hf_smb_nt_create_options_open_by_fileid, + { "Open By FileID", "smb.nt.create_options.open_by_fileid", FT_BOOLEAN, 32, + TFS(&tfs_nt_create_options_open_by_fileid), 0x00002000, "Open file by inode", HFILL }}, + + { &hf_smb_nt_create_options_backup_intent, + { "Backup Intent", "smb.nt.create_options.backup_intent", FT_BOOLEAN, 32, + TFS(&tfs_nt_create_options_backup_intent), 0x00004000, "Is this opened by BACKUP ADMIN for backup intent?", HFILL }}, + + { &hf_smb_nt_create_options_no_compression, + { "No Compression", "smb.nt.create_options.no_compression", FT_BOOLEAN, 32, + TFS(&tfs_nt_create_options_no_compression), 0x00008000, "Is compression allowed?", HFILL }}, + + { &hf_smb_nt_create_options_reserve_opfilter, + { "Reserve Opfilter", "smb.nt.create_options.reserve_opfilter", FT_BOOLEAN, 32, + TFS(&tfs_nt_create_options_reserve_opfilter), 0x00100000, "Reserve Opfilter flag", HFILL }}, + + { &hf_smb_nt_create_options_open_reparse_point, + { "Open Reparse Point", "smb.nt.create_options.open_reparse_point", FT_BOOLEAN, 32, + TFS(&tfs_nt_create_options_open_reparse_point), 0x00200000, "Is this an open of a reparse point or of the normal file?", HFILL }}, + + { &hf_smb_nt_create_options_open_no_recall, + { "Open No Recall", "smb.nt.create_options.open_no_recall", FT_BOOLEAN, 32, + TFS(&tfs_nt_create_options_open_no_recall), 0x00400000, "Open no recall flag", HFILL }}, + + { &hf_smb_nt_create_options_open_for_free_space_query, + { "Open For Free Space query", "smb.nt.create_options.open_for_free_space_query", FT_BOOLEAN, 32, + TFS(&tfs_nt_create_options_open_for_free_space_query), 0x00800000, "Open For Free Space Query flag", HFILL }}, + + { &hf_smb_nt_share_access_read, + { "Read", "smb.share.access.read", FT_BOOLEAN, 32, + TFS(&tfs_nt_share_access_read), SHARE_ACCESS_READ, "Can the object be shared for reading?", HFILL }}, + + { &hf_smb_nt_share_access_write, + { "Write", "smb.share.access.write", FT_BOOLEAN, 32, + TFS(&tfs_nt_share_access_write), SHARE_ACCESS_WRITE, "Can the object be shared for write?", HFILL }}, + + { &hf_smb_nt_share_access_delete, + { "Delete", "smb.share.access.delete", FT_BOOLEAN, 32, + TFS(&tfs_nt_share_access_delete), SHARE_ACCESS_DELETE, NULL, HFILL }}, + + { &hf_smb_file_eattr, + { "File Attributes", "smb.file_attribute", FT_UINT32, BASE_HEX, + NULL, 0x0, NULL, HFILL }}, + + { &hf_smb_file_eattr_read_only, + { "Read Only", "smb.file_attribute.read_only", FT_BOOLEAN, 32, + TFS(&tfs_file_attribute_read_only), SMB_FILE_ATTRIBUTE_READ_ONLY, "READ ONLY file attribute", HFILL }}, + + { &hf_smb_file_eattr_hidden, + { "Hidden", "smb.file_attribute.hidden", FT_BOOLEAN, 32, + TFS(&tfs_file_attribute_hidden), SMB_FILE_ATTRIBUTE_HIDDEN, "HIDDEN file attribute", HFILL }}, + + { &hf_smb_file_eattr_system, + { "System", "smb.file_attribute.system", FT_BOOLEAN, 32, + TFS(&tfs_file_attribute_system), SMB_FILE_ATTRIBUTE_SYSTEM, "SYSTEM file attribute", HFILL }}, + + { &hf_smb_file_eattr_volume, + { "Volume ID", "smb.file_attribute.volume", FT_BOOLEAN, 32, + TFS(&tfs_file_attribute_volume), SMB_FILE_ATTRIBUTE_VOLUME, "VOLUME file attribute", HFILL }}, + + { &hf_smb_file_eattr_directory, + { "Directory", "smb.file_attribute.directory", FT_BOOLEAN, 32, + TFS(&tfs_file_attribute_directory), SMB_FILE_ATTRIBUTE_DIRECTORY, "DIRECTORY file attribute", HFILL }}, + + { &hf_smb_file_eattr_archive, + { "Archive", "smb.file_attribute.archive", FT_BOOLEAN, 32, + TFS(&tfs_file_attribute_archive), SMB_FILE_ATTRIBUTE_ARCHIVE, "ARCHIVE file attribute", HFILL }}, + + { &hf_smb_file_eattr_device, + { "Device", "smb.file_attribute.device", FT_BOOLEAN, 32, + TFS(&tfs_file_attribute_device), SMB_FILE_ATTRIBUTE_DEVICE, "Is this file a device?", HFILL }}, + + { &hf_smb_file_eattr_normal, + { "Normal", "smb.file_attribute.normal", FT_BOOLEAN, 32, + TFS(&tfs_file_attribute_normal), SMB_FILE_ATTRIBUTE_NORMAL, "Is this a normal file?", HFILL }}, + + { &hf_smb_file_eattr_temporary, + { "Temporary", "smb.file_attribute.temporary", FT_BOOLEAN, 32, + TFS(&tfs_file_attribute_temporary), SMB_FILE_ATTRIBUTE_TEMPORARY, "Is this a temporary file?", HFILL }}, + + { &hf_smb_file_eattr_sparse, + { "Sparse", "smb.file_attribute.sparse", FT_BOOLEAN, 32, + TFS(&tfs_file_attribute_sparse), SMB_FILE_ATTRIBUTE_SPARSE, "Is this a sparse file?", HFILL }}, + + { &hf_smb_file_eattr_reparse, + { "Reparse Point", "smb.file_attribute.reparse", FT_BOOLEAN, 32, + TFS(&tfs_file_attribute_reparse), SMB_FILE_ATTRIBUTE_REPARSE, "Does this file have an associated reparse point?", HFILL }}, + + { &hf_smb_file_eattr_compressed, + { "Compressed", "smb.file_attribute.compressed", FT_BOOLEAN, 32, + TFS(&tfs_file_attribute_compressed), SMB_FILE_ATTRIBUTE_COMPRESSED, "Is this file compressed?", HFILL }}, + + { &hf_smb_file_eattr_offline, + { "Offline", "smb.file_attribute.offline", FT_BOOLEAN, 32, + TFS(&tfs_file_attribute_offline), SMB_FILE_ATTRIBUTE_OFFLINE, "Is this file offline?", HFILL }}, + + { &hf_smb_file_eattr_not_content_indexed, + { "Content Indexed", "smb.file_attribute.not_content_indexed", FT_BOOLEAN, 32, + TFS(&tfs_file_attribute_not_content_indexed), SMB_FILE_ATTRIBUTE_NOT_CONTENT_INDEXED, "May this file be indexed by the content indexing service", HFILL }}, + + { &hf_smb_file_eattr_encrypted, + { "Encrypted", "smb.file_attribute.encrypted", FT_BOOLEAN, 32, + TFS(&tfs_file_attribute_encrypted), SMB_FILE_ATTRIBUTE_ENCRYPTED, "Is this file encrypted?", HFILL }}, + + { &hf_smb_size_returned_quota_data, + { "Size of returned Quota data", "smb.size_returned_quota_data", FT_UINT32, BASE_DEC, + NULL, 0x0, NULL, HFILL }}, + + { &hf_smb_sec_desc_len, + { "NT Security Descriptor Length", "smb.sec_desc_len", FT_UINT32, BASE_DEC, + NULL, 0, "Security Descriptor Length", HFILL }}, + + { &hf_smb_nt_qsd, + { "Security Information", "smb.nt_qsd", FT_UINT32, BASE_HEX, + NULL, 0x0, NULL, HFILL }}, + + { &hf_smb_nt_qsd_owner, + { "Owner", "smb.nt_qsd.owner", FT_BOOLEAN, 32, + TFS(&tfs_nt_qsd_owner), NT_QSD_OWNER, "Is owner security information being queried?", HFILL }}, + + { &hf_smb_nt_qsd_group, + { "Group", "smb.nt_qsd.group", FT_BOOLEAN, 32, + TFS(&tfs_nt_qsd_group), NT_QSD_GROUP, "Is group security information being queried?", HFILL }}, + + { &hf_smb_nt_qsd_dacl, + { "DACL", "smb.nt_qsd.dacl", FT_BOOLEAN, 32, + TFS(&tfs_nt_qsd_dacl), NT_QSD_DACL, "Is DACL security information being queried?", HFILL }}, + + { &hf_smb_nt_qsd_sacl, + { "SACL", "smb.nt_qsd.sacl", FT_BOOLEAN, 32, + TFS(&tfs_nt_qsd_sacl), NT_QSD_SACL, "Is SACL security information being queried?", HFILL }}, + + { &hf_smb_extended_attributes, + { "Extended Attributes", "smb.ext_attr", FT_BYTES, BASE_NONE, + NULL, 0, NULL, HFILL }}, + + { &hf_smb_oplock_level, + { "Oplock level", "smb.oplock.level", FT_UINT8, BASE_DEC, + VALS(oplock_level_vals), 0, "Level of oplock granted", HFILL }}, + + { &hf_smb_response_type, + { "Response type", "smb.response_type", FT_UINT8, BASE_HEX, + VALS(response_type_vals), 0, "NT Transaction Create response type", HFILL }}, + + { &hf_smb_create_action, + { "Create action", "smb.create.action", FT_UINT32, BASE_DEC, + VALS(oa_open_vals), 0, "Type of action taken", HFILL }}, + + { &hf_smb_file_id, + { "Server unique file ID", "smb.create.file_id", FT_UINT32, BASE_HEX, + NULL, 0, NULL, HFILL }}, + + { &hf_smb_file_id_64bit, + { "Server unique 64-bit file ID", "smb.create.file_id_64b", FT_UINT64, BASE_HEX, + NULL, 0, NULL, HFILL }}, + + { &hf_smb_ea_error_offset, + { "EA Error offset", "smb.ea.error_offset", FT_UINT32, BASE_DEC, + NULL, 0, "Offset into EA list if EA error", HFILL }}, + + { &hf_smb_end_of_file, + { "End Of File", "smb.end_of_file", FT_UINT64, BASE_DEC, + NULL, 0, "Offset to the first free byte in the file", HFILL }}, + + { &hf_smb_replace, + { "Replace", "smb.replace", FT_BOOLEAN, BASE_NONE, + TFS(&tfs_smb_replace), 0x0, "Remove target if it exists?", HFILL }}, + + { &hf_smb_root_dir_handle, + { "Root Directory Handle", "smb.root_dir_handle", FT_UINT32, BASE_HEX, + NULL, 0, NULL, HFILL }}, + + { &hf_smb_target_name_len, + { "Target name length", "smb.target_name_len", FT_UINT32, BASE_DEC, + NULL, 0, "Length of target file name", HFILL }}, + + { &hf_smb_target_name, + { "Target name", "smb.target_name", FT_STRING, BASE_NONE, + NULL, 0, "Target file name", HFILL }}, + + { &hf_smb_device_type, + { "Device Type", "smb.device.type", FT_UINT32, BASE_HEX | BASE_EXT_STRING, + &device_type_vals_ext, 0, "Type of device", HFILL }}, + + { &hf_smb_is_directory, + { "Is Directory", "smb.is_directory", FT_UINT8, BASE_DEC, + VALS(is_directory_vals), 0, "Is this object a directory?", HFILL }}, + + { &hf_smb_next_entry_offset, + { "Next Entry Offset", "smb.next_entry_offset", FT_UINT32, BASE_DEC, + NULL, 0, "Offset to next entry", HFILL }}, + + { &hf_smb_change_time, + { "Change", "smb.change.time", FT_ABSOLUTE_TIME, ABSOLUTE_TIME_LOCAL, + NULL, 0, "Last Change Time", HFILL }}, + + { &hf_smb_setup_len, + { "Setup Len", "smb.print.setup.len", FT_UINT16, BASE_DEC, + NULL, 0, "Length of printer setup data", HFILL }}, + + { &hf_smb_print_mode, + { "Mode", "smb.print.mode", FT_UINT16, BASE_DEC, + VALS(print_mode_vals), 0, "Text or Graphics mode", HFILL }}, + + { &hf_smb_print_identifier, + { "Identifier", "smb.print.identifier", FT_STRING, BASE_NONE, + NULL, 0, "Identifier string for this print job", HFILL }}, + + { &hf_smb_restart_index, + { "Restart Index", "smb.print.restart_index", FT_UINT16, BASE_DEC, + NULL, 0, "Index of entry after last returned", HFILL }}, + + { &hf_smb_print_queue_date, + { "Queued", "smb.print.queued.date", FT_ABSOLUTE_TIME, ABSOLUTE_TIME_LOCAL, + NULL, 0, "Date when this entry was queued", HFILL }}, + + { &hf_smb_print_queue_dos_date, + { "Queued Date", "smb.print.queued.smb.date", FT_UINT16, BASE_HEX, + NULL, 0, "Date when this print job was queued, SMB_DATE format", HFILL }}, + + { &hf_smb_print_queue_dos_time, + { "Queued Time", "smb.print.queued.smb.time", FT_UINT16, BASE_HEX, + NULL, 0, "Time when this print job was queued, SMB_TIME format", HFILL }}, + + { &hf_smb_print_status, + { "Status", "smb.print.status", FT_UINT8, BASE_HEX, + VALS(print_status_vals), 0, "Status of this entry", HFILL }}, + + { &hf_smb_print_spool_file_number, + { "Spool File Number", "smb.print.spool.file_number", FT_UINT16, BASE_DEC, + NULL, 0, "Spool File Number, assigned by the spooler", HFILL }}, + + { &hf_smb_print_spool_file_size, + { "Spool File Size", "smb.print.spool.file_size", FT_UINT32, BASE_DEC, + NULL, 0, "Number of bytes in spool file", HFILL }}, + + { &hf_smb_print_spool_file_name, + { "Name", "smb.print.spool.name", FT_STRINGZ, BASE_NONE, + NULL, 0, "Name of client that submitted this job", HFILL }}, + + { &hf_smb_start_index, + { "Start Index", "smb.print.start_index", FT_UINT16, BASE_DEC, + NULL, 0, "First queue entry to return", HFILL }}, + + { &hf_smb_originator_name, + { "Originator Name", "smb.originator_name", FT_STRINGZ, BASE_NONE, + NULL, 0, "Name of sender of message", HFILL }}, + + { &hf_smb_destination_name, + { "Destination Name", "smb.destination_name", FT_STRINGZ, BASE_NONE, + NULL, 0, "Name of recipient of message", HFILL }}, + + { &hf_smb_message_len, + { "Message Len", "smb.message.len", FT_UINT16, BASE_DEC, + NULL, 0, "Length of message", HFILL }}, + + { &hf_smb_message, + { "Message", "smb.message", FT_STRING, BASE_NONE, + NULL, 0, "Message text", HFILL }}, + + { &hf_smb_mgid, + { "Message Group ID", "smb.mgid", FT_UINT16, BASE_DEC, + NULL, 0, "Message group ID for multi-block messages", HFILL }}, + + { &hf_smb_forwarded_name, + { "Forwarded Name", "smb.forwarded_name", FT_STRINGZ, BASE_NONE, + NULL, 0, "Recipient name being forwarded", HFILL }}, + + { &hf_smb_machine_name, + { "Machine Name", "smb.machine_name", FT_STRINGZ, BASE_NONE, + NULL, 0, "Name of target machine", HFILL }}, + + { &hf_smb_cancel_to, + { "Cancel to", "smb.cancel_to", FT_FRAMENUM, BASE_NONE, + NULL, 0, "This packet is a cancellation of the packet in this frame", HFILL }}, + + { &hf_smb_trans_name, + { "Transaction Name", "smb.trans_name", FT_STRING, BASE_NONE, + NULL, 0, "Name of transaction", HFILL }}, + + { &hf_smb_transaction_flags, + { "Flags", "smb.transaction.flags", FT_UINT16, BASE_HEX, + NULL, 0x0, NULL, HFILL }}, + + { &hf_smb_transaction_flags_dtid, + { "Disconnect TID", "smb.transaction.flags.dtid", FT_BOOLEAN, 16, + TFS(&tfs_tf_dtid), 0x0001, "Disconnect TID?", HFILL }}, + + { &hf_smb_transaction_flags_owt, + { "One Way Transaction", "smb.transaction.flags.owt", FT_BOOLEAN, 16, + TFS(&tfs_tf_owt), 0x0002, "One Way Transaction (no response)?", HFILL }}, + + { &hf_smb_search_count, + { "Search Count", "smb.search_count", FT_UINT16, BASE_DEC, + NULL, 0, "Maximum number of search entries to return", HFILL }}, + + { &hf_smb_search_pattern, + { "Search Pattern", "smb.search_pattern", FT_STRING, BASE_NONE, + NULL, 0, NULL, HFILL }}, + + { &hf_smb_ff2, + { "Flags", "smb.find_first2.flags", FT_UINT16, BASE_HEX, + NULL, 0x0, NULL, HFILL }}, + + { &hf_smb_ff2_backup, + { "Backup Intent", "smb.find_first2.flags.backup", FT_BOOLEAN, 16, + TFS(&tfs_ff2_backup), 0x0010, "Find with backup intent", HFILL }}, + + { &hf_smb_ff2_continue, + { "Continue", "smb.find_first2.flags.continue", FT_BOOLEAN, 16, + TFS(&tfs_ff2_continue), 0x0008, "Continue search from previous ending place", HFILL }}, + + { &hf_smb_ff2_resume, + { "Resume", "smb.find_first2.flags.resume", FT_BOOLEAN, 16, + TFS(&tfs_ff2_resume), FF2_RESUME, "Return resume keys for each entry found", HFILL }}, + + { &hf_smb_ff2_close_eos, + { "Close on EOS", "smb.find_first2.flags.eos", FT_BOOLEAN, 16, + TFS(&tfs_ff2_close_eos), 0x0002, "Close search if end of search reached", HFILL }}, + + { &hf_smb_ff2_close, + { "Close", "smb.find_first2.flags.close", FT_BOOLEAN, 16, + TFS(&tfs_ff2_close), 0x0001, "Close search after this request", HFILL }}, + + { &hf_smb_ff2_information_level, + { "Level of Interest", "smb.ff2_loi", FT_UINT16, BASE_DEC, + VALS(ff2_il_vals), 0, "Level of interest for FIND_FIRST2 command", HFILL }}, + + { &hf_smb_qpi_loi, + { "Level of Interest", "smb.qpi_loi", FT_UINT16, BASE_DEC, + VALS(qpi_loi_vals), 0, "Level of interest for TRANSACTION[2] QUERY_{FILE,PATH}_INFO commands", HFILL }}, + + { &hf_smb_spi_loi, + { "Level of Interest", "smb.spi_loi", FT_UINT16, BASE_DEC | BASE_EXT_STRING, + &spi_loi_vals_ext, 0, "Level of interest for TRANSACTION[2] SET_{FILE,PATH}_INFO commands", HFILL }}, + +#if 0 + { &hf_smb_sfi, + { "IO Flag", "smb.sfi_flags", FT_UINT16, BASE_HEX, + NULL, 0x0, NULL, HFILL }}, + + { &hf_smb_sfi_writetru, + { "Writethrough", "smb.sfi_writethrough", FT_BOOLEAN, 16, + TFS(&tfs_da_writetru), 0x0010, "Writethrough mode?", HFILL }}, + + { &hf_smb_sfi_caching, + { "Caching", "smb.sfi_caching", FT_BOOLEAN, 16, + TFS(&tfs_da_caching), 0x0020, "Caching mode?", HFILL }}, +#endif + + { &hf_smb_storage_type, + { "Storage Type", "smb.storage_type", FT_UINT32, BASE_DEC, + NULL, 0, "Type of storage", HFILL }}, + + { &hf_smb_resume, + { "Resume Key", "smb.resume", FT_UINT32, BASE_DEC, + NULL, 0, NULL, HFILL }}, + + { &hf_smb_max_referral_level, + { "Max Referral Level", "smb.max_referral_level", FT_UINT16, BASE_DEC, + NULL, 0, "Latest referral version number understood", HFILL }}, + + { &hf_smb_qfsi_information_level, + { "Level of Interest", "smb.qfsi_loi", FT_UINT16, BASE_HEX | BASE_EXT_STRING, + &qfsi_vals_ext, 0, "Level of interest for QUERY_FS_INFORMATION2 command", HFILL }}, + + { &hf_smb_sfsi_information_level, + { "Level of Interest", "smb.sfsi_loi", FT_UINT16, BASE_HEX, + VALS(sfsi_vals), 0, "Level of interest for SET_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_number_of_links, + { "Link Count", "smb.link_count", FT_UINT32, BASE_DEC, + NULL, 0, "Number of hard links to the file", HFILL }}, + + { &hf_smb_delete_pending, + { "Delete Pending", "smb.delete_pending", FT_UINT16, BASE_DEC, + VALS(delete_pending_vals), 0, "Is this object about to be deleted?", HFILL }}, + + { &hf_smb_index_number, + { "Index Number", "smb.index_number", FT_UINT64, BASE_HEX, + NULL, 0, "File system unique identifier", HFILL }}, + + { &hf_smb_position, + { "Position", "smb.position", FT_UINT64, BASE_DEC, + NULL, 0, "File position", HFILL }}, + +#if 0 + { &hf_smb_current_offset, + { "Current Offset", "smb.offset", FT_UINT64, BASE_DEC, + NULL, 0, "Current offset in the file", HFILL }}, +#endif + + { &hf_smb_t2_alignment, + { "Alignment", "smb.alignment", FT_UINT32, BASE_DEC, + VALS(alignment_vals), 0, "What alignment do we require for buffers", HFILL }}, + + { &hf_smb_t2_stream_name_length, + { "Stream Name Length", "smb.stream_name_len", FT_UINT32, BASE_DEC, + NULL, 0, "Length of stream name", HFILL }}, + + { &hf_smb_t2_stream_size, + { "Stream Size", "smb.stream_size", FT_UINT64, BASE_DEC, + NULL, 0, "Size of the stream in number of bytes", HFILL }}, + + { &hf_smb_t2_stream_name, + { "Stream Name", "smb.stream_name", FT_STRING, BASE_NONE, + NULL, 0, "Name of the stream", HFILL }}, + + { &hf_smb_t2_compressed_file_size, + { "Compressed Size", "smb.compressed.file_size", FT_UINT64, BASE_DEC, + NULL, 0, "Size of the compressed file", HFILL }}, + + { &hf_smb_t2_compressed_format, + { "Compression Format", "smb.compressed.format", FT_UINT16, BASE_DEC, + NULL, 0, "Compression algorithm used", HFILL }}, + + { &hf_smb_t2_compressed_unit_shift, + { "Unit Shift", "smb.compressed.unit_shift", FT_UINT8, BASE_DEC, + NULL, 0, "Size of the stream in number of bytes", HFILL }}, + + { &hf_smb_t2_compressed_chunk_shift, + { "Chunk Shift", "smb.compressed.chunk_shift", FT_UINT8, BASE_DEC, + NULL, 0, "Allocated size of the stream in number of bytes", HFILL }}, + + { &hf_smb_t2_compressed_cluster_shift, + { "Cluster Shift", "smb.compressed.cluster_shift", FT_UINT8, BASE_DEC, + NULL, 0, "Allocated size of the stream in number of bytes", HFILL }}, + + { &hf_smb_t2_marked_for_deletion, + { "Marked for Deletion", "smb.marked_for_deletion", FT_BOOLEAN, BASE_NONE, + TFS(&tfs_marked_for_deletion), 0x0, "Marked for deletion?", HFILL }}, + + { &hf_smb_dfs_path_consumed, + { "Path Consumed", "smb.dfs.path_consumed", FT_UINT16, BASE_DEC, + NULL, 0, "Number of RequestFilename bytes client", HFILL }}, + + { &hf_smb_dfs_num_referrals, + { "Num Referrals", "smb.dfs.num_referrals", FT_UINT16, BASE_DEC, + NULL, 0, "Number of referrals in this pdu", HFILL }}, + + { &hf_smb_get_dfs_flags, + { "Flags", "smb.dfs.flags", FT_UINT16, BASE_HEX, + NULL, 0x0, NULL, HFILL }}, + + { &hf_smb_get_dfs_server_hold_storage, + { "Hold Storage", "smb.dfs.flags.server_hold_storage", FT_BOOLEAN, 16, + TFS(&tfs_get_dfs_server_hold_storage), 0x0002, "The servers in referrals should hold storage for the file", HFILL }}, + + { &hf_smb_get_dfs_fielding, + { "Fielding", "smb.dfs.flags.fielding", FT_BOOLEAN, 16, + TFS(&tfs_get_dfs_fielding), 0x0001, "The servers in referrals are capable of fielding", HFILL }}, + + { &hf_smb_dfs_referral_version, + { "Version", "smb.dfs.referral.version", FT_UINT16, BASE_DEC, + NULL, 0, "Version of referral element", HFILL }}, + + { &hf_smb_dfs_referral_size, + { "Size", "smb.dfs.referral.size", FT_UINT16, BASE_DEC, + NULL, 0, "Size of referral element", HFILL }}, + + { &hf_smb_dfs_referral_server_type, + { "Server Type", "smb.dfs.referral.server.type", FT_UINT16, BASE_DEC, + VALS(dfs_referral_server_type_vals), 0, "Type of referral server", HFILL }}, + + { &hf_smb_dfs_referral_flags, + { "Flags", "smb.dfs.referral.flags", FT_UINT16, BASE_HEX, + NULL, 0x0, NULL, HFILL }}, + + { &hf_smb_dfs_referral_flags_name_list_referral, + { "NameListReferral", "smb.dfs.referral.flags.name_list_referral", FT_BOOLEAN, 16, + TFS(&tfs_dfs_referral_flags_name_list_referral), REFENT_FLAGS_NAME_LIST_REFERRAL, "Is a domain/DC referral response?", HFILL }}, + + { &hf_smb_dfs_referral_flags_target_set_boundary, + { "TargetSetBoundary", "smb.dfs.referral.flags.target_set_boundary", FT_BOOLEAN, 16, + TFS(&tfs_dfs_referral_flags_target_set_boundary), REFENT_FLAGS_TARGET_SET_BOUNDARY, "Is this a first target in the target set?", HFILL }}, + + { &hf_smb_dfs_referral_node_offset, + { "Node Offset", "smb.dfs.referral.node_offset", FT_UINT16, BASE_DEC, + NULL, 0, "Offset of name of entity to visit next", HFILL }}, + + { &hf_smb_dfs_referral_node, + { "Node", "smb.dfs.referral.node", FT_STRING, BASE_NONE, + NULL, 0, "Name of entity to visit next", HFILL }}, + + { &hf_smb_dfs_referral_proximity, + { "Proximity", "smb.dfs.referral.proximity", FT_UINT32, BASE_DEC, + NULL, 0, "Hint describing proximity of this server to the client", HFILL }}, + + { &hf_smb_dfs_referral_ttl, + { "TTL", "smb.dfs.referral.ttl", FT_UINT32, BASE_DEC, + NULL, 0, "Number of seconds the client can cache this referral", HFILL }}, + + { &hf_smb_dfs_referral_path_offset, + { "Path Offset", "smb.dfs.referral.path_offset", FT_UINT16, BASE_DEC, + NULL, 0, "Offset of Dfs Path that matched pathconsumed", HFILL }}, + + { &hf_smb_dfs_referral_path, + { "Path", "smb.dfs.referral.path", FT_STRING, BASE_NONE, + NULL, 0, "Dfs Path that matched pathconsumed", HFILL }}, + + { &hf_smb_dfs_referral_alt_path_offset, + { "Alt Path Offset", "smb.dfs.referral.alt_path_offset", FT_UINT16, BASE_DEC, + NULL, 0, "Offset of alternative(8.3) Path that matched pathconsumed", HFILL }}, + + { &hf_smb_dfs_referral_alt_path, + { "Alt Path", "smb.dfs.referral.alt_path", FT_STRING, BASE_NONE, + NULL, 0, "Alternative(8.3) Path that matched pathconsumed", HFILL }}, + + { &hf_smb_dfs_referral_domain_offset, + { "Domain Offset", "smb.dfs.referral.domain_offset", FT_UINT16, BASE_DEC, + NULL, 0, "Offset of Dfs Path that matched pathconsumed", HFILL }}, + + { &hf_smb_dfs_referral_number_of_expnames, + { "Number of Expanded Names", "smb.dfs.referral.number_of_expnames", FT_UINT16, BASE_DEC, + NULL, 0, NULL, HFILL }}, + + { &hf_smb_dfs_referral_expnames_offset, + { "Expanded Names Offset", "smb.dfs.referral.expnames_offset", FT_UINT16, BASE_DEC, + NULL, 0, "Offset of Dfs Path that matched pathconsumed", HFILL }}, + + { &hf_smb_dfs_referral_domain_name, + { "Domain Name", "smb.dfs.referral.domain_name", FT_STRING, BASE_NONE, + NULL, 0, "Dfs referral domain name", HFILL }}, + + { &hf_smb_dfs_referral_expname, + { "Expanded Name", "smb.dfs.referral.expname", FT_STRING, BASE_NONE, + NULL, 0, "Dfs expanded name", HFILL }}, + + { &hf_smb_dfs_referral_server_guid, + { "Server GUID", "smb.dfs.referral.server_guid", FT_GUID, BASE_NONE, + NULL, 0, "Globally unique identifier for this server", HFILL }}, + + { &hf_smb_end_of_search, + { "End Of Search", "smb.end_of_search", FT_UINT16, BASE_DEC, + NULL, 0, "Was last entry returned?", HFILL }}, + + { &hf_smb_last_name_offset, + { "Last Name Offset", "smb.last_name_offset", FT_UINT16, BASE_DEC, + NULL, 0, "If non-0 this is the offset into the datablock for the file name of the last entry", HFILL }}, + + { &hf_smb_fn_information_level, + { "Level of Interest", "smb.fn_loi", FT_UINT16, BASE_DEC, + NULL, 0, "Level of interest for FIND_NOTIFY command", HFILL }}, + + { &hf_smb_monitor_handle, + { "Monitor Handle", "smb.monitor_handle", FT_UINT16, BASE_HEX, + NULL, 0, "Handle for Find Notify operations", HFILL }}, + + { &hf_smb_change_count, + { "Change Count", "smb.change_count", FT_UINT16, BASE_DEC, + NULL, 0, "Number of changes to wait for", HFILL }}, + + { &hf_smb_file_index, + { "File Index", "smb.file_index", FT_UINT32, BASE_DEC, + NULL, 0, NULL, HFILL }}, + + { &hf_smb_short_file_name, + { "Short File Name", "smb.short_file", FT_STRING, BASE_NONE, + NULL, 0, "Short (8.3) File Name", HFILL }}, + + { &hf_smb_short_file_name_len, + { "Short File Name Len", "smb.short_file_name_len", FT_UINT32, BASE_DEC, + NULL, 0, "Length of Short (8.3) File Name", HFILL }}, + + { &hf_smb_fs_id, + { "FS Id", "smb.fs_id", FT_UINT32, BASE_DEC, + NULL, 0, "File System ID (NT Server always returns 0)", HFILL }}, + + { &hf_smb_sector_unit, + { "Sectors/Unit", "smb.fs_sector_per_unit", FT_UINT32, BASE_DEC, + NULL, 0, "Sectors per allocation unit", HFILL }}, + + { &hf_smb_fs_units, + { "Total Units", "smb.fs_units", FT_UINT32, BASE_DEC, + NULL, 0, "Total number of units on this filesystem", HFILL }}, + + { &hf_smb_fs_sector, + { "Bytes per Sector", "smb.fs_bytes_per_sector", FT_UINT32, BASE_DEC, + NULL, 0, NULL, HFILL }}, + + { &hf_smb_avail_units, + { "Available Units", "smb.avail.units", FT_UINT32, BASE_DEC, + NULL, 0, "Total number of available units on this filesystem", HFILL }}, + + { &hf_smb_volume_serial_num, + { "Volume Serial Number", "smb.volume.serial", FT_UINT32, BASE_HEX, + NULL, 0, NULL, HFILL }}, + + { &hf_smb_volume_label_len, + { "Label Length", "smb.volume.label.len", FT_UINT32, BASE_DEC, + NULL, 0, "Length of volume label", HFILL }}, + + { &hf_smb_volume_label, + { "Label", "smb.volume.label", FT_STRING, BASE_NONE, + NULL, 0, "Volume label", HFILL }}, + + { &hf_smb_free_alloc_units64, + { "Free Units", "smb.free_alloc_units", FT_UINT64, BASE_DEC, + NULL, 0, "Number of free allocation units", HFILL }}, + + { &hf_smb_caller_free_alloc_units64, + { "Caller Free Units", "smb.caller_free_alloc_units", FT_UINT64, BASE_DEC, + NULL, 0, "Number of caller free allocation units", HFILL }}, + + { &hf_smb_actual_free_alloc_units64, + { "Actual Free Units", "smb.actual_free_alloc_units", FT_UINT64, BASE_DEC, + NULL, 0, "Number of actual free allocation units", HFILL }}, + + { &hf_smb_soft_quota_limit, + { "(Soft) Quota Threshold", "smb.quota.soft.default", FT_UINT64, BASE_DEC, + NULL, 0, "Soft Quota threshold", 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 }}, + + { &hf_smb_fs_name_len, + { "Label Length", "smb.fs_name.len", FT_UINT32, BASE_DEC, + NULL, 0, "Length of filesystem name in bytes", HFILL }}, + + { &hf_smb_fs_name, + { "FS Name", "smb.fs_name", FT_STRING, BASE_NONE, + NULL, 0, "Name of filesystem", HFILL }}, + + { &hf_smb_device_char, + { "Device Characteristics", "smb.device", FT_UINT32, BASE_HEX, + NULL, 0x0, NULL, HFILL }}, + + { &hf_smb_device_char_removable, + { "Removable", "smb.device.removable", FT_BOOLEAN, 32, + TFS(&tfs_device_char_removable), 0x00000001, "Is this a removable device", HFILL }}, + + { &hf_smb_device_char_read_only, + { "Read Only", "smb.device.read_only", FT_BOOLEAN, 32, + TFS(&tfs_device_char_read_only), 0x00000002, "Is this a read-only device", HFILL }}, + + { &hf_smb_device_char_floppy, + { "Floppy", "smb.device.floppy", FT_BOOLEAN, 32, + TFS(&tfs_device_char_floppy), 0x00000004, "Is this a floppy disk", HFILL }}, + + { &hf_smb_device_char_write_once, + { "Write Once", "smb.device.write_once", FT_BOOLEAN, 32, + TFS(&tfs_device_char_write_once), 0x00000008, "Is this a write-once device", HFILL }}, + + { &hf_smb_device_char_remote, + { "Remote", "smb.device.remote", FT_BOOLEAN, 32, + TFS(&tfs_device_char_remote), 0x00000010, "Is this a remote device", HFILL }}, + + { &hf_smb_device_char_mounted, + { "Mounted", "smb.device.mounted", FT_BOOLEAN, 32, + TFS(&tfs_device_char_mounted), 0x00000020, "Is this a mounted device", HFILL }}, + + { &hf_smb_device_char_virtual, + { "Virtual", "smb.device.virtual", FT_BOOLEAN, 32, + TFS(&tfs_device_char_virtual), 0x00000040, "Is this a virtual device", HFILL }}, + + { &hf_smb_device_char_secure_open, + { "Secure Open", "smb.device.secure_open", FT_BOOLEAN, 32, + TFS(&tfs_device_char_secure_open), 0x00000100, "Is this a secure open device", HFILL }}, + + { &hf_smb_device_char_ts, + { "Terminal Services", "smb.device.ts", FT_BOOLEAN, 32, + TFS(&tfs_device_char_ts), 0x00001000, "Is this a terminal services device", HFILL }}, + + { &hf_smb_device_char_webdav, + { "Webdav", "smb.device.webdav", FT_BOOLEAN, 32, + TFS(&tfs_device_char_webdav), 0x00002000, "Is this a WEBDAV device", HFILL }}, + + { &hf_smb_device_char_aat, + { "Allow Appcontainer Traversal", "smb.device.aat", FT_BOOLEAN, 32, + TFS(&tfs_device_char_aat), 0x00020000, "Does this device allow appcontainer traversal", HFILL }}, + + { &hf_smb_device_char_portable, + { "Portable", "smb.device.portable", FT_BOOLEAN, 32, + TFS(&tfs_device_char_portable), 0x00004000, "Is this a portable device", HFILL }}, + + { &hf_smb_fs_attr, + { "FS Attributes", "smb.fs_attr", FT_UINT32, BASE_HEX, + NULL, 0x0, NULL, HFILL }}, + + { &hf_smb_fs_attr_css, + { "Case Sensitive Search", "smb.fs_attr.css", FT_BOOLEAN, 32, + TFS(&tfs_fs_attr_css), 0x00000001, "Does this FS support Case Sensitive Search?", HFILL }}, + + { &hf_smb_fs_attr_cpn, + { "Case Preserving", "smb.fs_attr.cpn", FT_BOOLEAN, 32, + TFS(&tfs_fs_attr_cpn), 0x00000002, "Will this FS Preserve Name Case?", HFILL }}, + + { &hf_smb_fs_attr_uod, + { "Unicode On Disk", "smb.fs_attr.uod", FT_BOOLEAN, 32, + TFS(&tfs_fs_attr_uod), 0x00000004, "Does this FS support Unicode On Disk?", HFILL }}, + + { &hf_smb_fs_attr_pacls, + { "Persistent ACLs", "smb.fs_attr.pacls", FT_BOOLEAN, 32, + TFS(&tfs_fs_attr_pacls), 0x00000008, "Does this FS support Persistent ACLs?", HFILL }}, + + { &hf_smb_fs_attr_fc, + { "Compression", "smb.fs_attr.fc", FT_BOOLEAN, 32, + TFS(&tfs_fs_attr_fc), 0x00000010, "Does this FS support File Compression?", HFILL }}, + + { &hf_smb_fs_attr_vq, + { "Volume Quotas", "smb.fs_attr.vq", FT_BOOLEAN, 32, + TFS(&tfs_fs_attr_vq), 0x00000020, "Does this FS support Volume Quotas?", HFILL }}, + + { &hf_smb_fs_attr_ssf, + { "Sparse Files", "smb.fs_attr.ssf", FT_BOOLEAN, 32, + TFS(&tfs_fs_attr_ssf), 0x00000040, "Does this FS support SPARSE FILES?", HFILL }}, + + { &hf_smb_fs_attr_srp, + { "Reparse Points", "smb.fs_attr.srp", FT_BOOLEAN, 32, + TFS(&tfs_fs_attr_srp), 0x00000080, "Does this FS support REPARSE POINTS?", HFILL }}, + + { &hf_smb_fs_attr_srs, + { "Remote Storage", "smb.fs_attr.srs", FT_BOOLEAN, 32, + TFS(&tfs_fs_attr_srs), 0x00000100, "Does this FS support REMOTE STORAGE?", HFILL }}, + + { &hf_smb_fs_attr_sla, + { "LFN APIs", "smb.fs_attr.sla", FT_BOOLEAN, 32, + TFS(&tfs_fs_attr_sla), 0x00004000, "Does this FS support LFN APIs?", HFILL }}, + + { &hf_smb_fs_attr_vic, + { "Volume Is Compressed", "smb.fs_attr.vis", FT_BOOLEAN, 32, + TFS(&tfs_fs_attr_vic), 0x00008000, "Is this FS on a compressed volume?", HFILL }}, + + { &hf_smb_fs_attr_soids, + { "Supports OIDs", "smb.fs_attr.soids", FT_BOOLEAN, 32, + TFS(&tfs_fs_attr_soids), 0x00010000, "Does this FS support OIDs?", HFILL }}, + + { &hf_smb_fs_attr_se, + { "Supports Encryption", "smb.fs_attr.se", FT_BOOLEAN, 32, + TFS(&tfs_fs_attr_se), 0x00020000, "Does this FS support encryption?", HFILL }}, + + { &hf_smb_fs_attr_ns, + { "Named Streams", "smb.fs_attr.ns", FT_BOOLEAN, 32, + TFS(&tfs_fs_attr_ns), 0x00040000, "Does this FS support named streams?", HFILL }}, + + { &hf_smb_fs_attr_rov, + { "Read Only Volume", "smb.fs_attr.rov", FT_BOOLEAN, 32, + TFS(&tfs_fs_attr_rov), 0x00080000, "Is this FS on a read only volume?", HFILL }}, + + { &hf_smb_fs_attr_swo, + { "Sequential Write Once", "smb.fs_attr.swo", FT_BOOLEAN, 32, + TFS(&tfs_fs_attr_swo), 0x00100000, "Is this FS on a sequential write once volume?", HFILL }}, + + { &hf_smb_fs_attr_st, + { "Transactions", "smb.fs_attr.st", FT_BOOLEAN, 32, + TFS(&tfs_fs_attr_st), 0x00200000, "Does this FS support transactions?", HFILL }}, + + { &hf_smb_fs_attr_shl, + { "Hard Links", "smb.fs_attr.shl", FT_BOOLEAN, 32, + TFS(&tfs_fs_attr_shl), 0x00400000, "Does this FS support hard links?", HFILL }}, + + { &hf_smb_fs_attr_sis, + { "Integrity Streams", "smb.fs_attr.sis", FT_BOOLEAN, 32, + TFS(&tfs_fs_attr_sis), 0x04000000, "Does this FS support integrity streams?", HFILL }}, + + { &hf_smb_fs_attr_sbr, + { "Block Refcounting", "smb.fs_attr.sbr", FT_BOOLEAN, 32, + TFS(&tfs_fs_attr_sbr), 0x08000000, "Does this FS support block refcounting?", HFILL }}, + + { &hf_smb_fs_attr_ssv, + { "Sparse VDL", "smb.fs_attr.ssv", FT_BOOLEAN, 32, + TFS(&tfs_fs_attr_ssv), 0x10000000, "Does this FS support sparse VDL?", HFILL }}, + + { &hf_smb_user_quota_change_time, + { "Change Time", "smb.quota.user.change_time", FT_ABSOLUTE_TIME, ABSOLUTE_TIME_LOCAL, + NULL, 0x0, "The last time the quota was changed", HFILL }}, + + { &hf_smb_length_of_sid, + { "Length of SID", "smb.length_of_sid", FT_UINT32, BASE_DEC, + NULL, 0x0, NULL, 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_pipe_write_len, + { "Pipe Write Len", "smb.pipe.write_len", FT_UINT16, BASE_DEC, + NULL, 0, "Number of bytes written to pipe", 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, + { "Quota Flags", "smb.quota.flags", FT_UINT8, BASE_HEX, + NULL, 0x0, NULL, 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 }}, + + { &hf_smb_segment_overlap, + { "Fragment overlap", "smb.segment.overlap", FT_BOOLEAN, BASE_NONE, NULL, 0x0, + "Fragment overlaps with other fragments", HFILL }}, + + { &hf_smb_segment_overlap_conflict, + { "Conflicting data in fragment overlap", "smb.segment.overlap.conflict", FT_BOOLEAN, BASE_NONE, NULL, 0x0, + "Overlapping fragments contained conflicting data", HFILL }}, + + { &hf_smb_segment_multiple_tails, + { "Multiple tail fragments found", "smb.segment.multipletails", FT_BOOLEAN, BASE_NONE, NULL, 0x0, + "Several tails were found when defragmenting the packet", HFILL }}, + + { &hf_smb_segment_too_long_fragment, + { "Fragment too long", "smb.segment.toolongfragment", FT_BOOLEAN, BASE_NONE, NULL, 0x0, + "Fragment contained data past end of packet", HFILL }}, + + { &hf_smb_segment_error, + { "Defragmentation error", "smb.segment.error", FT_FRAMENUM, BASE_NONE, NULL, 0x0, + "Defragmentation error due to illegal fragments", HFILL }}, + + { &hf_smb_segment_count, + { "Fragment count", "smb.fragment.count", FT_UINT32, BASE_DEC, NULL, 0x0, + NULL, HFILL }}, + + { &hf_smb_reassembled_length, + { "Reassembled SMB length", "smb.reassembled.length", FT_UINT32, BASE_DEC, NULL, 0x0, + "The total length of the reassembled payload", HFILL }}, + + { &hf_smb_opened_in, + { "Opened in", "smb.fid.opened_in", FT_FRAMENUM, BASE_NONE, NULL, 0x0, + "The frame this fid was opened", HFILL }}, + + { &hf_smb_closed_in, + { "Closed in", "smb.fid.closed_in", FT_FRAMENUM, BASE_NONE, NULL, 0x0, + "The frame this fid was closed", HFILL }}, + + { &hf_smb_mapped_in, + { "Mapped in", "smb.fid.mapped_in", FT_FRAMENUM, BASE_NONE, NULL, 0x0, + "The frame this share was mapped", HFILL }}, + + { &hf_smb_unmapped_in, + { "Unmapped in", "smb.fid.unmapped_in", FT_FRAMENUM, BASE_NONE, NULL, 0x0, + "The frame this share was unmapped", HFILL }}, + + { &hf_smb_segment, + { "SMB Segment", "smb.segment", FT_FRAMENUM, BASE_NONE, NULL, 0x0, + NULL, HFILL }}, + + { &hf_smb_segments, + { "SMB Segments", "smb.segment.segments", FT_NONE, BASE_NONE, NULL, 0x0, + NULL, HFILL }}, + + { &hf_smb_unix_major_version, + { "Major Version", "smb.unix.major_version", FT_UINT16, BASE_DEC, + NULL, 0, "UNIX Major Version", HFILL }}, + + { &hf_smb_unix_minor_version, + { "Minor Version", "smb.unix.minor_version", FT_UINT16, BASE_DEC, + NULL, 0, "UNIX Minor Version", HFILL }}, + + { &hf_smb_unix_capability, + { "Capabilities", "smb.unix.capability", FT_UINT64, BASE_HEX, + NULL, 0x0, NULL, HFILL }}, + + { &hf_smb_unix_capability_fcntl, + { "FCNTL Capability", "smb.unix.capability.fcntl", FT_BOOLEAN, 32, + TFS(&tfs_set_notset), 0x00000001, NULL, HFILL }}, + + { &hf_smb_unix_capability_posix_acl, + { "POSIX ACL Capability", "smb.unix.capability.posix_acl", FT_BOOLEAN, 32, + TFS(&tfs_set_notset), 0x00000002, NULL, HFILL }}, + + { &hf_smb_unix_capability_xattr, + { "EA Capability", "smb.unix.capability.ea", FT_BOOLEAN, 32, + TFS(&tfs_set_notset), 0x00000004, NULL, HFILL }}, + + { &hf_smb_unix_capability_attr, + { "Additional Attributes Capability", "smb.unix.capability.attr", FT_BOOLEAN, 32, + TFS(&tfs_set_notset), 0x00000008, NULL, HFILL }}, + + { &hf_smb_unix_capability_posix_paths, + { "POSIX Pathnames Capability", "smb.unix.capability.posix_paths", FT_BOOLEAN, 32, + TFS(&tfs_set_notset), 0x00000010, NULL, HFILL }}, + + { &hf_smb_unix_capability_posix_path_ops, + { "POSIX Path Operations Capability", "smb.unix.capability.posix_path_ops", FT_BOOLEAN, 32, + TFS(&tfs_set_notset), 0x00000020, NULL, HFILL }}, + + { &hf_smb_unix_capability_large_read, + { "Large Read Capability", "smb.unix.capability.large_read", FT_BOOLEAN, 32, + TFS(&tfs_set_notset), 0x00000040, NULL, HFILL }}, + + { &hf_smb_unix_capability_large_write, + { "Large Write Capability", "smb.unix.capability.large_write", FT_BOOLEAN, 32, + TFS(&tfs_set_notset), 0x00000080, NULL, HFILL }}, + + { &hf_smb_unix_capability_encryption, + { "Encryption Capability", "smb.unix.capability.encryption", FT_BOOLEAN, 32, + TFS(&tfs_set_notset), 0x00000100, NULL, HFILL }}, + + { &hf_smb_unix_capability_mandatory_crypto, + { "Mandatory Encryption Capability", "smb.unix.capability.mandatory_crypto", FT_BOOLEAN, 32, + TFS(&tfs_set_notset), 0x00000200, NULL, HFILL }}, + + { &hf_smb_unix_capability_proxy, + { "Proxy Capability", "smb.unix.capability.proxy", FT_BOOLEAN, 32, + TFS(&tfs_set_notset), 0x00000400, NULL, HFILL }}, + + { &hf_smb_file_access_mask_read_data, + { "Read Data", "smb.file.accessmask.read_data", FT_BOOLEAN, 32, + TFS(&tfs_set_notset), 0x00000001, NULL, HFILL }}, + + { &hf_smb_file_access_mask_write_data, + { "Write Data", "smb.file.accessmask.write_data", FT_BOOLEAN, 32, + TFS(&tfs_set_notset), 0x00000002, NULL, HFILL }}, + + { &hf_smb_file_access_mask_append_data, + { "Append Data", "smb.file.accessmask.append_data", FT_BOOLEAN, 32, + TFS(&tfs_set_notset), 0x00000004, NULL, HFILL }}, + + { &hf_smb_file_access_mask_read_ea, + { "Read EA", "smb.file.accessmask.read_ea", FT_BOOLEAN, 32, + TFS(&tfs_set_notset), 0x00000008, NULL, HFILL }}, + + { &hf_smb_file_access_mask_write_ea, + { "Write EA", "smb.file.accessmask.write_ea", FT_BOOLEAN, 32, + TFS(&tfs_set_notset), 0x00000010, NULL, HFILL }}, + + { &hf_smb_file_access_mask_execute, + { "Execute", "smb.file.accessmask.execute", FT_BOOLEAN, 32, + TFS(&tfs_set_notset), 0x00000020, NULL, HFILL }}, + + { &hf_smb_file_access_mask_read_attribute, + { "Read Attribute", "smb.file.accessmask.read_attribute", FT_BOOLEAN, 32, + TFS(&tfs_set_notset), 0x00000080, NULL, HFILL }}, + + { &hf_smb_file_access_mask_write_attribute, + { "Write Attribute", "smb.file.accessmask.write_attribute", FT_BOOLEAN, 32, + TFS(&tfs_set_notset), 0x00000100, NULL, HFILL }}, + + { &hf_smb_dir_access_mask_list, + { "List", "smb.dir.accessmask.list", FT_BOOLEAN, 32, + TFS(&tfs_set_notset), 0x00000001, NULL, HFILL }}, + + { &hf_smb_dir_access_mask_add_file, + { "Add File", "smb.dir.accessmask.add_file", FT_BOOLEAN, 32, + TFS(&tfs_set_notset), 0x00000002, NULL, HFILL }}, + + { &hf_smb_dir_access_mask_add_subdir, + { "Add Subdir", "smb.dir.accessmask.add_subdir", FT_BOOLEAN, 32, + TFS(&tfs_set_notset), 0x00000004, NULL, HFILL }}, + + { &hf_smb_dir_access_mask_read_ea, + { "Read EA", "smb.dir.accessmask.read_ea", FT_BOOLEAN, 32, + TFS(&tfs_set_notset), 0x00000008, NULL, HFILL }}, + + { &hf_smb_dir_access_mask_write_ea, + { "Write EA", "smb.dir.accessmask.write_ea", FT_BOOLEAN, 32, + TFS(&tfs_set_notset), 0x00000010, NULL, HFILL }}, + + { &hf_smb_dir_access_mask_traverse, + { "Traverse", "smb.dir.accessmask.traverse", FT_BOOLEAN, 32, + TFS(&tfs_set_notset), 0x00000020, NULL, HFILL }}, + + { &hf_smb_dir_access_mask_delete_child, + { "Delete Child", "smb.dir.accessmask.delete_child", FT_BOOLEAN, 32, + TFS(&tfs_set_notset), 0x00000040, NULL, HFILL }}, + + { &hf_smb_dir_access_mask_read_attribute, + { "Read Attribute", "smb.dir.accessmask.read_attribute", FT_BOOLEAN, 32, + TFS(&tfs_set_notset), 0x00000080, NULL, HFILL }}, + + { &hf_smb_dir_access_mask_write_attribute, + { "Write Attribute", "smb.dir.accessmask.write_attribute", FT_BOOLEAN, 32, + TFS(&tfs_set_notset), 0x00000100, NULL, HFILL }}, + + { &hf_smb_unix_file_link_dest, + { "Link destination", "smb.unix.file.link_dest", FT_STRING, + BASE_NONE, NULL, 0, NULL, HFILL }}, + + { &hf_smb_unix_file_size, + { "File size", "smb.unix.file.size", FT_UINT64, BASE_DEC, + NULL, 0, NULL, HFILL }}, + + { &hf_smb_unix_file_num_bytes, + { "Number of bytes", "smb.unix.file.num_bytes", FT_UINT64, BASE_DEC, + NULL, 0, "Number of bytes used to store the file", HFILL }}, + + { &hf_smb_unix_file_last_status, + { "Last status change", "smb.unix.file.stime", FT_ABSOLUTE_TIME, ABSOLUTE_TIME_LOCAL, + NULL, 0, NULL, HFILL }}, + + { &hf_smb_unix_file_last_access, + { "Last access", "smb.unix.file.atime", FT_ABSOLUTE_TIME, ABSOLUTE_TIME_LOCAL, + NULL, 0, NULL, HFILL }}, + + { &hf_smb_unix_file_last_change, + { "Last modification", "smb.unix.file.mtime", FT_ABSOLUTE_TIME, ABSOLUTE_TIME_LOCAL, + NULL, 0, NULL, HFILL }}, + + { &hf_smb_unix_file_creation_time, + { "Creation time", "smb.unix.file.crtime", FT_ABSOLUTE_TIME, ABSOLUTE_TIME_LOCAL, + NULL, 0, NULL, HFILL }}, + + { &hf_smb_unix_file_uid, + { "UID", "smb.unix.file.uid", FT_UINT64, BASE_DEC, + NULL, 0, NULL, HFILL }}, + + { &hf_smb_unix_file_gid, + { "GID", "smb.unix.file.gid", FT_UINT64, BASE_DEC, + NULL, 0, NULL, HFILL }}, + + { &hf_smb_unix_file_type, + { "File type", "smb.unix.file.file_type", FT_UINT32, BASE_DEC, + VALS(unix_file_type_vals), 0, NULL, HFILL }}, + + { &hf_smb_unix_file_dev_major, + { "Major device", "smb.unix.file.dev_major", FT_UINT64, BASE_HEX, + NULL, 0, NULL, HFILL }}, + + { &hf_smb_unix_file_dev_minor, + { "Minor device", "smb.unix.file.dev_minor", FT_UINT64, BASE_HEX, + NULL, 0, NULL, HFILL }}, + + { &hf_smb_unix_file_unique_id, + { "Unique ID", "smb.unix.file.unique_id", FT_UINT64, BASE_HEX, + NULL, 0, NULL, HFILL }}, + + { &hf_smb_unix_file_permissions, + { "File permissions", "smb.unix.file.perms", FT_UINT64, BASE_HEX, + NULL, 0, NULL, HFILL }}, + + { &hf_smb_unix_file_nlinks, + { "Num links", "smb.unix.file.num_links", FT_UINT64, BASE_DEC, + NULL, 0, NULL, HFILL }}, + + { &hf_smb_unix_info2_file_flags, + { "Flags", "smb.unix_info2.file.flags", FT_UINT32, BASE_HEX, + NULL, 0, NULL, HFILL }}, + + { &hf_smb_unix_info2_file_flags_mask, + { "Flags mask", "smb.unix_info2.file.flags_mask", FT_UINT32, BASE_HEX, + NULL, 0, NULL, HFILL }}, + + { &hf_smb_unix_info2_file_flags_secure_delete, + { "Secure delete", "smb.unix_info2.file.flags.secure_delete", FT_BOOLEAN, 32, + NULL, 0x00000001, NULL, HFILL }}, + + { &hf_smb_unix_info2_file_flags_enable_undelete, + { "Enable undelete", "smb.unix_info2.file.flags.enable_undelete", FT_BOOLEAN, 32, + NULL, 0x00000002, NULL, HFILL }}, + + { &hf_smb_unix_info2_file_flags_synchronous, + { "Synchronous", "smb.unix_info2.file.flags.synchronous", FT_BOOLEAN, 32, + NULL, 0x00000004, NULL, HFILL }}, + + { &hf_smb_unix_info2_file_flags_immutable, + { "Immutable", "smb.unix_info2.file.flags.immutable", FT_BOOLEAN, 32, + NULL, 0x00000008, NULL, HFILL }}, + + { &hf_smb_unix_info2_file_flags_append_only, + { "Append-only", "smb.unix_info2.file.flags.append_only", FT_BOOLEAN, 32, + NULL, 0x00000010, NULL, HFILL }}, + + { &hf_smb_unix_info2_file_flags_do_not_backup, + { "Do not backup", "smb.unix_info2.file.flags.do_not_backup", FT_BOOLEAN, 32, + NULL, 0x00000020, NULL, HFILL }}, + + { &hf_smb_unix_info2_file_flags_no_update_atime, + { "Don't update atime", "smb.unix_info2.file.flags.no_update_atime", FT_BOOLEAN, 32, + NULL, 0x00000040, NULL, HFILL }}, + + { &hf_smb_unix_info2_file_flags_hidden, + { "Hidden", "smb.unix_info2.file.flags.hidden", FT_BOOLEAN, 32, + NULL, 0x00000080, NULL, HFILL }}, + + { &hf_smb_unix_file_name_length, + { "File name length", "smb.unix.file.name_length", FT_UINT32, BASE_DEC, + NULL, 0, NULL, HFILL }}, + + { &hf_smb_unix_file_name, + { "File name", "smb.unix.file.name", FT_STRING, + BASE_NONE, NULL, 0, NULL, HFILL }}, + + { &hf_smb_unix_find_file_nextoffset, + { "Next entry offset", "smb.unix.find_file.next_offset", FT_UINT32, BASE_DEC, + NULL, 0, NULL, HFILL }}, + + { &hf_smb_unix_find_file_resumekey, + { "Resume key", "smb.unix.find_file.resume_key", FT_UINT32, BASE_DEC, + NULL, 0, NULL, HFILL }}, + + { &hf_smb_unix_whoami_mapflags, + { "UNIX whoami mapping flags", "smb.unix.whoami.mapflags", FT_UINT32, BASE_DEC, + NULL, 0, NULL, HFILL }}, + + { &hf_smb_unix_whoami_mapflags_mask, + { "UNIX whoami mapping flags mask", "smb.unix.whoami.mapflags_mask", FT_UINT32, BASE_DEC, + NULL, 0, NULL, HFILL }}, + + { &hf_smb_unix_whoami_num_supl_gids, + { "Number of supplementary UNIX GIDs", "smb.unix.whoami.num_gids", FT_UINT32, BASE_DEC, + NULL, 0, NULL, HFILL }}, + + { &hf_smb_unix_whoami_num_supl_sids, + { "Number of supplementary SIDs", "smb.unix.whoami.num_sids", FT_UINT32, BASE_DEC, + NULL, 0, NULL, HFILL }}, + + { &hf_smb_unix_whoami_sids_buflen, + { "Supplementary SIDs buffer length", "smb.unix.whoami.sids_buflen", FT_UINT32, BASE_DEC, + NULL, 0, NULL, HFILL }}, + + { &hf_smb_create_flags, + { "Create Flags", "smb.create_flags", FT_UINT32, BASE_HEX, + NULL, 0, NULL, HFILL }}, + + { &hf_smb_create_options, + { "Create Options", "smb.create_options", FT_UINT32, BASE_HEX, + NULL, 0, NULL, HFILL }}, + + { &hf_smb_share_access, + { "Share Access", "smb.share_access", FT_UINT32, BASE_HEX, + NULL, 0, NULL, HFILL }}, + + { &hf_smb_access_mask, + { "Access Mask", "smb.access_mask", FT_UINT32, BASE_HEX, + NULL, 0, NULL, HFILL }}, + + { &hf_smb_mode, + { "Mode", "smb.mode", FT_UINT32, BASE_HEX, + NULL, 0, NULL, HFILL }}, + + { &hf_smb_attribute, + { "Attribute", "smb.attribute", FT_UINT32, BASE_HEX, + NULL, 0, NULL, HFILL }}, + + { &hf_smb_reparse_tag, + { "Reparse Tag", "smb.reparse_tag", FT_UINT32, BASE_HEX, + NULL, 0, NULL, HFILL }}, + + { &hf_smb_disposition_delete_on_close, + { "Delete on close", "smb.disposition.delete_on_close", FT_BOOLEAN, 8, + TFS(&tfs_disposition_delete_on_close), 0x01, NULL, HFILL }}, + + { &hf_smb_pipe_info_flag, + { "Pipe Info", "smb.pipe_info_flag", FT_BOOLEAN, 8, + TFS(&tfs_pipe_info_flag), 0x01, NULL, HFILL }}, + + { &hf_smb_logged_in, + { "Logged In", "smb.logged_in", FT_FRAMENUM, BASE_NONE, + NULL, 0, NULL, HFILL }}, + + { &hf_smb_logged_out, + { "Logged Out", "smb.logged_out", FT_FRAMENUM, BASE_NONE, + NULL, 0, NULL, HFILL }}, + + { &hf_smb_file_rw_offset, + { "File Offset", "smb.file.rw.offset", FT_UINT64, BASE_DEC, + NULL, 0, NULL, HFILL }}, + + { &hf_smb_file_rw_length, + { "File RW Length", "smb.file.rw.length", FT_UINT32, BASE_DEC, + NULL, 0, NULL, HFILL }}, + + { &hf_smb_posix_acl_version, + { "Posix ACL version", "smb.posix_acl.version", FT_UINT16, BASE_DEC, + NULL, 0, NULL, HFILL }}, + + { &hf_smb_posix_num_file_aces, + { "Number of file ACEs", "smb.posix_acl.num_file_aces", FT_UINT16, BASE_DEC, + NULL, 0, NULL, HFILL }}, + + { &hf_smb_posix_num_def_aces, + { "Number of default ACEs", "smb.posix_acl.num_def_aces", FT_UINT16, BASE_DEC, + NULL, 0, NULL, HFILL }}, + + { &hf_smb_posix_ace_type, + { "ACE Type", "smb.posix_acl.ace_type", FT_UINT8, BASE_DEC, + VALS(ace_type_vals), 0, NULL, HFILL }}, + + { &hf_smb_posix_ace_flags, + { "Permissions", "smb.posix_acl.ace_perms", FT_UINT8, BASE_HEX, + NULL, 0, NULL, HFILL }}, + + { &hf_smb_posix_ace_perm_read, + {"READ", "smb.posix_acl.ace_perms.read", FT_BOOLEAN, 8, + NULL, 0x04, NULL, HFILL}}, + + { &hf_smb_posix_ace_perm_write, + {"WRITE", "smb.posix_acl.ace_perms.write", FT_BOOLEAN, 8, + NULL, 0x02, NULL, HFILL}}, + + { &hf_smb_posix_ace_perm_execute, + {"EXECUTE", "smb.posix_acl.ace_perms.execute", FT_BOOLEAN, 8, + NULL, 0x01, NULL, HFILL}}, + + { &hf_smb_posix_ace_perm_owner_uid, + { "Owner UID", "smb.posix_acl.ace_perms.owner_uid", FT_UINT32, BASE_DEC, + NULL, 0, NULL, HFILL }}, + + { &hf_smb_posix_ace_perm_owner_gid, + { "Owner GID", "smb.posix_acl.ace_perms.owner_gid", FT_UINT32, BASE_DEC, + NULL, 0, NULL, HFILL }}, + + { &hf_smb_posix_ace_perm_uid, + { "UID", "smb.posix_acl.ace_perms.uid", FT_UINT32, BASE_DEC, + NULL, 0, NULL, HFILL }}, + + { &hf_smb_posix_ace_perm_gid, + { "GID", "smb.posix_acl.ace_perms.gid", FT_UINT32, BASE_DEC, + NULL, 0, NULL, HFILL }}, + + { &hf_smb_trans_data_setup_word, + { "Setup Word", "smb.trans_data.setup_word", FT_UINT16, BASE_HEX, + NULL, 0x0, NULL, HFILL }}, + + { &hf_smb_trans_data_parameters, + { "Parameters", "smb.trans_data.parameters", FT_BYTES, BASE_NONE, + NULL, 0x0, NULL, HFILL }}, + + { &hf_smb_trans_data, + { "Data", "smb.trans_data", FT_BYTES, BASE_NONE, + NULL, 0x0, NULL, HFILL }}, + + { &hf_smb_extra_byte_parameters, + { "Extra byte parameters", "smb.extra_byte_parameters", FT_BYTES, BASE_NONE, + NULL, 0x0, NULL, HFILL }}, + + { &hf_smb_file_access_mask_full_control, + { "FULL CONTROL", "smb.file.accessmask.full_control", FT_UINT32, BASE_HEX, + NULL, 0x000001ff, NULL, HFILL }}, + + { &hf_smb_dir_access_mask_full_control, + { "FULL CONTROL", "smb.dir.accessmask.full_control", FT_UINT32, BASE_HEX, + NULL, 0x000001ff, NULL, HFILL }}, + + { &hf_smb_word_unk_response_format, + { "Words for unknown response format", "smb.word_unk_response_format", FT_BYTES, BASE_NONE, + NULL, 0x0, NULL, HFILL }}, + + { &hf_smb_nt_transaction_setup, + { "NT Transaction Setup", "smb.nt_transaction_setup", FT_BYTES, BASE_NONE, + NULL, 0x0, NULL, HFILL }}, + + { &hf_smb_server_component, + { "Server Component", "smb.server_component", FT_UINT32, BASE_HEX, + NULL, 0x0, NULL, HFILL }}, + + { &hf_smb_byte_parameters, + { "Byte parameters", "smb.byte_parameters", FT_BYTES, BASE_NONE, + NULL, 0x0, NULL, HFILL }}, + + { &hf_smb_word_parameters, + { "Word parameters", "smb.word_parameters", FT_BYTES, BASE_NONE, + NULL, 0x0, NULL, HFILL }}, + }; + + static gint *ett[] = { + &ett_smb, + &ett_smb_fid, + &ett_smb_tid, + &ett_smb_uid, + &ett_smb_hdr, + &ett_smb_command, + &ett_smb_fileattributes, + &ett_smb_capabilities, + &ett_smb_aflags, + &ett_smb_dialect, + &ett_smb_dialects, + &ett_smb_mode, + &ett_smb_rawmode, + &ett_smb_flags, + &ett_smb_flags2, + &ett_smb_desiredaccess, + &ett_smb_search, + &ett_smb_file, + &ett_smb_openfunction, + &ett_smb_filetype, + &ett_smb_openaction, + &ett_smb_writemode, + &ett_smb_lock_type, + &ett_smb_ssetupandxaction, + &ett_smb_optionsup, + &ett_smb_time_date, + &ett_smb_move_copy_flags, + &ett_smb_file_attributes, + &ett_smb_search_resume_key, + &ett_smb_search_dir_info, + &ett_smb_unlocks, + &ett_smb_unlock, + &ett_smb_locks, + &ett_smb_lock, + &ett_smb_open_flags, + &ett_smb_ipc_state, + &ett_smb_open_action, + &ett_smb_setup_action, + &ett_smb_connect_flags, + &ett_smb_connect_support_bits, + &ett_smb_nt_access_mask, + &ett_smb_nt_create_bits, + &ett_smb_nt_create_options, + &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, + &ett_smb_print_queue_entry, + &ett_smb_transaction_flags, + &ett_smb_transaction_params, + &ett_smb_find_first2_flags, +#if 0 + &ett_smb_ioflag, +#endif + &ett_smb_transaction_data, + &ett_smb_stream_info, + &ett_smb_dfs_referrals, + &ett_smb_dfs_referral, + &ett_smb_dfs_referral_flags, + &ett_smb_dfs_referral_expnames, + &ett_smb_get_dfs_flags, + &ett_smb_ff2_data, + &ett_smb_device_characteristics, + &ett_smb_fs_attributes, + &ett_smb_segments, + &ett_smb_segment, + &ett_smb_quotaflags, + &ett_smb_secblob, + &ett_smb_mac_support_flags, + &ett_smb_unicode_password, + &ett_smb_ea, + &ett_smb_unix_capabilities, + &ett_smb_unix_whoami_gids, + &ett_smb_unix_whoami_sids, + &ett_smb_posix_ace, + &ett_smb_posix_ace_perms, + &ett_smb_info2_file_flags + }; + + static ei_register_info ei[] = { + { &ei_smb_missing_word_parameters, {"smb.missing_word_parameters", PI_MALFORMED, PI_ERROR, "The word parameters are missing, so the byte parameters cannot be dissected.", EXPFILL }}, + { &ei_smb_mal_information_level, { "smb.information_level.malformed", PI_MALFORMED, PI_ERROR, "Information level structure goes past the end of the transaction data.", EXPFILL }}, + { &ei_smb_not_implemented, { "smb.not_implemented", PI_UNDECODED, PI_WARN, "Not Implemented yet", EXPFILL }}, + { &ei_smb_nt_transaction_setup, { "smb.nt_transaction_setup.unknown", PI_PROTOCOL, PI_NOTE, "Unknown NT Transaction Setup (matching request not seen)", EXPFILL }}, + { &ei_smb_posix_ace_type, { "smb.posix_acl.ace_type.unknown", PI_PROTOCOL, PI_WARN, "Unknown posix ace type", EXPFILL }}, + { &ei_smb_info_level_unknown, { "smb.info_level_unknown", PI_PROTOCOL, PI_WARN, "Information level unknown", EXPFILL }}, + { &ei_smb_info_level_not_understood, { "smb.info_level_not_understood", PI_PROTOCOL, PI_WARN, "Information level not understood", EXPFILL }}, + }; + + module_t *smb_module; + expert_module_t* expert_smb; + + proto_smb = proto_register_protocol("SMB (Server Message Block Protocol)", + "SMB", "smb"); + proto_register_subtree_array(ett, array_length(ett)); + proto_register_field_array(proto_smb, hf, array_length(hf)); + expert_smb = expert_register_protocol(proto_smb); + expert_register_field_array(expert_smb, ei, array_length(ei)); + + proto_do_register_windows_common(proto_smb); + + register_cleanup_routine(&smb_cleanup); + smb_module = prefs_register_protocol(proto_smb, NULL); + prefs_register_bool_preference(smb_module, "trans_reassembly", + "Reassemble SMB Transaction payload", + "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 reassemble DCERPC over SMB commands", + &smb_dcerpc_reassembly); + prefs_register_bool_preference(smb_module, "sid_name_snooping", + "Snoop SID to Name mappings", + "Whether the dissector should snoop SMB and related CIFS protocols to discover and display Names associated with SIDs", + &sid_name_snooping); + + /* For display of SIDs and RIDs in Hex option */ + prefs_register_bool_preference(smb_module, "sid_display_hex", + "Display SIDs in Hex", + "Whether the dissector should display SIDs and RIDs in hexadecimal rather than decimal", + &sid_display_hex); + + /* Will Export Object take name as fid ? */ + prefs_register_bool_preference(smb_module, "eosmb_take_name_as_fid", + "Use the full file name as File ID when exporting an SMB object", + "Whether the export object functionality will take the full path file name as file identifier", + &eosmb_take_name_as_fid); + + /* + * XXX - addresses_ports_reassembly_table_functions? + * Probably correct for SMB-over-NBT and SMB-over-TCP, + * as stuff from two different connections should + * probably not be combined, but what about other + * transports for SMB, e.g. NBF or Netware? + */ + reassembly_table_register(&smb_trans_reassembly_table, + &addresses_reassembly_table_functions); + + smb_tap = register_tap("smb"); + + smb_handle = register_dissector("smb", dissect_smb, proto_smb); + + register_srt_table(proto_smb, NULL, 3, smbstat_packet, smbstat_init, NULL); + /* Register the tap for the "Export Object" function */ + smb_eo_tap = register_export_object(proto_smb, smb_eo_packet, smb_eo_cleanup); +} + +void +proto_reg_handoff_smb(void) +{ + gssapi_handle = find_dissector_add_dependency("gssapi", proto_smb); + ntlmssp_handle = find_dissector_add_dependency("ntlmssp", proto_smb); + + heur_dissector_add("netbios", dissect_smb_heur, "SMB over Netbios", "smb_netbios", proto_smb, HEURISTIC_ENABLE); + heur_dissector_add("smb_direct", dissect_smb_heur, "SMB over SMB Direct", "smb_smb_direct", proto_smb, HEURISTIC_ENABLE); + heur_dissector_add("cotp", dissect_smb_heur, "SMB over COTP", "smb_cotp", proto_smb, HEURISTIC_ENABLE); + heur_dissector_add("vines_spp", dissect_smb_heur, "SMB over Vines", "smb_vines", proto_smb, HEURISTIC_ENABLE); + + dissector_add_uint("ipx.socket", IPX_SOCKET_NWLINK_SMB_SERVER, smb_handle); + dissector_add_uint("ipx.socket", IPX_SOCKET_NWLINK_SMB_REDIR, smb_handle); + dissector_add_uint("ipx.socket", IPX_SOCKET_NWLINK_SMB_MESSENGER, smb_handle); + dissector_add_uint("spp.socket", IDP_SOCKET_SMB, smb_handle); +} + +/* + * Editor modelines - https://www.wireshark.org/tools/modelines.html + * + * Local variables: + * c-basic-offset: 8 + * tab-width: 8 + * indent-tabs-mode: t + * End: + * + * vi: set shiftwidth=8 tabstop=8 noexpandtab: + * :indentSize=8:tabSize=8:noTabs=false: + */ |