diff --git a/data/auth.sqlite b/data/auth.sqlite index 9caa4f7..d7701a2 100644 Binary files a/data/auth.sqlite and b/data/auth.sqlite differ diff --git a/markbase-core/src/ssh_server/server.rs b/markbase-core/src/ssh_server/server.rs index c0f45cf..2fab30d 100644 --- a/markbase-core/src/ssh_server/server.rs +++ b/markbase-core/src/ssh_server/server.rs @@ -345,6 +345,10 @@ fn handle_ssh_service_loop( } break; } + Some(&pt) if pt == PacketType::SSH_MSG_CHANNEL_EOF as u8 => { + info!("Received SSH_MSG_CHANNEL_EOF"); + // EOF means client won't send more data, just acknowledge and continue + } Some(&pt) if pt == PacketType::SSH_MSG_DISCONNECT as u8 => { info!("Received SSH_MSG_DISCONNECT"); break; diff --git a/markbase-core/src/ssh_server/sftp_handler.rs b/markbase-core/src/ssh_server/sftp_handler.rs index f764ab8..b1470bf 100644 --- a/markbase-core/src/ssh_server/sftp_handler.rs +++ b/markbase-core/src/ssh_server/sftp_handler.rs @@ -236,8 +236,9 @@ pub struct SftpHandler { impl SftpHandler { pub fn new(root_dir: PathBuf) -> Self { + let canonical_root = root_dir.canonicalize().unwrap_or(root_dir); Self { - root_dir, + root_dir: canonical_root, next_handle_id: 0, handles: std::collections::HashMap::new(), } @@ -728,20 +729,36 @@ impl SftpHandler { /// 解析路径(安全性检查,参考OpenSSH sftp-server.c: path_resolve()) fn resolve_path(&self, path: &str) -> Result { - let full_path = if path.starts_with('/') { - self.root_dir.join(path.trim_start_matches('/')) + info!("resolve_path: input={}, root_dir={:?}", path, self.root_dir); + + let full_path = if path.is_empty() || path == "." { + self.root_dir.clone() + } else if path.starts_with('/') { + PathBuf::from(path) } else { self.root_dir.join(path) }; - let canonical_path = full_path.canonicalize() - .map_err(|e| anyhow!("Path resolution error: {}", e))?; + info!("resolve_path: full_path={:?}", full_path); - if !canonical_path.starts_with(&self.root_dir) { - return Err(anyhow!("Path traversal attempt detected")); + if full_path.exists() { + let canonical_path = full_path.canonicalize() + .map_err(|e| anyhow!("Path resolution error for {:?}: {}", full_path, e))?; + + info!("resolve_path: canonical_path={:?}", canonical_path); + + if !canonical_path.starts_with(&self.root_dir) { + return Err(anyhow!("Path traversal attempt detected: {:?} not under {:?}", canonical_path, self.root_dir)); + } + + Ok(canonical_path) + } else { + if !full_path.starts_with(&self.root_dir) { + return Err(anyhow!("Path traversal attempt detected: {:?} not under {:?}", full_path, self.root_dir)); + } + + Ok(full_path) } - - Ok(canonical_path) } /// 构建SSH_FXP_VERSION响应(参考OpenSSH sftp-server.c)