diff --git a/markbase-core/src/ssh_server/sftp_handler.rs b/markbase-core/src/ssh_server/sftp_handler.rs index 8a0be40..c0ab140 100644 --- a/markbase-core/src/ssh_server/sftp_handler.rs +++ b/markbase-core/src/ssh_server/sftp_handler.rs @@ -858,6 +858,18 @@ impl SftpHandler { "sha256-hash@openssh.com" => { self.handle_sha256_hash(&mut cursor, id) } + "sha384-hash@openssh.com" => { + self.handle_sha384_hash(&mut cursor, id) + } + "sha512-hash@openssh.com" => { + self.handle_sha512_hash(&mut cursor, id) + } + "check-file@openssh.com" => { + self.handle_check_file(&mut cursor, id) + } + "copy-data@openssh.com" => { + self.handle_copy_data(&mut cursor, id) + } _ => { warn!("Unsupported SFTP extension: {}", extension_name); self.build_status_response(id, SftpStatus::SSH_FX_FAILURE, &format!("Unsupported extension: {}", extension_name)) @@ -1082,6 +1094,188 @@ impl SftpHandler { } } + /// 处理sha384-hash@openssh.com扩展(Phase 12:SHA384哈希计算) + fn handle_sha384_hash(&self, cursor: &mut std::io::Cursor<&[u8]>, id: u32) -> Result> { + let path = read_sftp_string(cursor)?; + let offset = cursor.read_u64::()?; + let length = cursor.read_u64::()?; + + info!("sha384-hash: path={}, offset={}, length={}", path, offset, length); + + let full_path = self.resolve_path(&path)?; + + match File::open(&full_path) { + Ok(mut file) => { + file.seek(SeekFrom::Start(offset))?; + + let mut buffer = vec![0u8; length as usize]; + file.read_exact(&mut buffer)?; + + // 计算SHA384哈希 + use sha2::{Sha384, Digest}; + let mut hasher = Sha384::new(); + hasher.update(&buffer); + let hash = hasher.finalize(); + let hash_hex = format!("{:x}", hash); + + // 构建响应 + let mut response = Vec::new(); + response.write_u8(SftpPacketType::SSH_FXP_EXTENDED_REPLY as u8)?; + response.write_u32::(id)?; + + response.write_u32::(6)?; + response.write_all("sha384".as_bytes())?; + + response.write_u32::(hash_hex.len() as u32)?; + response.write_all(hash_hex.as_bytes())?; + + self.wrap_sftp_packet(&response) + } + Err(e) => { + self.build_status_response(id, SftpStatus::SSH_FX_FAILURE, &format!("SHA384 hash error: {}", e)) + } + } + } + + /// 处理sha512-hash@openssh.com扩展(Phase 12:SHA512哈希计算) + fn handle_sha512_hash(&self, cursor: &mut std::io::Cursor<&[u8]>, id: u32) -> Result> { + let path = read_sftp_string(cursor)?; + let offset = cursor.read_u64::()?; + let length = cursor.read_u64::()?; + + info!("sha512-hash: path={}, offset={}, length={}", path, offset, length); + + let full_path = self.resolve_path(&path)?; + + match File::open(&full_path) { + Ok(mut file) => { + file.seek(SeekFrom::Start(offset))?; + + let mut buffer = vec![0u8; length as usize]; + file.read_exact(&mut buffer)?; + + // 计算SHA512哈希 + use sha2::{Sha512, Digest}; + let mut hasher = Sha512::new(); + hasher.update(&buffer); + let hash = hasher.finalize(); + let hash_hex = format!("{:x}", hash); + + // 构建响应 + let mut response = Vec::new(); + response.write_u8(SftpPacketType::SSH_FXP_EXTENDED_REPLY as u8)?; + response.write_u32::(id)?; + + response.write_u32::(6)?; + response.write_all("sha512".as_bytes())?; + + response.write_u32::(hash_hex.len() as u32)?; + response.write_all(hash_hex.as_bytes())?; + + self.wrap_sftp_packet(&response) + } + Err(e) => { + self.build_status_response(id, SftpStatus::SSH_FX_FAILURE, &format!("SHA512 hash error: {}", e)) + } + } + } + + /// 处理check-file@openssh.com扩展(Phase 12:文件检查) + fn handle_check_file(&self, cursor: &mut std::io::Cursor<&[u8]>, id: u32) -> Result> { + let path = read_sftp_string(cursor)?; + let check_flags = cursor.read_u32::()?; + + info!("check-file: path={}, flags={:#x}", path, check_flags); + + let full_path = self.resolve_path(&path)?; + + match fs::metadata(&full_path) { + Ok(metadata) => { + // 构建响应 + let mut response = Vec::new(); + response.write_u8(SftpPacketType::SSH_FXP_EXTENDED_REPLY as u8)?; + response.write_u32::(id)?; + + // 返回文件存在和基本信息 + response.write_u32::(1)?; // result: 1 = file exists + + let msg = format!("File exists, size: {}", metadata.len()); + response.write_u32::(msg.len() as u32)?; + response.write_all(msg.as_bytes())?; + + self.wrap_sftp_packet(&response) + } + Err(e) => { + self.build_status_response(id, SftpStatus::SSH_FX_NO_SUCH_FILE, &format!("Check file error: {}", e)) + } + } + } + + /// 处理copy-data@openssh.com扩展(Phase 12:服务器端复制) + fn handle_copy_data(&mut self, cursor: &mut std::io::Cursor<&[u8]>, id: u32) -> Result> { + let read_handle_bytes = read_sftp_string_bytes(cursor)?; + let read_offset = cursor.read_u64::()?; + let read_length = cursor.read_u64::()?; + let write_handle_bytes = read_sftp_string_bytes(cursor)?; + let write_offset = cursor.read_u64::()?; + + info!("copy-data: read_handle={}, read_offset={}, read_length={}, write_handle={}, write_offset={}", + u32::from_be_bytes([read_handle_bytes[0], read_handle_bytes[1], read_handle_bytes[2], read_handle_bytes[3]]), + read_offset, read_length, + u32::from_be_bytes([write_handle_bytes[0], write_handle_bytes[1], write_handle_bytes[2], write_handle_bytes[3]]), + write_offset); + + let read_handle_id = u32::from_be_bytes([read_handle_bytes[0], read_handle_bytes[1], read_handle_bytes[2], read_handle_bytes[3]]); + let write_handle_id = u32::from_be_bytes([write_handle_bytes[0], write_handle_bytes[1], write_handle_bytes[2], write_handle_bytes[3]]); + + // 获取read handle的path(不可变引用) + let read_path = if let Some(read_handle) = self.handles.get(&read_handle_id) { + read_handle.path.clone() + } else { + return self.build_status_response(id, SftpStatus::SSH_FX_FAILURE, "Invalid read handle"); + }; + + // 获取write handle的path(不可变引用) + let write_path = if let Some(write_handle) = self.handles.get(&write_handle_id) { + write_handle.path.clone() + } else { + return self.build_status_response(id, SftpStatus::SSH_FX_FAILURE, "Invalid write handle"); + }; + + // 从read_path读取数据 + match File::open(&read_path) { + Ok(mut read_file) => { + read_file.seek(SeekFrom::Start(read_offset))?; + let mut buffer = vec![0u8; read_length as usize]; + read_file.read_exact(&mut buffer)?; + + // 写入到write_path + match OpenOptions::new().write(true).open(&write_path) { + Ok(mut write_file) => { + write_file.seek(SeekFrom::Start(write_offset))?; + write_file.write_all(&buffer)?; + + // 构建响应 + let mut response = Vec::new(); + response.write_u8(SftpPacketType::SSH_FXP_EXTENDED_REPLY as u8)?; + response.write_u32::(id)?; + + // 返回复制的字节数 + response.write_u64::(read_length)?; + + self.wrap_sftp_packet(&response) + } + Err(e) => { + self.build_status_response(id, SftpStatus::SSH_FX_FAILURE, &format!("Write file error: {}", e)) + } + } + } + Err(e) => { + self.build_status_response(id, SftpStatus::SSH_FX_FAILURE, &format!("Read file error: {}", e)) + } + } + } + /// 解析路径(安全性检查,参考OpenSSH sftp-server.c: path_resolve()) fn resolve_path(&self, path: &str) -> Result { info!("resolve_path: input={}, root_dir={:?}", path, self.root_dir);