From 1be361d91a7c2a2295fe9041c9313d522684b435 Mon Sep 17 00:00:00 2001 From: Warren Date: Mon, 15 Jun 2026 10:50:08 +0800 Subject: [PATCH] Update Phase 6: Fix SFTP subsystem initialization and data handling MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Phase 6 updates: - Add SftpHandler integration in Channel structure - Initialize SFTP handler on subsystem request - Handle SFTP packets via CHANNEL_DATA - Fix CHANNEL_DATA response handling in server loop Phase 7 progress: - SFTP subsystem initialization working - SSH_FXP_INIT/VERSION handshake working - SFTP packet format partially implemented - Need further debugging for complete SFTP functionality Current status: - SSH command execution fully working (Phase 6 ✓) - SFTP connection initialization working - File transfer operations pending debug --- markbase-core/src/ssh_server/channel.rs | 54 ++++++++++++++++++++++--- markbase-core/src/ssh_server/server.rs | 7 +++- 2 files changed, 54 insertions(+), 7 deletions(-) diff --git a/markbase-core/src/ssh_server/channel.rs b/markbase-core/src/ssh_server/channel.rs index 543f495..58a74a1 100644 --- a/markbase-core/src/ssh_server/channel.rs +++ b/markbase-core/src/ssh_server/channel.rs @@ -8,6 +8,8 @@ use byteorder::{BigEndian, ReadBytesExt, WriteBytesExt}; use log::{info, warn, debug}; use std::collections::HashMap; use std::sync::{Arc, Mutex}; +use crate::ssh_server::sftp_handler::SftpHandler; // Phase 7: SFTP handler +use std::path::PathBuf; // Phase 7: Path for SFTP root directory /// SSH Channel管理器(参考OpenSSH channel.c: struct channel) pub struct ChannelManager { @@ -73,6 +75,7 @@ impl ChannelManager { maximum_packet_size, state: ChannelState::Open, output_buffer: None, // Phase 6: 初始化为空 + sftp_handler: None, // Phase 7: 初始化为空 }; self.channels.insert(server_channel, channel); @@ -184,7 +187,17 @@ impl ChannelManager { // 检查subsystem支持(OpenSSH支持:sftp) if subsystem == "sftp" { info!("SFTP subsystem requested"); - // Phase 7将实现SFTP + + // Phase 7: 初始化SFTP handler + let root_dir = PathBuf::from("/Users/accusys/markbase"); // 默认root目录 + let sftp_handler = SftpHandler::new(root_dir); + + // 存储到channel + if let Some(ch) = self.channels.get_mut(&channel) { + ch.sftp_handler = Some(sftp_handler); + info!("SFTP handler initialized for channel {}", channel); + } + if want_reply { Ok(Some(self.build_channel_success(channel)?)) } else { @@ -258,10 +271,10 @@ impl ChannelManager { } /// 处理SSH_MSG_CHANNEL_DATA(参考OpenSSH channel.c: channel_input_data()) - pub fn handle_channel_data(&mut self, packet: &SshPacket) -> Result<()> { + pub fn handle_channel_data(&mut self, packet: &SshPacket) -> Result> { info!("Processing SSH_MSG_CHANNEL_DATA"); - let mut cursor = std::io::Cursor::new(packet.payload.as_slice()); // 使用as_slice()(Rust标准) + let mut cursor = std::io::Cursor::new(packet.payload.as_slice()); // Packet type let packet_type = cursor.read_u8()?; @@ -273,13 +286,41 @@ impl ChannelManager { let recipient_channel = cursor.read_u32::()?; // 读取数据(SSH string) - let data = read_ssh_string(&mut cursor)?; + let data_length = cursor.read_u32::()?; + let mut data = vec![0u8; data_length as usize]; + cursor.read_exact(&mut data)?; info!("Channel data: channel={}, length={}", recipient_channel, data.len()); + info!("Channel data content (first 20 bytes): {:?}", &data[..std::cmp::min(20, data.len())]); - // 简化实现:接受数据(实际应处理) + // Phase 7: 检查是否是SFTP channel + if let Some(channel) = self.channels.get_mut(&recipient_channel) { + if let Some(sftp_handler) = &mut channel.sftp_handler { + info!("Processing SFTP request ({} bytes)", data.len()); + + // SFTP data是SSH string格式:前4 bytes是length field + // 真正的SFTP packet从data[4]开始(跳过length field) + if data.len() < 4 { + warn!("SFTP data too short (less than 4 bytes)"); + return Ok(None); + } + + let sftp_packet_length = u32::from_be_bytes([data[0], data[1], data[2], data[3]]) as usize; + let sftp_packet = &data[4..4 + sftp_packet_length]; + + info!("SFTP packet: length={}, content={:?}", sftp_packet_length, &sftp_packet[..std::cmp::min(20, sftp_packet.len())]); + + // 处理SFTP请求 + let response = sftp_handler.handle_request(sftp_packet)?; + info!("SFTP response: {} bytes", response.len()); + + // 构建SSH_MSG_CHANNEL_DATA返回SFTP响应(需要SSH string格式) + return Ok(Some(self.build_channel_data(recipient_channel, &response)?)); + } + } - Ok(()) + // 如果不是SFTP,返回None(Phase 6的普通channel data处理) + Ok(None) } /// 处理SSH_MSG_CHANNEL_CLOSE(参考OpenSSH channel.c: channel_input_close()) @@ -455,6 +496,7 @@ struct Channel { maximum_packet_size: u32, state: ChannelState, output_buffer: Option>, // Phase 6: 命令输出缓冲 + sftp_handler: Option, // Phase 7: SFTP处理器 } /// SSH Channel状态(参考OpenSSH channel.c) diff --git a/markbase-core/src/ssh_server/server.rs b/markbase-core/src/ssh_server/server.rs index c374310..c0f45cf 100644 --- a/markbase-core/src/ssh_server/server.rs +++ b/markbase-core/src/ssh_server/server.rs @@ -330,7 +330,12 @@ fn handle_ssh_service_loop( } Some(&pt) if pt == PacketType::SSH_MSG_CHANNEL_DATA as u8 => { info!("Received SSH_MSG_CHANNEL_DATA"); - channel_manager.handle_channel_data(&packet)?; + if let Some(response) = channel_manager.handle_channel_data(&packet)? { + // Phase 7: SFTP响应通过CHANNEL_DATA返回 + let encrypted_response = EncryptedPacket::new(&response.payload, encryption_ctx, true)?; + encrypted_response.write(stream)?; + info!("Sent SSH_MSG_CHANNEL_DATA (SFTP response)"); + } } Some(&pt) if pt == PacketType::SSH_MSG_CHANNEL_CLOSE as u8 => { info!("Received SSH_MSG_CHANNEL_CLOSE");