/* packet-sftp.c * Routines for ssh packet dissection * * Jérôme Hamm * * Wireshark - Network traffic analyzer * By Gerald Combs * Copyright 1998 Gerald Combs * * Copied from packet-ssh.c * * SPDX-License-Identifier: GPL-2.0-or-later * * * Note: support for SFTP. * */ /* SFTP is defined in: * * draft-ietf-secsh-filexfer-02 - SSH File Transfer Protocol * */ #include "config.h" /* Start with WIRESHARK_LOG_DOMAINS=sftp and WIRESHARK_LOG_LEVEL=debug to see messages. */ #define WS_LOG_DOMAIN "sftp" #include #include void proto_register_sftp(void); static int proto_sftp = -1; static int hf_ssh_sftp_len = -1; static int hf_ssh_sftp_type = -1; static int hf_ssh_sftp_version = -1; static int hf_ssh_sftp_id = -1; static int hf_ssh_sftp_path_len = -1; static int hf_ssh_sftp_path = -1; static int hf_ssh_sftp_pflags = -1; static int hf_ssh_sftp_name_count = -1; static int hf_ssh_sftp_name_fn_len = -1; static int hf_ssh_sftp_name_fn = -1; static int hf_ssh_sftp_name_ln_len = -1; static int hf_ssh_sftp_name_ln = -1; static int hf_ssh_sftp_attrs_flags = -1; static int hf_ssh_sftp_attrs_size = -1; static int hf_ssh_sftp_attrs_uid = -1; static int hf_ssh_sftp_attrs_gid = -1; static int hf_ssh_sftp_attrs_permissions = -1; static int hf_ssh_sftp_attrs_atime = -1; static int hf_ssh_sftp_attrs_mtime = -1; static int hf_ssh_sftp_attrs_extended_count = -1; static int hf_ssh_sftp_handle_len = -1; static int hf_ssh_sftp_handle = -1; static int hf_ssh_sftp_status = -1; static int hf_ssh_sftp_error_message_len = -1; static int hf_ssh_sftp_error_message = -1; static int hf_ssh_sftp_offset = -1; static int hf_ssh_sftp_length = -1; static int hf_ssh_sftp_data_len = -1; static int hf_ssh_sftp_data = -1; static int hf_ssh_lang_tag_length = -1; static int hf_ssh_lang_tag = -1; static gint ett_sftp = -1; static gint ett_sftp_attrs = -1; static dissector_handle_t sftp_handle; #define SSH_FXP_INIT 1 #define SSH_FXP_VERSION 2 #define SSH_FXP_OPEN 3 #define SSH_FXP_CLOSE 4 #define SSH_FXP_READ 5 #define SSH_FXP_WRITE 6 #define SSH_FXP_LSTAT 7 #define SSH_FXP_FSTAT 8 #define SSH_FXP_SETSTAT 9 #define SSH_FXP_FSETSTAT 10 #define SSH_FXP_OPENDIR 11 #define SSH_FXP_READDIR 12 #define SSH_FXP_REMOVE 13 #define SSH_FXP_MKDIR 14 #define SSH_FXP_RMDIR 15 #define SSH_FXP_REALPATH 16 #define SSH_FXP_STAT 17 #define SSH_FXP_RENAME 18 #define SSH_FXP_READLINK 19 #define SSH_FXP_LINK 21 #define SSH_FXP_BLOCK 22 #define SSH_FXP_UNBLOCK 23 #define SSH_FXP_STATUS 101 #define SSH_FXP_HANDLE 102 #define SSH_FXP_DATA 103 #define SSH_FXP_NAME 104 #define SSH_FXP_ATTRS 105 #define SSH_FXP_EXTENDED 200 #define SSH_FXP_EXTENDED_REPLY 201 #define SSH_FILEXFER_ATTR_SIZE 0x00000001 #define SSH_FILEXFER_ATTR_UIDGID 0x00000002 #define SSH_FILEXFER_ATTR_PERMISSIONS 0x00000004 #define SSH_FILEXFER_ATTR_ACMODTIME 0x00000008 #define SSH_FILEXFER_ATTR_EXTENDED 0x80000000 static const value_string ssh2_sftp_vals[] = { {SSH_FXP_INIT, "SSH_FXP_INIT"}, {SSH_FXP_VERSION, "SSH_FXP_VERSION"}, {SSH_FXP_OPEN, "SSH_FXP_OPEN"}, {SSH_FXP_CLOSE, "SSH_FXP_CLOSE"}, {SSH_FXP_READ, "SSH_FXP_READ"}, {SSH_FXP_WRITE, "SSH_FXP_WRITE"}, {SSH_FXP_LSTAT, "SSH_FXP_LSTAT"}, {SSH_FXP_FSTAT, "SSH_FXP_FSTAT"}, {SSH_FXP_SETSTAT, "SSH_FXP_SETSTAT"}, {SSH_FXP_FSETSTAT, "SSH_FXP_FSETSTAT"}, {SSH_FXP_OPENDIR, "SSH_FXP_OPENDIR"}, {SSH_FXP_READDIR, "SSH_FXP_READDIR"}, {SSH_FXP_REMOVE, "SSH_FXP_REMOVE"}, {SSH_FXP_MKDIR, "SSH_FXP_MKDIR"}, {SSH_FXP_RMDIR, "SSH_FXP_RMDIR"}, {SSH_FXP_REALPATH, "SSH_FXP_REALPATH"}, {SSH_FXP_STAT, "SSH_FXP_STAT"}, {SSH_FXP_RENAME, "SSH_FXP_RENAME"}, {SSH_FXP_READLINK, "SSH_FXP_READLINK"}, {SSH_FXP_LINK, "SSH_FXP_LINK"}, {SSH_FXP_BLOCK, "SSH_FXP_BLOCK"}, {SSH_FXP_UNBLOCK, "SSH_FXP_UNBLOCK"}, {SSH_FXP_STATUS, "SSH_FXP_STATUS"}, {SSH_FXP_HANDLE, "SSH_FXP_HANDLE"}, {SSH_FXP_DATA, "SSH_FXP_DATA"}, {SSH_FXP_NAME, "SSH_FXP_NAME"}, {SSH_FXP_ATTRS, "SSH_FXP_ATTRS"}, {SSH_FXP_EXTENDED, "SSH_FXP_EXTENDED"}, {SSH_FXP_EXTENDED_REPLY, "SSH_FXP_EXTENDED_REPLY"}, {0, NULL} }; static int dissect_sftp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data _U_); static int dissect_sftp_attrs(tvbuff_t *packet_tvb, packet_info *pinfo, int offset, proto_item *msg_type_tree); //static int dissect_sftp(tvbuff_t *packet_tvb, packet_info *pinfo, // int offset, proto_item *msg_type_tree) static int dissect_sftp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data _U_) { int offset = 0; guint plen; guint slen; plen = tvb_get_ntohl(tvb, offset) ; wmem_strbuf_t *title = wmem_strbuf_new(wmem_packet_scope(), "SFTP"); proto_item * sftp_tree = proto_tree_add_subtree(tree, tvb, offset, -1, ett_sftp, NULL, NULL); proto_tree_add_item(sftp_tree, hf_ssh_sftp_len, tvb, offset, 4, ENC_BIG_ENDIAN); offset += 4; guint8 typ; typ = tvb_get_guint8(tvb, offset) ; proto_tree_add_item(sftp_tree, hf_ssh_sftp_type, tvb, offset, 1, ENC_BIG_ENDIAN); offset += 1; col_append_sep_str(pinfo->cinfo, COL_INFO, NULL, val_to_str(typ, ssh2_sftp_vals, "Unknown (%u)")); switch(typ){ case SSH_FXP_INIT:{ int ver = tvb_get_ntohl(tvb, offset) ; wmem_strbuf_append_printf(title, " SSH_FXP_INIT (%d) version %d", typ, ver); proto_tree_add_item(sftp_tree, hf_ssh_sftp_version, tvb, offset, 4, ENC_BIG_ENDIAN); offset += 4; break; } case SSH_FXP_VERSION:{ int ver = tvb_get_ntohl(tvb, offset) ; wmem_strbuf_append_printf(title, " SSH_FXP_VERSION (%d) version %d", typ, ver); proto_tree_add_item(sftp_tree, hf_ssh_sftp_version, tvb, offset, 4, ENC_BIG_ENDIAN); offset += 4; break; } case SSH_FXP_OPEN:{ int id = tvb_get_ntohl(tvb, offset) ; proto_tree_add_item(sftp_tree, hf_ssh_sftp_id, tvb, offset, 4, ENC_BIG_ENDIAN); offset += 4; slen = tvb_get_ntohl(tvb, offset) ; proto_tree_add_item(sftp_tree, hf_ssh_sftp_path_len, tvb, offset, 4, ENC_BIG_ENDIAN); offset += 4; guint8 * path = tvb_get_string_enc(wmem_packet_scope(), tvb, offset, slen, ENC_UTF_8); proto_tree_add_item(sftp_tree, hf_ssh_sftp_path, tvb, offset, slen, ENC_UTF_8); offset += slen; // int pflags = tvb_get_ntohl(tvb, offset) ; proto_tree_add_item(sftp_tree, hf_ssh_sftp_pflags, tvb, offset, 4, ENC_BIG_ENDIAN); offset += 4; slen = dissect_sftp_attrs(tvb, pinfo, offset, sftp_tree); offset += slen; wmem_strbuf_append_printf(title, " SSH_FXP_OPEN (%d) id=%d [%s]", typ, id, path); break; } case SSH_FXP_CLOSE:{ int id = tvb_get_ntohl(tvb, offset) ; proto_tree_add_item(sftp_tree, hf_ssh_sftp_id, tvb, offset, 4, ENC_BIG_ENDIAN); offset += 4; slen = tvb_get_ntohl(tvb, offset) ; proto_tree_add_item(sftp_tree, hf_ssh_sftp_handle_len, tvb, offset, 4, ENC_BIG_ENDIAN); offset += 4; gchar * handle = tvb_bytes_to_str(wmem_packet_scope(), tvb, offset, slen); proto_tree_add_item(sftp_tree, hf_ssh_sftp_handle, tvb, offset, slen, ENC_NA); offset += slen; wmem_strbuf_append_printf(title, " SSH_FXP_CLOSE (%d) id=%d {%s}", typ, id, handle); break; } case SSH_FXP_READ:{ int id = tvb_get_ntohl(tvb, offset) ; proto_tree_add_item(sftp_tree, hf_ssh_sftp_id, tvb, offset, 4, ENC_BIG_ENDIAN); offset += 4; slen = tvb_get_ntohl(tvb, offset) ; proto_tree_add_item(sftp_tree, hf_ssh_sftp_handle_len, tvb, offset, 4, ENC_BIG_ENDIAN); offset += 4; gchar * handle = tvb_bytes_to_str(wmem_packet_scope(), tvb, offset, slen); proto_tree_add_item(sftp_tree, hf_ssh_sftp_handle, tvb, offset, slen, ENC_NA); offset += slen; proto_tree_add_item(sftp_tree, hf_ssh_sftp_offset, tvb, offset, 8, ENC_BIG_ENDIAN); offset += 8; proto_tree_add_item(sftp_tree, hf_ssh_sftp_length, tvb, offset, 4, ENC_BIG_ENDIAN); offset += 4; wmem_strbuf_append_printf(title, " SSH_FXP_READ (%d) id=%d {%s}", typ, id, handle); break; } case SSH_FXP_WRITE:{ int id = tvb_get_ntohl(tvb, offset); proto_tree_add_item(sftp_tree, hf_ssh_sftp_id, tvb, offset, 4, ENC_BIG_ENDIAN); offset += 4; slen = tvb_get_ntohl(tvb, offset) ; proto_tree_add_item(sftp_tree, hf_ssh_sftp_handle_len, tvb, offset, 4, ENC_BIG_ENDIAN); offset += 4; gchar * handle = tvb_bytes_to_str(wmem_packet_scope(), tvb, offset, slen); proto_tree_add_item(sftp_tree, hf_ssh_sftp_handle, tvb, offset, slen, ENC_NA); offset += slen; proto_tree_add_item(sftp_tree, hf_ssh_sftp_offset, tvb, offset, 8, ENC_BIG_ENDIAN); offset += 8; int dlen = tvb_get_ntohl(tvb, offset); proto_tree_add_item(sftp_tree, hf_ssh_sftp_data_len, tvb, offset, 4, ENC_BIG_ENDIAN); offset += 4; proto_tree_add_item(sftp_tree, hf_ssh_sftp_data, tvb, offset, dlen, ENC_NA); offset += dlen; wmem_strbuf_append_printf(title, " SSH_FXP_WRITE (%d) id=%d {%s} len=%d", typ, id, handle, dlen); break; } case SSH_FXP_LSTAT:{ int id = tvb_get_ntohl(tvb, offset); proto_tree_add_item(sftp_tree, hf_ssh_sftp_id, tvb, offset, 4, ENC_BIG_ENDIAN); offset += 4; slen = tvb_get_ntohl(tvb, offset) ; proto_tree_add_item(sftp_tree, hf_ssh_sftp_path_len, tvb, offset, 4, ENC_BIG_ENDIAN); offset += 4; guint8 * path = tvb_get_string_enc(wmem_packet_scope(), tvb, offset, slen, ENC_UTF_8); wmem_strbuf_append_printf(title, " SSH_FXP_LSTAT (%d) id=%d [%s]", typ, id, path); proto_tree_add_item(sftp_tree, hf_ssh_sftp_path, tvb, offset, slen, ENC_UTF_8); offset += slen; break; } case SSH_FXP_FSTAT:{ int id = tvb_get_ntohl(tvb, offset); proto_tree_add_item(sftp_tree, hf_ssh_sftp_id, tvb, offset, 4, ENC_BIG_ENDIAN); offset += 4; slen = tvb_get_ntohl(tvb, offset) ; proto_tree_add_item(sftp_tree, hf_ssh_sftp_handle_len, tvb, offset, 4, ENC_BIG_ENDIAN); offset += 4; gchar * handle = tvb_bytes_to_str(wmem_packet_scope(), tvb, offset, slen); proto_tree_add_item(sftp_tree, hf_ssh_sftp_handle, tvb, offset, slen, ENC_NA); offset += slen; wmem_strbuf_append_printf(title, " SSH_FXP_FSTAT (%d) id=%d {%s}", typ, id, handle); break; } case SSH_FXP_SETSTAT:{ int id = tvb_get_ntohl(tvb, offset); proto_tree_add_item(sftp_tree, hf_ssh_sftp_id, tvb, offset, 4, ENC_BIG_ENDIAN); offset += 4; slen = tvb_get_ntohl(tvb, offset) ; proto_tree_add_item(sftp_tree, hf_ssh_sftp_path_len, tvb, offset, 4, ENC_BIG_ENDIAN); offset += 4; guint8 * path = tvb_get_string_enc(wmem_packet_scope(), tvb, offset, slen, ENC_UTF_8); proto_tree_add_item(sftp_tree, hf_ssh_sftp_path, tvb, offset, slen, ENC_UTF_8); offset += slen; slen = dissect_sftp_attrs(tvb, pinfo, offset, sftp_tree); proto_item_set_len(sftp_tree, slen); offset += slen; wmem_strbuf_append_printf(title, " SSH_FXP_SETSTAT (%d) id=%d [%s]", typ, id, path); break; } // case SSH_FXP_FSETSTAT):{ // break; // } case SSH_FXP_OPENDIR:{ int id = tvb_get_ntohl(tvb, offset); proto_tree_add_item(sftp_tree, hf_ssh_sftp_id, tvb, offset, 4, ENC_BIG_ENDIAN); offset += 4; slen = tvb_get_ntohl(tvb, offset) ; proto_tree_add_item(sftp_tree, hf_ssh_sftp_path_len, tvb, offset, 4, ENC_BIG_ENDIAN); offset += 4; guint8 * path = tvb_get_string_enc(wmem_packet_scope(), tvb, offset, slen, ENC_UTF_8); proto_tree_add_item(sftp_tree, hf_ssh_sftp_path, tvb, offset, slen, ENC_UTF_8); offset += slen; wmem_strbuf_append_printf(title, " SSH_FXP_OPENDIR (%d) id=%d [%s]", typ, id, path); break; } case SSH_FXP_READDIR:{ int id = tvb_get_ntohl(tvb, offset); proto_tree_add_item(sftp_tree, hf_ssh_sftp_id, tvb, offset, 4, ENC_BIG_ENDIAN); offset += 4; slen = tvb_get_ntohl(tvb, offset) ; proto_tree_add_item(sftp_tree, hf_ssh_sftp_handle_len, tvb, offset, 4, ENC_BIG_ENDIAN); offset += 4; gchar * handle = tvb_bytes_to_str(wmem_packet_scope(), tvb, offset, slen); proto_tree_add_item(sftp_tree, hf_ssh_sftp_handle, tvb, offset, slen, ENC_NA); offset += slen; wmem_strbuf_append_printf(title, " SSH_FXP_READDIR (%d) id=%d {%s}", typ, id, handle); break; } case SSH_FXP_REMOVE:{ int id = tvb_get_ntohl(tvb, offset); proto_tree_add_item(sftp_tree, hf_ssh_sftp_id, tvb, offset, 4, ENC_BIG_ENDIAN); offset += 4; slen = tvb_get_ntohl(tvb, offset) ; proto_tree_add_item(sftp_tree, hf_ssh_sftp_path_len, tvb, offset, 4, ENC_BIG_ENDIAN); offset += 4; guint8 * path = tvb_get_string_enc(wmem_packet_scope(), tvb, offset, slen, ENC_UTF_8); wmem_strbuf_append_printf(title, " SSH_FXP_REMOVE (%d) id=%d [%s]", typ, id, path); proto_tree_add_item(sftp_tree, hf_ssh_sftp_path, tvb, offset, slen, ENC_UTF_8); offset += slen; break; } // case SSH_FXP_MKDIR:{ // break; // } // case SSH_FXP_RMDIR:{ // break; // } case SSH_FXP_REALPATH:{ int id = tvb_get_ntohl(tvb, offset); proto_tree_add_item(sftp_tree, hf_ssh_sftp_id, tvb, offset, 4, ENC_BIG_ENDIAN); offset += 4; slen = tvb_get_ntohl(tvb, offset); proto_tree_add_item(sftp_tree, hf_ssh_sftp_path_len, tvb, offset, 4, ENC_BIG_ENDIAN); offset += 4; guint8 * path = tvb_get_string_enc(wmem_packet_scope(), tvb, offset, slen, ENC_UTF_8); wmem_strbuf_append_printf(title, " SSH_FXP_REALPATH (%d) id=%d [%s]", typ, id, path); proto_tree_add_item(sftp_tree, hf_ssh_sftp_path, tvb, offset, slen, ENC_UTF_8); offset += slen; break; } case SSH_FXP_STAT:{ int id = tvb_get_ntohl(tvb, offset); proto_tree_add_item(sftp_tree, hf_ssh_sftp_id, tvb, offset, 4, ENC_BIG_ENDIAN); offset += 4; slen = tvb_get_ntohl(tvb, offset) ; proto_tree_add_item(sftp_tree, hf_ssh_sftp_path_len, tvb, offset, 4, ENC_BIG_ENDIAN); offset += 4; guint8 * path = tvb_get_string_enc(wmem_packet_scope(), tvb, offset, slen, ENC_UTF_8); wmem_strbuf_append_printf(title, " SSH_FXP_STAT (%d) id=%d [%s]", typ, id, path); proto_tree_add_item(sftp_tree, hf_ssh_sftp_path, tvb, offset, slen, ENC_UTF_8); offset += slen; break; } case SSH_FXP_RENAME:{ int id = tvb_get_ntohl(tvb, offset); proto_tree_add_item(sftp_tree, hf_ssh_sftp_id, tvb, offset, 4, ENC_BIG_ENDIAN); offset += 4; slen = tvb_get_ntohl(tvb, offset) ; proto_tree_add_item(sftp_tree, hf_ssh_sftp_path_len, tvb, offset, 4, ENC_BIG_ENDIAN); offset += 4; guint8 * oldpath = tvb_get_string_enc(wmem_packet_scope(), tvb, offset, slen, ENC_UTF_8); proto_tree_add_item(sftp_tree, hf_ssh_sftp_path, tvb, offset, slen, ENC_UTF_8); offset += slen; slen = tvb_get_ntohl(tvb, offset) ; proto_tree_add_item(sftp_tree, hf_ssh_sftp_path_len, tvb, offset, 4, ENC_BIG_ENDIAN); offset += 4; guint8 * newpath = tvb_get_string_enc(wmem_packet_scope(), tvb, offset, slen, ENC_UTF_8); proto_tree_add_item(sftp_tree, hf_ssh_sftp_path, tvb, offset, slen, ENC_UTF_8); offset += slen; wmem_strbuf_append_printf(title, " SSH_FXP_STAT (%d) id=%d [%s] > [%s]", typ, id, oldpath, newpath); break; } // case SSH_FXP_READLINK:{ // break; // } // case SSH_FXP_SYMLINK:{ // break; // } case SSH_FXP_STATUS:{ int id = tvb_get_ntohl(tvb, offset) ; proto_tree_add_item(sftp_tree, hf_ssh_sftp_id, tvb, offset, 4, ENC_BIG_ENDIAN); offset += 4; int code = tvb_get_ntohl(tvb, offset) ; proto_tree_add_item(sftp_tree, hf_ssh_sftp_status, tvb, offset, 4, ENC_BIG_ENDIAN); offset += 4; slen = tvb_get_ntohl(tvb, offset) ; proto_tree_add_item(sftp_tree, hf_ssh_sftp_error_message_len, tvb, offset, 4, ENC_BIG_ENDIAN); offset += 4; guint8 * err_msg = tvb_get_string_enc(wmem_packet_scope(), tvb, offset, slen, ENC_UTF_8); proto_tree_add_item(sftp_tree, hf_ssh_sftp_error_message, tvb, offset, slen, ENC_UTF_8); offset += slen; slen = tvb_get_ntohl(tvb, offset) ; proto_tree_add_item(sftp_tree, hf_ssh_lang_tag_length, tvb, offset, 4, ENC_BIG_ENDIAN); offset += 4; proto_tree_add_item(sftp_tree, hf_ssh_lang_tag, tvb, offset, slen, ENC_UTF_8); offset += slen; wmem_strbuf_append_printf(title, " SSH_FXP_STATUS (%d) id=%d code=%d [%s]", typ, id, code, err_msg); break; } case SSH_FXP_HANDLE:{ int id = tvb_get_ntohl(tvb, offset); proto_tree_add_item(sftp_tree, hf_ssh_sftp_id, tvb, offset, 4, ENC_BIG_ENDIAN); offset += 4; slen = tvb_get_ntohl(tvb, offset) ; proto_tree_add_item(sftp_tree, hf_ssh_sftp_handle_len, tvb, offset, 4, ENC_BIG_ENDIAN); offset += 4; gchar * handle = tvb_bytes_to_str(wmem_packet_scope(), tvb, offset, slen); proto_tree_add_item(sftp_tree, hf_ssh_sftp_handle, tvb, offset, slen, ENC_NA); offset += slen; wmem_strbuf_append_printf(title, " SSH_FXP_HANDLE (%d) id=%d {%s}", typ, id, handle); break; } case SSH_FXP_DATA:{ int id = tvb_get_ntohl(tvb, offset) ; proto_tree_add_item(sftp_tree, hf_ssh_sftp_id, tvb, offset, 4, ENC_BIG_ENDIAN); offset += 4; int dlen = tvb_get_ntohl(tvb, offset) ; proto_tree_add_item(sftp_tree, hf_ssh_sftp_data_len, tvb, offset, 4, ENC_BIG_ENDIAN); offset += 4; proto_tree_add_item(sftp_tree, hf_ssh_sftp_data, tvb, offset, dlen, ENC_NA); offset += dlen; wmem_strbuf_append_printf(title, " SSH_FXP_DATA (%d) id=%d len=%d", typ, id, dlen); break; } case SSH_FXP_NAME:{ wmem_strbuf_append_printf(title, " SSH_FXP_NAME (%d)", typ); proto_tree_add_item(sftp_tree, hf_ssh_sftp_id, tvb, offset, 4, ENC_BIG_ENDIAN); offset += 4; guint count = tvb_get_ntohl(tvb, offset) ; proto_tree_add_item(sftp_tree, hf_ssh_sftp_name_count, tvb, offset, 4, ENC_BIG_ENDIAN); offset += 4; guint cnt; for(cnt=0;cnt