/* XXX Fixme : continuation stuff removed, should be solved by smb reassembly XXX Fixme : shouldnt show [malformed frame] for long packets */ /* packet-smb-pipe.c * Routines for SMB named pipe packet dissection * Copyright 1999, Richard Sharpe * significant rewrite to tvbuffify the dissector, Ronnie Sahlberg and * Guy Harris 2001 * * $Id: packet-smb-pipe.c,v 1.24 2001/08/05 01:15:26 guy Exp $ * * Ethereal - Network traffic analyzer * By Gerald Combs * Copyright 1998 Gerald Combs * * Copied from packet-pop.c * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #ifdef HAVE_CONFIG_H # include "config.h" #endif #include #ifdef HAVE_SYS_TYPES_H # include #endif #ifdef HAVE_NETINET_IN_H # include #endif #include #include #include #include #include "packet.h" #include "conversation.h" #include "smb.h" #include "packet-smb-pipe.h" #include "packet-smb-browse.h" static int proto_smb_lanman = -1; static int hf_function_code = -1; static int hf_param_desc = -1; static int hf_return_desc = -1; static int hf_not_implemented = -1; static int hf_detail_level = -1; static int hf_recv_buf_len = -1; static int hf_response_to = -1; static int hf_status = -1; static int hf_convert = -1; static int hf_ecount = -1; static int hf_acount = -1; static int hf_share_name = -1; static int hf_share_type = -1; static int hf_share_comment = -1; static int hf_share_permissions = -1; static int hf_share_max_uses = -1; static int hf_share_current_uses = -1; static int hf_server_name = -1; static int hf_server_major = -1; static int hf_server_minor = -1; static int hf_server_comment = -1; static int hf_abytes = -1; static int hf_current_time = -1; static int hf_msecs = -1; static int hf_hour = -1; static int hf_minute = -1; static int hf_second = -1; static int hf_hundredths = -1; static int hf_tzoffset = -1; static int hf_timeinterval = -1; static int hf_day = -1; static int hf_month = -1; static int hf_year = -1; static int hf_weekday = -1; static int hf_computer_name = -1; static int hf_user_name = -1; static int hf_workstation_domain = -1; static int hf_workstation_major = -1; static int hf_workstation_minor = -1; static int hf_logon_domain = -1; static int hf_other_domains = -1; static int hf_password = -1; static int hf_workstation_name = -1; static int hf_ustruct_size = -1; static int hf_logon_code = -1; static int hf_privilege_level = -1; static int hf_operator_privileges = -1; static int hf_num_logons = -1; static int hf_bad_pw_count = -1; static int hf_last_logon = -1; static int hf_last_logoff = -1; static int hf_logoff_time = -1; static int hf_kickoff_time = -1; static int hf_password_age = -1; static int hf_password_can_change = -1; static int hf_password_must_change = -1; static int hf_script_path = -1; static int hf_logoff_code = -1; static int hf_duration = -1; static int hf_user_comment = -1; static int hf_full_name = -1; static int hf_homedir = -1; static int hf_parameters = -1; static int hf_logon_server = -1; static int hf_country_code = -1; static int hf_workstations = -1; static int hf_max_storage = -1; static int hf_units_per_week = -1; static int hf_logon_hours = -1; static int hf_code_page = -1; static int hf_new_password = -1; static int hf_old_password = -1; static gint ett_lanman = -1; static gint ett_lanman_servers = -1; static gint ett_lanman_server = -1; static gint ett_lanman_shares = -1; static gint ett_lanman_share = -1; /* * See * * ftp://ftp.microsoft.com/developr/drg/CIFS/cifsrap2.txt * * among other documents. */ static const value_string status_vals[] = { {0, "Success"}, {5, "User has insufficient privilege"}, {65, "Network access is denied"}, {86, "The specified password is invalid"}, {SMBE_moredata, "Additional data is available"}, {2114, "Service is not running on the remote computer"}, {2123, "Supplied buffer is too small"}, {2141, "Server is not configured for transactions (IPC$ not shared)"}, {2212, "An error occurred while loading or running the logon script"}, {2214, "The logon was not validated by any server"}, {2217, "The logon server is running an older software version"}, {2221, "The user name was not found"}, {2240, "The user is not allowed to logon from this computer"}, {2241, "The user is not allowed to logon at this time"}, {2242, "The user password has expired"}, {2243, "The password cannot be changed"}, {2246, "The password is too short"}, {0, NULL} }; static const value_string share_type_vals[] = { {0, "Directory tree"}, {1, "Printer queue"}, {2, "Communications device"}, {3, "IPC"}, {0, NULL} }; static const value_string privilege_vals[] = { {0, "Guest"}, {1, "User"}, {2, "Administrator"}, {0, NULL} }; static const value_string op_privilege_vals[] = { {0, "Print operator"}, {1, "Communications operator"}, {2, "Server operator"}, {3, "Accounts operator"}, {0, NULL} }; static const value_string weekday_vals[] = { {0, "Sunday"}, {1, "Monday"}, {2, "Tuesday"}, {3, "Wednesday"}, {4, "Thursday"}, {5, "Friday"}, {6, "Saturday"}, {0, NULL} }; static int not_implemented(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int offset) { proto_tree_add_item(tree, hf_not_implemented, tvb, offset, tvb_length_remaining(tvb, offset), TRUE); return offset+tvb_length_remaining(tvb,offset); } static int add_string_pointer(tvbuff_t *tvb, proto_tree *tree, int offset, int convert, int hf_index) { int cptr; gint string_len; /* pointer to string */ cptr = (tvb_get_letohl(tvb, offset)&0xffff)-convert; offset += 4; /* string */ if (tvb_offset_exists(tvb, cptr) && (string_len = tvb_strnlen(tvb, cptr, -1)) != -1) { proto_tree_add_item(tree, hf_index, tvb, cptr, string_len + 1, TRUE); } else { proto_tree_add_text(tree, tvb, 0, 0, "%s: ", proto_registrar_get_name(hf_index)); } return offset; } static int add_byte_array_pointer(tvbuff_t *tvb, proto_tree *tree, int offset, int len, int convert, int hf_index) { int cptr; /* pointer to string */ cptr = (tvb_get_letohl(tvb, offset)&0xffff)-convert; offset += 4; /* string */ proto_tree_add_item(tree, hf_index, tvb, cptr, len, TRUE); return offset; } /* * Sigh. This is for handling Microsoft's annoying almost-UNIX-time-but- * it's-local-time-not-UTC time. */ static time_t localtime_to_utc(time_t local) { struct tm *tmp; /* * Run it through "gmtime()" to break it down, and then run it * through "mktime()" to put it back together as UTC. */ tmp = gmtime(&local); tmp->tm_isdst = -1; /* we don't know if it's DST or not */ return mktime(tmp); } static int netshareenum_request(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, struct smb_request_val *request_val, int offset) { /* detail level */ proto_tree_add_item(tree, hf_detail_level, tvb, offset, 2, TRUE); offset += 2; /* receiver buffer length */ proto_tree_add_item(tree, hf_recv_buf_len, tvb, offset, 2, TRUE); offset += 2; return offset; } static int netshareenum_response(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, struct smb_request_val *request_val, int offset, guint16 status, int convert) { struct smb_info *smb_info = pinfo->private; proto_item *it = NULL; proto_tree *tr = NULL; guint16 acount, ecount; int i; /* entry count */ ecount = tvb_get_letohs(tvb, offset); proto_tree_add_uint(tree, hf_ecount, tvb, offset, 2, ecount); offset += 2; /* available count */ acount = tvb_get_letohs(tvb, offset); proto_tree_add_uint(tree, hf_acount, tvb, offset, 2, acount); offset += 2; if (status != 0 && status != SMBE_moredata) return offset; /* The rest is in the data section. */ offset = smb_info->data_offset; /* create a subtree for all available shares */ if (tree) { it = proto_tree_add_text(tree, tvb, offset, tvb_length_remaining(tvb, offset), "Available Shares"); tr = proto_item_add_subtree(it, ett_lanman_shares); } for (i = 0; i < ecount; i++){ proto_item *si = NULL; proto_tree *st = NULL; char *share; int start_offset = offset; share = (char *)tvb_get_ptr(tvb, offset, 13); if (tree) { si = proto_tree_add_text(tr, tvb, offset, tvb_length_remaining(tvb, offset), "Share %s", share); st = proto_item_add_subtree(si, ett_lanman_shares); } /* share name */ proto_tree_add_item(st, hf_share_name, tvb, offset, 13, TRUE); offset += 13; /* pad byte */ offset += 1; /* share type */ proto_tree_add_item(st, hf_share_type, tvb, offset, 2, TRUE); offset += 2; /* share comment */ offset = add_string_pointer(tvb, st, offset, convert, hf_share_comment); proto_item_set_len(si, offset-start_offset); } return offset; } static int netsharegetinfo_request(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, struct smb_request_val *request_val, int offset) { guint share_name_len; guint16 level; /* share name */ share_name_len = tvb_strsize(tvb, offset); proto_tree_add_item(tree, hf_share_name, tvb, offset, share_name_len, TRUE); offset += share_name_len; /* detail level */ level = tvb_get_letohs(tvb, offset); request_val->last_level = level; /* remember this for the response */ proto_tree_add_uint(tree, hf_detail_level, tvb, offset, 2, level); offset += 2; /* receiver buffer length */ proto_tree_add_item(tree, hf_recv_buf_len, tvb, offset, 2, TRUE); offset += 2; return offset; } static int netsharegetinfo_response(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, struct smb_request_val *request_val, int offset, guint16 status, int convert) { struct smb_info *smb_info = pinfo->private; guint16 abytes; guint16 permissions; guint16 max_uses; /* available bytes */ abytes = tvb_get_letohs(tvb, offset); proto_tree_add_uint(tree, hf_abytes, tvb, offset, 2, abytes); offset += 2; if (status != 0 && status != SMBE_moredata) return offset; /* XXX - what is this field? */ proto_tree_add_text(tree, tvb, offset, 2, "Mysterious field: %04x", tvb_get_letohs(tvb, offset)); offset += 2; /* The rest is in the data section. */ offset = smb_info->data_offset; /* share name */ proto_tree_add_item(tree, hf_share_name, tvb, offset, 13, TRUE); offset += 13; if (request_val->last_level == 0) return offset; /* that's it, at level 0 */ /* pad byte */ offset += 1; /* share type */ proto_tree_add_item(tree, hf_share_type, tvb, offset, 2, TRUE); offset += 2; /* share comment */ offset = add_string_pointer(tvb, tree, offset, convert, hf_share_comment); if (request_val->last_level == 1) return offset; /* that's it, at level 1 */ /* share permissions */ /* XXX - do as bit fields */ permissions = tvb_get_letohs(tvb, offset); proto_tree_add_uint(tree, hf_share_permissions, tvb, offset, 2, permissions); offset += 2; /* max uses */ max_uses = tvb_get_letohs(tvb, offset); if (max_uses == 0xffff) { /* -1 */ proto_tree_add_uint_format(tree, hf_share_max_uses, tvb, offset, 2, max_uses, "Share Max Uses: No limit"); } else { proto_tree_add_uint(tree, hf_share_max_uses, tvb, offset, 2, max_uses); } offset += 2; /* current uses */ max_uses = tvb_get_letohs(tvb, offset); proto_tree_add_item(tree, hf_share_current_uses, tvb, offset, 2, TRUE); offset += 2; return offset; } static int add_server_info(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int offset, int convert, guint16 level) { /* server name */ proto_tree_add_item(tree, hf_server_name, tvb, offset, 16, TRUE); offset += 16; if (level) { /* major version */ proto_tree_add_item(tree, hf_server_major, tvb, offset, 1, TRUE); offset += 1; /* minor version */ proto_tree_add_item(tree, hf_server_minor, tvb, offset, 1, TRUE); offset += 1; /* server type flags */ dissect_smb_server_type_flags(tvb, pinfo, tree, offset, FALSE); offset += 4; /* server comment */ offset = add_string_pointer(tvb, tree, offset, convert, hf_server_comment); } return offset; } static int netservergetinfo_request(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, struct smb_request_val *request_val, int offset) { guint16 level; /* detail level */ level = tvb_get_letohs(tvb, offset); request_val->last_level = level; /* remember this for the response */ proto_tree_add_uint(tree, hf_detail_level, tvb, offset, 2, level); offset += 2; /* receiver buffer length */ proto_tree_add_item(tree, hf_recv_buf_len, tvb, offset, 2, TRUE); offset += 2; return offset; } static int netservergetinfo_response(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, struct smb_request_val *request_val, int offset, guint16 status, int convert) { struct smb_info *smb_info = pinfo->private; guint16 abytes; /* available bytes */ abytes = tvb_get_letohs(tvb, offset); proto_tree_add_uint(tree, hf_abytes, tvb, offset, 2, abytes); offset += 2; /* XXX - what is this field? */ proto_tree_add_text(tree, tvb, offset, 2, "Mysterious field: %04x", tvb_get_letohs(tvb, offset)); offset += 2; if (status != 0 && status != SMBE_moredata) return offset; /* The rest is in the data section. */ offset = smb_info->data_offset; offset = add_server_info(tvb, pinfo, tree, offset, convert, request_val->last_level); return offset; } static int netusergetinfo_request(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, struct smb_request_val *request_val, int offset) { guint16 level; /* detail level */ level = tvb_get_letohs(tvb, offset); request_val->last_level = level; /* remember this for the response */ proto_tree_add_uint(tree, hf_detail_level, tvb, offset, 2, level); offset += 2; /* receiver buffer length */ proto_tree_add_item(tree, hf_recv_buf_len, tvb, offset, 2, TRUE); offset += 2; return offset; } static int netusergetinfo_response(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, struct smb_request_val *request_val, int offset, guint16 status, int convert) { struct smb_info *smb_info = pinfo->private; guint16 abytes; struct timeval timeval; guint16 nlogons; guint32 max_storage; /* available bytes */ abytes = tvb_get_letohs(tvb, offset); proto_tree_add_uint(tree, hf_abytes, tvb, offset, 2, abytes); offset += 2; /* XXX - what is this field? */ proto_tree_add_text(tree, tvb, offset, 2, "Mysterious field: %04x", tvb_get_letohs(tvb, offset)); offset += 2; if (status != 0 && status != SMBE_moredata) return offset; /* The rest is in the data section. */ offset = smb_info->data_offset; /* user name */ proto_tree_add_item(tree, hf_user_name, tvb, offset, 21, TRUE); offset += 21; /* pad1 */ offset += 1; /* user comment */ offset = add_string_pointer(tvb, tree, offset, convert, hf_user_comment); /* full name */ offset = add_string_pointer(tvb, tree, offset, convert, hf_full_name); /* privilege level */ proto_tree_add_item(tree, hf_privilege_level, tvb, offset, 2, TRUE); offset += 2; /* operator privileges */ proto_tree_add_item(tree, hf_operator_privileges, tvb, offset, 4, TRUE); offset += 4; /* password age */ timeval.tv_sec = tvb_get_letohl(tvb, offset); proto_tree_add_time_format(tree, hf_password_age, tvb, offset, 4, &timeval, "Password Age: %s", time_secs_to_str(timeval.tv_sec)); offset += 4; /* home directory */ offset = add_string_pointer(tvb, tree, offset, convert, hf_homedir); /* parameters */ offset = add_string_pointer(tvb, tree, offset, convert, hf_parameters); timeval.tv_usec = 0; /* last logon time */ timeval.tv_sec = tvb_get_letohl(tvb, offset); if (timeval.tv_sec == -1) { proto_tree_add_time_format(tree, hf_last_logon, tvb, offset, 4, &timeval, "Last Logon Date/Time: Unknown"); } else { timeval.tv_sec = localtime_to_utc(timeval.tv_sec); proto_tree_add_time(tree, hf_last_logon, tvb, offset, 4, &timeval); } offset += 4; /* last logoff time */ timeval.tv_sec = tvb_get_letohl(tvb, offset); if (timeval.tv_sec == -1) { proto_tree_add_time_format(tree, hf_last_logoff, tvb, offset, 4, &timeval, "Last Logoff Date/Time: Unknown"); } else { timeval.tv_sec = localtime_to_utc(timeval.tv_sec); proto_tree_add_time(tree, hf_last_logoff, tvb, offset, 4, &timeval); } offset += 4; /* bad password count */ proto_tree_add_item(tree, hf_bad_pw_count, tvb, offset, 2, TRUE); offset += 2; /* number of logons */ nlogons = tvb_get_letohs(tvb, offset); if (nlogons == 0xffff) /* -1 */ proto_tree_add_uint_format(tree, hf_num_logons, tvb, offset, 2, nlogons, "Number of Logons: Unknown"); else proto_tree_add_uint(tree, hf_num_logons, tvb, offset, 2, nlogons); offset += 2; /* logon server */ offset = add_string_pointer(tvb, tree, offset, convert, hf_logon_server); /* country code */ /* XXX - we should have a value_string table for these */ proto_tree_add_item(tree, hf_country_code, tvb, offset, 2, TRUE); offset += 2; /* workstations */ offset = add_string_pointer(tvb, tree, offset, convert, hf_workstations); /* max storage */ max_storage = tvb_get_letohl(tvb, offset); if (nlogons == 0xffffffff) proto_tree_add_uint_format(tree, hf_max_storage, tvb, offset, 4, max_storage, "Max Storage: No limit"); else proto_tree_add_uint(tree, hf_max_storage, tvb, offset, 4, max_storage); offset += 4; /* units per week */ proto_tree_add_item(tree, hf_units_per_week, tvb, offset, 2, TRUE); offset += 2; /* logon hours */ /* XXX - should actually carve up the bits */ /* XXX - how do we recognize a null pointer? */ offset = add_byte_array_pointer(tvb, tree, offset, 21, convert, hf_logon_hours); /* code page */ /* XXX - we should have a value_string table for these */ proto_tree_add_item(tree, hf_code_page, tvb, offset, 2, TRUE); offset += 2; return offset; } static int netremotetod_request(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, struct smb_request_val *request_val, int offset) { /* receiver buffer length */ proto_tree_add_item(tree, hf_recv_buf_len, tvb, offset, 2, TRUE); offset += 2; return offset; } static int netremotetod_response(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, struct smb_request_val *request_val, int offset, guint16 status, int convert) { struct timeval timeval; gint16 tzoffset; guint16 timeinterval; if (status != 0 && status != SMBE_moredata) return offset; /* current time */ timeval.tv_sec = tvb_get_letohl(tvb, offset); timeval.tv_sec = localtime_to_utc(timeval.tv_sec); timeval.tv_usec = 0; proto_tree_add_time(tree, hf_current_time, tvb, offset, 4, &timeval); offset += 4; /* msecs since arbitrary point in the past */ timeval.tv_usec = tvb_get_letohl(tvb, offset); offset += 4; /* hour */ proto_tree_add_item(tree, hf_hour, tvb, offset, 1, TRUE); offset += 1; /* minute */ proto_tree_add_item(tree, hf_minute, tvb, offset, 1, TRUE); offset += 1; /* second */ proto_tree_add_item(tree, hf_second, tvb, offset, 1, TRUE); offset += 1; /* hundredths-of-second */ proto_tree_add_item(tree, hf_hundredths, tvb, offset, 1, TRUE); offset += 1; /* time zone offset, in minutes */ tzoffset = tvb_get_letohs(tvb, offset); if (tzoffset < 0) { proto_tree_add_int_format(tree, hf_tzoffset, tvb, offset, 2, tzoffset, "Time Zone Offset: %s east of UTC", time_secs_to_str(-tzoffset*60)); } else if (tzoffset > 0) { proto_tree_add_int_format(tree, hf_tzoffset, tvb, offset, 2, tzoffset, "Time Zone Offset: %s west of UTC", time_secs_to_str(tzoffset*60)); } else { proto_tree_add_int_format(tree, hf_tzoffset, tvb, offset, 2, tzoffset, "Time Zone Offset: at UTC"); } offset += 2; /* timer resolution */ timeinterval = tvb_get_letohs(tvb, offset); proto_tree_add_uint_format(tree, hf_timeinterval, tvb, offset, 2, timeinterval, "Time Interval: %f seconds", timeinterval*.0001); offset += 2; /* day */ proto_tree_add_item(tree, hf_day, tvb, offset, 1, TRUE); offset += 1; /* month */ proto_tree_add_item(tree, hf_month, tvb, offset, 1, TRUE); offset += 1; /* year */ proto_tree_add_item(tree, hf_year, tvb, offset, 2, TRUE); offset += 2; /* day of week */ proto_tree_add_item(tree, hf_weekday, tvb, offset, 1, TRUE); offset += 1; return offset; } static int netserverenum2_request(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, struct smb_request_val *request_val, int offset) { guint16 level; /* detail level */ level = tvb_get_letohs(tvb, offset); request_val->last_level = level; /* remember this for the response */ proto_tree_add_uint(tree, hf_detail_level, tvb, offset, 2, level); offset += 2; /* receiver buffer length */ proto_tree_add_item(tree, hf_recv_buf_len, tvb, offset, 2, TRUE); offset += 2; /* server type flags */ dissect_smb_server_type_flags(tvb, pinfo, tree, offset, TRUE); offset += 4; return offset; } static int netserverenum2_response(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, struct smb_request_val *request_val, int offset, guint16 status, int convert) { struct smb_info *smb_info = pinfo->private; guint16 ecount, acount; proto_item *it = NULL; proto_tree *tr = NULL; int i; /* entry count */ ecount = tvb_get_letohs(tvb, offset); proto_tree_add_uint(tree, hf_ecount, tvb, offset, 2, ecount); offset += 2; /* available count */ acount = tvb_get_letohs(tvb, offset); proto_tree_add_uint(tree, hf_acount, tvb, offset, 2, acount); offset += 2; if (status != 0 && status != SMBE_moredata) return offset; /* The rest is in the data section. */ offset = smb_info->data_offset; if (tree) { it = proto_tree_add_text(tree, tvb, offset, tvb_length_remaining(tvb, offset), "Servers"); tr = proto_item_add_subtree(it, ett_lanman_servers); } for (i = 0; i < ecount; i++) { proto_item *si = NULL; proto_tree *st = NULL; char *server; int old_offset = offset; server = (char *)tvb_get_ptr(tvb, offset, 16); if (tree) { si = proto_tree_add_text(tr, tvb, offset, request_val->last_level ? 26 : 16, "Server %.16s", server); st = proto_item_add_subtree(si, ett_lanman_server); } offset = add_server_info(tvb, pinfo, st, offset, convert, request_val->last_level); proto_item_set_len(si, offset-old_offset); } return offset; } static int netwkstagetinfo_request(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, struct smb_request_val *request_val, int offset) { guint16 level; /* detail level */ level = tvb_get_letohs(tvb, offset); request_val->last_level = level; /* remember this for the response */ proto_tree_add_uint(tree, hf_detail_level, tvb, offset, 2, level); offset += 2; /* receiver buffer length */ proto_tree_add_item(tree, hf_recv_buf_len, tvb, offset, 2, TRUE); offset += 2; return offset; } static int netwkstagetinfo_response(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, struct smb_request_val *request_val, int offset, guint16 status, int convert) { struct smb_info *smb_info = pinfo->private; guint16 abytes; /* available bytes */ abytes = tvb_get_letohs(tvb, offset); proto_tree_add_uint(tree, hf_abytes, tvb, offset, 2, abytes); offset += 2; /* XXX - what is this field? */ proto_tree_add_text(tree, tvb, offset, 2, "Mysterious field: %04x", tvb_get_letohs(tvb, offset)); offset += 2; if (status != 0 && status != SMBE_moredata) return offset; /* The rest is in the data section. */ offset = smb_info->data_offset; /* computer name */ offset = add_string_pointer(tvb, tree, offset, convert, hf_computer_name); /* user name */ offset = add_string_pointer(tvb, tree, offset, convert, hf_user_name); /* workstation domain */ offset = add_string_pointer(tvb, tree, offset, convert, hf_workstation_domain); /* major version */ proto_tree_add_item(tree, hf_workstation_major, tvb, offset, 1, TRUE); offset += 1; /* minor version */ proto_tree_add_item(tree, hf_workstation_minor, tvb, offset, 1, TRUE); offset += 1; /* logon domain */ offset = add_string_pointer(tvb, tree, offset, convert, hf_logon_domain); /* other domains */ offset = add_string_pointer(tvb, tree, offset, convert, hf_other_domains); return offset; } static int netwkstauserlogon_request(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, struct smb_request_val *request_val, int offset) { guint16 level; /* detail level */ level = tvb_get_letohs(tvb, offset); request_val->last_level = level; /* remember this for the response */ proto_tree_add_uint(tree, hf_detail_level, tvb, offset, 2, level); offset += 2; /* user name */ proto_tree_add_item(tree, hf_user_name, tvb, offset, 21, TRUE); offset += 21; /* pad1 */ offset += 1; /* password */ proto_tree_add_item(tree, hf_password, tvb, offset, 15, TRUE); offset += 15; /* pad2 */ offset += 1; /* workstation name */ proto_tree_add_item(tree, hf_workstation_name, tvb, offset, 16, TRUE); offset += 16; /* size of the above */ proto_tree_add_item(tree, hf_ustruct_size, tvb, offset, 2, TRUE); offset += 2; /* receiver buffer length */ proto_tree_add_item(tree, hf_recv_buf_len, tvb, offset, 2, TRUE); offset += 2; return offset; } static int netwkstauserlogon_response(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, struct smb_request_val *request_val, int offset, guint16 status, int convert) { struct smb_info *smb_info = pinfo->private; guint16 abytes; guint16 nlogons; struct timeval timeval; /* available bytes */ abytes = tvb_get_letohs(tvb, offset); proto_tree_add_uint(tree, hf_abytes, tvb, offset, 2, abytes); offset += 2; /* XXX - what is this field? */ proto_tree_add_text(tree, tvb, offset, 2, "Mysterious field: %04x", tvb_get_letohs(tvb, offset)); offset += 2; if (status != 0 && status != SMBE_moredata) return offset; /* The rest is in the data section. */ offset = smb_info->data_offset; /* logon code */ proto_tree_add_item(tree, hf_logon_code, tvb, offset, 2, TRUE); offset += 2; /* user name */ proto_tree_add_item(tree, hf_user_name, tvb, offset, 21, TRUE); offset += 21; /* pad1 */ offset += 1; /* privilege level */ proto_tree_add_item(tree, hf_privilege_level, tvb, offset, 2, TRUE); offset += 2; /* operator privileges */ proto_tree_add_item(tree, hf_operator_privileges, tvb, offset, 4, TRUE); offset += 4; /* number of logons */ nlogons = tvb_get_letohs(tvb, offset); if (nlogons == 0xffff) /* -1 */ proto_tree_add_uint_format(tree, hf_num_logons, tvb, offset, 2, nlogons, "Number of Logons: Unknown"); else proto_tree_add_uint(tree, hf_num_logons, tvb, offset, 2, nlogons); offset += 2; /* bad password count */ proto_tree_add_item(tree, hf_bad_pw_count, tvb, offset, 2, TRUE); offset += 2; timeval.tv_usec = 0; /* last logon time */ timeval.tv_sec = tvb_get_letohl(tvb, offset); if (timeval.tv_sec == -1) { proto_tree_add_time_format(tree, hf_last_logon, tvb, offset, 4, &timeval, "Last Logon Date/Time: Unknown"); } else { timeval.tv_sec = localtime_to_utc(timeval.tv_sec); proto_tree_add_time(tree, hf_last_logon, tvb, offset, 4, &timeval); } offset += 4; /* last logoff time */ timeval.tv_sec = tvb_get_letohl(tvb, offset); if (timeval.tv_sec == -1) { proto_tree_add_time_format(tree, hf_last_logoff, tvb, offset, 4, &timeval, "Last Logoff Date/Time: Unknown"); } else { timeval.tv_sec = localtime_to_utc(timeval.tv_sec); proto_tree_add_time(tree, hf_last_logoff, tvb, offset, 4, &timeval); } offset += 4; /* logoff time */ timeval.tv_sec = tvb_get_letohl(tvb, offset); if (timeval.tv_sec == -1) { proto_tree_add_time_format(tree, hf_logoff_time, tvb, offset, 4, &timeval, "Logoff Date/Time: None"); } else { timeval.tv_sec = localtime_to_utc(timeval.tv_sec); proto_tree_add_time(tree, hf_logoff_time, tvb, offset, 4, &timeval); } offset += 4; /* kickoff time */ timeval.tv_sec = tvb_get_letohl(tvb, offset); if (timeval.tv_sec == -1) { proto_tree_add_time_format(tree, hf_kickoff_time, tvb, offset, 4, &timeval, "Kickoff Date/Time: None"); } else { timeval.tv_sec = localtime_to_utc(timeval.tv_sec); proto_tree_add_time(tree, hf_kickoff_time, tvb, offset, 4, &timeval); } offset += 4; /* password age */ timeval.tv_sec = tvb_get_letohl(tvb, offset); proto_tree_add_time_format(tree, hf_password_age, tvb, offset, 4, &timeval, "Password Age: %s", time_secs_to_str(timeval.tv_sec)); offset += 4; /* date/time when password can change */ timeval.tv_sec = tvb_get_letohl(tvb, offset); if (timeval.tv_sec == -1) { proto_tree_add_time_format(tree, hf_password_can_change, tvb, offset, 4, &timeval, "Password Can Change: Never"); } else { timeval.tv_sec = localtime_to_utc(timeval.tv_sec); proto_tree_add_time(tree, hf_password_can_change, tvb, offset, 4, &timeval); } offset += 4; /* date/time when password must change */ timeval.tv_sec = tvb_get_letohl(tvb, offset); if (timeval.tv_sec == -1) { proto_tree_add_time_format(tree, hf_password_must_change, tvb, offset, 4, &timeval, "Password Must Change: Never"); } else { timeval.tv_sec = localtime_to_utc(timeval.tv_sec); proto_tree_add_time(tree, hf_password_must_change, tvb, offset, 4, &timeval); } offset += 4; /* computer where user is logged on */ offset = add_string_pointer(tvb, tree, offset, convert, hf_server_name); /* domain in which user is logged on */ offset = add_string_pointer(tvb, tree, offset, convert, hf_logon_domain); /* pathname of user's login script */ offset = add_string_pointer(tvb, tree, offset, convert, hf_script_path); /* reserved */ proto_tree_add_text(tree, tvb, offset, 4, "Reserved: %08x", tvb_get_letohl(tvb, offset)); offset += 4; return offset; } static int netwkstauserlogoff_request(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, struct smb_request_val *request_val, int offset) { /* user name */ proto_tree_add_item(tree, hf_user_name, tvb, offset, 21, TRUE); offset += 21; /* pad1 */ offset += 1; /* workstation name */ proto_tree_add_item(tree, hf_workstation_name, tvb, offset, 16, TRUE); offset += 16; return offset; } static int netwkstauserlogoff_response(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, struct smb_request_val *request_val, int offset, guint16 status, int convert) { struct smb_info *smb_info = pinfo->private; guint16 abytes; guint16 nlogons; struct timeval timeval; /* available bytes */ abytes = tvb_get_letohs(tvb, offset); proto_tree_add_uint(tree, hf_abytes, tvb, offset, 2, abytes); offset += 2; /* XXX - what is this field? */ proto_tree_add_text(tree, tvb, offset, 2, "Mysterious field: %04x", tvb_get_letohs(tvb, offset)); offset += 2; if (status != 0 && status != SMBE_moredata) return offset; /* The rest is in the data section. */ offset = smb_info->data_offset; /* logoff code */ proto_tree_add_item(tree, hf_logoff_code, tvb, offset, 2, TRUE); offset += 2; /* duration */ timeval.tv_sec = tvb_get_letohl(tvb, offset); timeval.tv_usec = 0; proto_tree_add_time_format(tree, hf_duration, tvb, offset, 4, &timeval, "Duration of Session: %s", time_secs_to_str(timeval.tv_sec)); offset += 4; /* number of logons */ nlogons = tvb_get_letohs(tvb, offset); if (nlogons == 0xffff) /* -1 */ proto_tree_add_uint_format(tree, hf_num_logons, tvb, offset, 2, nlogons, "Number of Logons: Unknown"); else proto_tree_add_uint(tree, hf_num_logons, tvb, offset, 2, nlogons); offset += 2; return offset; } static int samoemchangepassword_request(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, struct smb_request_val *request_val, int offset) { struct smb_info *smb_info = pinfo->private; guint user_name_len; /* user name */ user_name_len = tvb_strsize(tvb, offset); proto_tree_add_item(tree, hf_user_name, tvb, offset, user_name_len, TRUE); offset += user_name_len; /* new password */ proto_tree_add_item(tree, hf_new_password, tvb, smb_info->data_offset, 516, TRUE); /* old password */ proto_tree_add_item(tree, hf_old_password, tvb, smb_info->data_offset + 516, 16, TRUE); return offset; } static int samoemchangepassword_response(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, struct smb_request_val *request_val, int offset, guint16 status, int convert) { /* nothing in this reply */ return offset; } #define LANMAN_NETSHAREENUM 0 #define LANMAN_NETSHAREGETINFO 1 #define LANMAN_NETSERVERGETINFO 13 #define LANMAN_NETGROUPGETUSERS 52 #define LANMAN_NETUSERGETINFO 56 #define LANMAN_NETUSERGETGROUPS 59 #define LANMAN_NETWKSTAGETINFO 63 #define LANMAN_DOSPRINTQENUM 69 #define LANMAN_DOSPRINTQGETINFO 70 #define LANMAN_WPRINTQUEUEPAUSE 74 #define LANMAN_WPRINTQUEUERESUME 75 #define LANMAN_WPRINTJOBENUMERATE 76 #define LANMAN_WPRINTJOBGETINFO 77 #define LANMAN_RDOSPRINTJOBDEL 81 #define LANMAN_RDOSPRINTJOBPAUSE 82 #define LANMAN_RDOSPRINTJOBRESUME 83 #define LANMAN_WPRINTDESTENUM 84 #define LANMAN_WPRINTDESTGETINFO 85 #define LANMAN_NETREMOTETOD 91 #define LANMAN_WPRINTQUEUEPURGE 103 #define LANMAN_NETSERVERENUM2 104 #define LANMAN_WACCESSGETUSERPERMS 105 #define LANMAN_SETUSERPASSWORD 115 #define LANMAN_NETWKSTAUSERLOGON 132 #define LANMAN_NETWKSTAUSERLOGOFF 133 #define LANMAN_PRINTJOBINFO 147 #define LANMAN_WPRINTDRIVERENUM 205 #define LANMAN_WPRINTQPROCENUM 206 #define LANMAN_WPRINTPORTENUM 207 #define LANMAN_SAMOEMCHANGEPASSWORD 214 static const value_string commands[] = { {LANMAN_NETSHAREENUM, "NetShareEnum"}, {LANMAN_NETSHAREGETINFO, "NetShareGetInfo"}, {LANMAN_NETSERVERGETINFO, "NetServerGetInfo"}, {LANMAN_NETGROUPGETUSERS, "NetGroupGetUsers"}, {LANMAN_NETUSERGETINFO, "NetUserGetInfo"}, {LANMAN_NETUSERGETGROUPS, "NetUserGetGroups"}, {LANMAN_NETWKSTAGETINFO, "NetWkstaGetInfo"}, {LANMAN_DOSPRINTQENUM, "DOSPrintQEnum"}, {LANMAN_DOSPRINTQGETINFO, "DOSPrintQGetInfo"}, {LANMAN_WPRINTQUEUEPAUSE, "WPrintQueuePause"}, {LANMAN_WPRINTQUEUERESUME, "WPrintQueueResume"}, {LANMAN_WPRINTJOBENUMERATE, "WPrintJobEnumerate"}, {LANMAN_WPRINTJOBGETINFO, "WPrintJobGetInfo"}, {LANMAN_RDOSPRINTJOBDEL, "RDOSPrintJobDel"}, {LANMAN_RDOSPRINTJOBPAUSE, "RDOSPrintJobPause"}, {LANMAN_RDOSPRINTJOBRESUME, "RDOSPrintJobResume"}, {LANMAN_WPRINTDESTENUM, "WPrintDestEnum"}, {LANMAN_WPRINTDESTGETINFO, "WPrintDestGetInfo"}, {LANMAN_NETREMOTETOD, "NetRemoteTOD"}, {LANMAN_WPRINTQUEUEPURGE, "WPrintQueuePurge"}, {LANMAN_NETSERVERENUM2, "NetServerEnum2"}, {LANMAN_WACCESSGETUSERPERMS, "WAccessGetUserPerms"}, {LANMAN_SETUSERPASSWORD, "SetUserPassword"}, {LANMAN_NETWKSTAUSERLOGON, "NetWkstaUserLogon"}, {LANMAN_NETWKSTAUSERLOGOFF, "NetWkstaUserLogoff"}, {LANMAN_PRINTJOBINFO, "PrintJobInfo"}, {LANMAN_WPRINTDRIVERENUM, "WPrintDriverEnum"}, {LANMAN_WPRINTQPROCENUM, "WPrintQProcEnum"}, {LANMAN_WPRINTPORTENUM, "WPrintPortEnum"}, {LANMAN_SAMOEMCHANGEPASSWORD, "SamOEMChangePassword"}, {0, NULL} }; struct lanman_dissector { int command; int (*request)(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, struct smb_request_val *request_val, int offset); int (*response)(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, struct smb_request_val *request_val, int offset, guint16 status, int convert); }; struct lanman_dissector lmd[] = { { LANMAN_NETSHAREENUM, netshareenum_request, netshareenum_response }, { LANMAN_NETSHAREGETINFO, netsharegetinfo_request, netsharegetinfo_response }, { LANMAN_NETSERVERGETINFO, netservergetinfo_request, netservergetinfo_response }, { LANMAN_NETUSERGETINFO, netusergetinfo_request, netusergetinfo_response }, { LANMAN_NETREMOTETOD, netremotetod_request, netremotetod_response }, { LANMAN_NETSERVERENUM2, netserverenum2_request, netserverenum2_response }, { LANMAN_NETWKSTAGETINFO, netwkstagetinfo_request, netwkstagetinfo_response }, { LANMAN_NETWKSTAUSERLOGON, netwkstauserlogon_request, netwkstauserlogon_response }, { LANMAN_NETWKSTAUSERLOGOFF, netwkstauserlogoff_request, netwkstauserlogoff_response }, { LANMAN_SAMOEMCHANGEPASSWORD, samoemchangepassword_request, samoemchangepassword_response }, { -1, NULL, NULL } }; struct lanman_dissector *find_lanman_dissector(int cmd) { int i; for (i = 0; lmd[i].command != -1; i++) { if (lmd[i].command == cmd) return &lmd[i]; } return NULL; } static gboolean dissect_pipe_lanman(tvbuff_t *tvb, packet_info *pinfo, proto_tree *parent_tree) { struct smb_info *smb_info = pinfo->private; struct smb_request_val *request_val = smb_info->request_val; int offset = 0; guint16 cmd; guint16 status; int convert; proto_item *item = NULL; proto_tree *tree = NULL; struct lanman_dissector *dis; guint param_descriptor_len, return_descriptor_len; if (check_col(pinfo->fd, COL_PROTOCOL)) { col_set_str(pinfo->fd, COL_PROTOCOL, "LANMAN"); } if (parent_tree) { item = proto_tree_add_item(parent_tree, proto_smb_lanman, tvb, 0, tvb_length(tvb), FALSE); tree = proto_item_add_subtree(item, ett_lanman); } /* continuation messages, dont try to decode them */ if (smb_info->ddisp) { if (check_col(pinfo->fd, COL_INFO)) { col_set_str(pinfo->fd, COL_INFO, "Transact Continuation"); } return TRUE; } if (smb_info->request) { /* this is a request */ /* function code */ cmd = tvb_get_letohs(tvb, offset); if (check_col(pinfo->fd, COL_INFO)) { col_add_fstr(pinfo->fd, COL_INFO, "%s Request", val_to_str(cmd, commands, "Unknown Command:0x%02x")); } proto_tree_add_uint(tree, hf_function_code, tvb, offset, 2, cmd); offset += 2; /* * If we haven't already done so, save the function code in * the structure we were handed, so that it's available to * the code parsing the reply. */ if (!pinfo->fd->flags.visited) request_val->last_lanman_cmd = cmd; /* parameter descriptor */ param_descriptor_len = tvb_strsize(tvb, offset); proto_tree_add_item(tree, hf_param_desc, tvb, offset, param_descriptor_len, TRUE); if (pinfo->fd->flags.visited) { /* * Save the parameter descriptor for future use. */ g_assert(request_val->last_param_descrip == NULL); request_val->last_param_descrip = g_malloc(param_descriptor_len); strcpy(request_val->last_param_descrip, tvb_get_ptr(tvb, offset, param_descriptor_len)); } offset += param_descriptor_len; /* return descriptor */ return_descriptor_len = tvb_strsize(tvb, offset); proto_tree_add_item(tree, hf_return_desc, tvb, offset, return_descriptor_len, TRUE); if (pinfo->fd->flags.visited) { /* * Save the return descriptor for future use. */ g_assert(request_val->last_data_descrip == NULL); request_val->last_data_descrip = g_malloc(return_descriptor_len); strcpy(request_val->last_data_descrip, tvb_get_ptr(tvb, offset, return_descriptor_len)); } offset += return_descriptor_len; /* command parameters */ dis = find_lanman_dissector(cmd); if (dis == NULL) { offset = not_implemented(tvb, pinfo, tree, offset); return FALSE; } offset = (*(dis->request))(tvb, pinfo, tree, request_val, offset); } else { /* * This is a response. * Have we seen the request to which it's a response? */ if (request_val == NULL) return FALSE; /* no - can't dissect it */ /* ok we have seen this one before */ /* response to the request in frame xx */ proto_tree_add_uint(tree, hf_response_to, tvb, 0, 0, request_val->frame); /* command */ if (check_col(pinfo->fd, COL_INFO)) { col_add_fstr(pinfo->fd, COL_INFO, "%s %sResponse", val_to_str(request_val->last_lanman_cmd, commands, "Unknown Command (0x%02x)"), smb_info->is_interim_response ? "Interim " : ""); } proto_tree_add_uint(tree, hf_function_code, tvb, 0, 0, request_val->last_lanman_cmd); if (smb_info->is_interim_response) return TRUE; /* no data to dissect */ /* command parameters */ /* status */ status = tvb_get_letohs(tvb, offset); proto_tree_add_uint(tree, hf_status, tvb, offset, 2, status); offset += 2; /* convert */ convert = tvb_get_letohs(tvb, offset); proto_tree_add_uint(tree, hf_convert, tvb, offset, 2, convert); offset += 2; /* * "convert" is relative to the beginning of the data * area, but we're handed a tvbuff that starts at the * beginning of the parameter area, so we need to * add "smb_info->data_offset" to offsets after * subtracting "convert"; subtract it from "convert" * so that it gets added in for free. */ convert -= smb_info->data_offset; dis = find_lanman_dissector(request_val->last_lanman_cmd); if (dis == NULL) { offset = not_implemented(tvb, pinfo, tree, offset); return FALSE; } offset = (*(dis->response))(tvb, pinfo, tree, request_val, offset, status, convert); } return TRUE; } gboolean dissect_pipe_smb(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, char *command) { if (!proto_is_protocol_enabled(proto_smb_lanman)) return FALSE; pinfo->current_proto = "LANMAN"; if (command != NULL && strcmp(command, "LANMAN") == 0) { /* Try to decode a LANMAN */ return dissect_pipe_lanman(tvb, pinfo, tree); } return FALSE; } void register_proto_smb_pipe(void) { static hf_register_info hf[] = { { &hf_function_code, { "Function Code", "lanman.function_code", FT_UINT16, BASE_DEC, VALS(commands), 0, "LANMAN Function Code/Command", HFILL }}, { &hf_param_desc, { "Parameter Descriptor", "lanman.param_desc", FT_STRING, BASE_NONE, NULL, 0, "LANMAN Parameter Descriptor", HFILL }}, { &hf_return_desc, { "Return Descriptor", "lanman.ret_desc", FT_STRING, BASE_NONE, NULL, 0, "LANMAN Return Descriptor", HFILL }}, { &hf_not_implemented, { "Unknown Data", "lanman.not_implemented", FT_BYTES, BASE_HEX, NULL, 0, "Decoding of this data is not implemented yet", HFILL }}, { &hf_detail_level, { "Detail Level", "lanman.level", FT_UINT16, BASE_DEC, NULL, 0, "LANMAN Detail Level", HFILL }}, { &hf_recv_buf_len, { "Receive Buffer Length", "lanman.recv_buf_len", FT_UINT16, BASE_DEC, NULL, 0, "LANMAN Receive Buffer Length", HFILL }}, { &hf_response_to, { "Response to request in frame", "lanman.response_to", FT_UINT32, BASE_DEC, NULL, 0, "This is a LANMAN response to the request in frame", HFILL }}, { &hf_status, { "Status", "lanman.status", FT_UINT16, BASE_DEC, VALS(status_vals), 0, "LANMAN Return status", HFILL }}, { &hf_convert, { "Convert", "lanman.convert", FT_UINT16, BASE_DEC, NULL, 0, "LANMAN Convert", HFILL }}, { &hf_ecount, { "Entry Count", "lanman.entry_count", FT_UINT16, BASE_DEC, NULL, 0, "LANMAN Number of Entries", HFILL }}, { &hf_acount, { "Available Entries", "lanman.available_count", FT_UINT16, BASE_DEC, NULL, 0, "LANMAN Number of Available Entries", HFILL }}, { &hf_share_name, { "Share Name", "lanman.share.name", FT_STRING, BASE_NONE, NULL, 0, "LANMAN Name of Share", HFILL }}, { &hf_share_type, { "Share Type", "lanman.share.type", FT_UINT16, BASE_DEC, VALS(share_type_vals), 0, "LANMAN Type of Share", HFILL }}, { &hf_share_comment, { "Share Comment", "lanman.share.comment", FT_STRING, BASE_NONE, NULL, 0, "LANMAN Share Comment", HFILL }}, { &hf_share_permissions, { "Share Permissions", "lanman.share.permissions", FT_UINT16, BASE_DEC, NULL, 0, "LANMAN Permissions on share", HFILL }}, { &hf_share_max_uses, { "Share Max Uses", "lanman.share.max_uses", FT_UINT16, BASE_DEC, NULL, 0, "LANMAN Max connections allowed to share", HFILL }}, { &hf_share_current_uses, { "Share Current Uses", "lanman.share.current_uses", FT_UINT16, BASE_DEC, NULL, 0, "LANMAN Current connections to share", HFILL }}, { &hf_server_name, { "Server Name", "lanman.server.name", FT_STRING, BASE_NONE, NULL, 0, "LANMAN Name of Server", HFILL }}, { &hf_server_major, { "Major Version", "lanman.server.major", FT_UINT8, BASE_DEC, NULL, 0, "LANMAN Server Major Version", HFILL }}, { &hf_server_minor, { "Minor Version", "lanman.server.minor", FT_UINT8, BASE_DEC, NULL, 0, "LANMAN Server Minor Version", HFILL }}, { &hf_server_comment, { "Server Comment", "lanman.server.comment", FT_STRING, BASE_NONE, NULL, 0, "LANMAN Server Comment", HFILL }}, { &hf_abytes, { "Available Bytes", "lanman.available_bytes", FT_UINT16, BASE_DEC, NULL, 0, "LANMAN Number of Available Bytes", HFILL }}, { &hf_current_time, { "Current Date/Time", "lanman.current_time", FT_ABSOLUTE_TIME, BASE_NONE, NULL, 0, "LANMAN Current date and time, in seconds since 00:00:00, January 1, 1970", HFILL }}, { &hf_msecs, { "Milliseconds", "lanman.msecs", FT_UINT32, BASE_DEC, NULL, 0, "LANMAN Milliseconds since arbitrary time in the past (typically boot time)", HFILL }}, { &hf_hour, { "Hour", "lanman.hour", FT_UINT8, BASE_DEC, NULL, 0, "LANMAN Current hour", HFILL }}, { &hf_minute, { "Minute", "lanman.minute", FT_UINT8, BASE_DEC, NULL, 0, "LANMAN Current minute", HFILL }}, { &hf_second, { "Second", "lanman.second", FT_UINT8, BASE_DEC, NULL, 0, "LANMAN Current second", HFILL }}, { &hf_hundredths, { "Hundredths of a second", "lanman.hundredths", FT_UINT8, BASE_DEC, NULL, 0, "LANMAN Current hundredths of a second", HFILL }}, { &hf_tzoffset, { "Time Zone Offset", "lanman.tzoffset", FT_INT16, BASE_DEC, NULL, 0, "LANMAN Offset of time zone from GMT, in minutes", HFILL }}, { &hf_timeinterval, { "Time Interval", "lanman.timeinterval", FT_UINT16, BASE_DEC, NULL, 0, "LANMAN .0001 second units per clock tick", HFILL }}, { &hf_day, { "Day", "lanman.day", FT_UINT8, BASE_DEC, NULL, 0, "LANMAN Current day", HFILL }}, { &hf_month, { "Month", "lanman.month", FT_UINT8, BASE_DEC, NULL, 0, "LANMAN Current month", HFILL }}, { &hf_year, { "Year", "lanman.year", FT_UINT16, BASE_DEC, NULL, 0, "LANMAN Current year", HFILL }}, { &hf_weekday, { "Weekday", "lanman.weekday", FT_UINT8, BASE_DEC, VALS(weekday_vals), 0, "LANMAN Current day of the week", HFILL }}, { &hf_computer_name, { "Computer Name", "lanman.computer_name", FT_STRING, BASE_NONE, NULL, 0, "LANMAN Computer Name", HFILL }}, { &hf_user_name, { "User Name", "lanman.user_name", FT_STRING, BASE_NONE, NULL, 0, "LANMAN User Name", HFILL }}, { &hf_workstation_domain, { "Workstation Domain", "lanman.workstation_domain", FT_STRING, BASE_NONE, NULL, 0, "LANMAN Workstation Domain", HFILL }}, { &hf_workstation_major, { "Workstation Major Version", "lanman.workstation_major", FT_UINT8, BASE_DEC, NULL, 0, "LANMAN Workstation Major Version", HFILL }}, { &hf_workstation_minor, { "Workstation Minor Version", "lanman.workstation_minor", FT_UINT8, BASE_DEC, NULL, 0, "LANMAN Workstation Minor Version", HFILL }}, { &hf_logon_domain, { "Logon Domain", "lanman.logon_domain", FT_STRING, BASE_NONE, NULL, 0, "LANMAN Logon Domain", HFILL }}, { &hf_other_domains, { "Other Domains", "lanman.other_domains", FT_STRING, BASE_NONE, NULL, 0, "LANMAN Other Domains", HFILL }}, { &hf_password, { "Password", "lanman.password", FT_STRING, BASE_NONE, NULL, 0, "LANMAN Password", HFILL }}, { &hf_workstation_name, { "Workstation Name", "lanman.workstation_name", FT_STRING, BASE_NONE, NULL, 0, "LANMAN Workstation Name", HFILL }}, { &hf_ustruct_size, { "Length of UStruct", "lanman.ustruct_size", FT_UINT16, BASE_DEC, NULL, 0, "LANMAN UStruct Length", HFILL }}, { &hf_logon_code, { "Logon Code", "lanman.logon_code", FT_UINT16, BASE_DEC, VALS(status_vals), 0, "LANMAN Logon Code", HFILL }}, { &hf_privilege_level, { "Privilege Level", "lanman.privilege_level", FT_UINT16, BASE_DEC, VALS(privilege_vals), 0, "LANMAN Privilege Level", HFILL }}, { &hf_operator_privileges, { "Operator Privileges", "lanman.operator_privileges", FT_UINT32, BASE_DEC, VALS(op_privilege_vals), 0, "LANMAN Operator Privileges", HFILL }}, { &hf_num_logons, { "Number of Logons", "lanman.num_logons", FT_UINT16, BASE_DEC, NULL, 0, "LANMAN Number of Logons", HFILL }}, { &hf_bad_pw_count, { "Bad Password Count", "lanman.bad_pw_count", FT_UINT16, BASE_DEC, NULL, 0, "LANMAN Number of incorrect passwords entered since last successful login", HFILL }}, { &hf_last_logon, { "Last Logon Date/Time", "lanman.last_logon", FT_ABSOLUTE_TIME, BASE_NONE, NULL, 0, "LANMAN Date and time of last logon", HFILL }}, { &hf_last_logoff, { "Last Logoff Date/Time", "lanman.last_logoff", FT_ABSOLUTE_TIME, BASE_NONE, NULL, 0, "LANMAN Date and time of last logoff", HFILL }}, { &hf_logoff_time, { "Logoff Date/Time", "lanman.logoff_time", FT_ABSOLUTE_TIME, BASE_NONE, NULL, 0, "LANMAN Date and time when user should log off", HFILL }}, { &hf_kickoff_time, { "Kickoff Date/Time", "lanman.kickoff_time", FT_ABSOLUTE_TIME, BASE_NONE, NULL, 0, "LANMAN Date and time when user will be logged off", HFILL }}, { &hf_password_age, { "Password Age", "lanman.password_age", FT_RELATIVE_TIME, BASE_NONE, NULL, 0, "LANMAN Time since user last changed his/her password", HFILL }}, { &hf_password_can_change, { "Password Can Change", "lanman.password_can_change", FT_ABSOLUTE_TIME, BASE_NONE, NULL, 0, "LANMAN Date and time when user can change their password", HFILL }}, { &hf_password_must_change, { "Password Must Change", "lanman.password_must_change", FT_ABSOLUTE_TIME, BASE_NONE, NULL, 0, "LANMAN Date and time when user must change their password", HFILL }}, { &hf_script_path, { "Script Path", "lanman.script_path", FT_STRING, BASE_NONE, NULL, 0, "LANMAN Pathname of user's logon script", HFILL }}, { &hf_logoff_code, { "Logoff Code", "lanman.logoff_code", FT_UINT16, BASE_DEC, VALS(status_vals), 0, "LANMAN Logoff Code", HFILL }}, { &hf_duration, { "Duration of Session", "lanman.duration", FT_RELATIVE_TIME, BASE_NONE, NULL, 0, "LANMAN Number of seconds the user was logged on", HFILL }}, { &hf_user_comment, { "User Comment", "lanman.user_comment", FT_STRING, BASE_NONE, NULL, 0, "LANMAN User Comment", HFILL }}, { &hf_full_name, { "Full Name", "lanman.full_name", FT_STRING, BASE_NONE, NULL, 0, "LANMAN Full Name", HFILL }}, { &hf_homedir, { "Home Directory", "lanman.homedir", FT_STRING, BASE_NONE, NULL, 0, "LANMAN Home Directory", HFILL }}, { &hf_parameters, { "Parameters", "lanman.parameters", FT_STRING, BASE_NONE, NULL, 0, "LANMAN Parameters", HFILL }}, { &hf_logon_server, { "Logon Server", "lanman.logon_server", FT_STRING, BASE_NONE, NULL, 0, "LANMAN Logon Server", HFILL }}, { &hf_country_code, { "Country Code", "lanman.country_code", FT_UINT16, BASE_DEC, NULL, 0, "LANMAN Country Code", HFILL }}, { &hf_workstations, { "Workstations", "lanman.workstations", FT_STRING, BASE_NONE, NULL, 0, "LANMAN Workstations", HFILL }}, { &hf_max_storage, { "Max Storage", "lanman.max_storage", FT_UINT32, BASE_DEC, NULL, 0, "LANMAN Max Storage", HFILL }}, { &hf_units_per_week, { "Units Per Week", "lanman.units_per_week", FT_UINT16, BASE_DEC, NULL, 0, "LANMAN Units Per Week", HFILL }}, { &hf_logon_hours, { "Logon Hours", "lanman.logon_hours", FT_BYTES, BASE_NONE, NULL, 0, "LANMAN Logon Hours", HFILL }}, { &hf_code_page, { "Code Page", "lanman.code_page", FT_UINT16, BASE_DEC, NULL, 0, "LANMAN Code Page", HFILL }}, { &hf_new_password, { "New Password", "lanman.new_password", FT_BYTES, BASE_HEX, NULL, 0, "LANMAN New Password (encrypted)", HFILL }}, { &hf_old_password, { "Old Password", "lanman.old_password", FT_BYTES, BASE_HEX, NULL, 0, "LANMAN Old Password (encrypted)", HFILL }}, }; static gint *ett[] = { &ett_lanman, &ett_lanman_servers, &ett_lanman_server, &ett_lanman_shares, &ett_lanman_share, }; proto_smb_lanman = proto_register_protocol( "Microsoft Windows Lanman Protocol", "LANMAN", "lanman"); proto_register_field_array(proto_smb_lanman, hf, array_length(hf)); proto_register_subtree_array(ett, array_length(ett)); }