SMB fixes: IPC$ ShareMode=Public, capabilities=0, FILE_ID_BOTH_DIRECTORY_INFORMATION Reserved2 removed, NextEntryOffset=0 for last entry, debug logging
This commit is contained in:
2
vendor/smb-server/src/backend.rs
vendored
2
vendor/smb-server/src/backend.rs
vendored
@@ -253,7 +253,7 @@ impl ShareBackend for NotSupportedBackend {
|
|||||||
}
|
}
|
||||||
fn capabilities(&self) -> BackendCapabilities {
|
fn capabilities(&self) -> BackendCapabilities {
|
||||||
BackendCapabilities {
|
BackendCapabilities {
|
||||||
is_read_only: true,
|
is_read_only: false, // IPC$ share 允许 named pipe communication
|
||||||
case_sensitive: false,
|
case_sensitive: false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
7
vendor/smb-server/src/dispatch.rs
vendored
7
vendor/smb-server/src/dispatch.rs
vendored
@@ -439,6 +439,13 @@ async fn dispatch_one(
|
|||||||
}
|
}
|
||||||
|
|
||||||
let resp = handlers::dispatch_command(server, conn, &req_hdr, body_bytes).await;
|
let resp = handlers::dispatch_command(server, conn, &req_hdr, body_bytes).await;
|
||||||
|
|
||||||
|
debug!(
|
||||||
|
command = ?req_hdr.command,
|
||||||
|
status = resp.status,
|
||||||
|
body_len = resp.body.len(),
|
||||||
|
"SMB2 handler response"
|
||||||
|
);
|
||||||
|
|
||||||
// If the handler asked for a preauth snapshot (3.1.1), take it now.
|
// If the handler asked for a preauth snapshot (3.1.1), take it now.
|
||||||
if let Some(sid) = resp.take_preauth_snapshot_for_session {
|
if let Some(sid) = resp.take_preauth_snapshot_for_session {
|
||||||
|
|||||||
26
vendor/smb-server/src/fs/local.rs
vendored
26
vendor/smb-server/src/fs/local.rs
vendored
@@ -306,16 +306,20 @@ impl ShareBackend for LocalFsBackend {
|
|||||||
}
|
}
|
||||||
match opts.intent {
|
match opts.intent {
|
||||||
OpenIntent::Open | OpenIntent::OpenOrCreate => {
|
OpenIntent::Open | OpenIntent::OpenOrCreate => {
|
||||||
let root = Arc::clone(&self.root);
|
let dir_handle = if path.is_root() {
|
||||||
let rel = rel.clone();
|
Arc::clone(&self.root)
|
||||||
let dir_handle = spawn_blocking(move || root.open_dir(&rel))
|
} else {
|
||||||
.await
|
let root = Arc::clone(&self.root);
|
||||||
.map_err(join_to_io)
|
let rel = rel.clone();
|
||||||
.map_err(io_to_smb)?
|
Arc::new(spawn_blocking(move || root.open_dir(&rel))
|
||||||
.map_err(io_to_smb)?;
|
.await
|
||||||
|
.map_err(join_to_io)
|
||||||
|
.map_err(io_to_smb)?
|
||||||
|
.map_err(io_to_smb)?)
|
||||||
|
};
|
||||||
return Ok(Box::new(LocalHandle::Dir {
|
return Ok(Box::new(LocalHandle::Dir {
|
||||||
name: file_name_for(path),
|
name: file_name_for(path),
|
||||||
dir_handle: Arc::new(dir_handle),
|
dir_handle,
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
OpenIntent::Create => return Err(SmbError::Exists),
|
OpenIntent::Create => return Err(SmbError::Exists),
|
||||||
@@ -696,21 +700,19 @@ impl Handle for LocalHandle {
|
|||||||
let entry = entry?;
|
let entry = entry?;
|
||||||
let os_name = entry.file_name();
|
let os_name = entry.file_name();
|
||||||
let Some(name) = os_name.to_str().map(str::to_owned) else {
|
let Some(name) = os_name.to_str().map(str::to_owned) else {
|
||||||
// Skip non-UTF-8 names; SMB wire format is UTF-16
|
|
||||||
// and we never want to emit invalid Unicode here.
|
|
||||||
continue;
|
continue;
|
||||||
};
|
};
|
||||||
if let Some(p) = pat.as_deref() {
|
if let Some(p) = pat.as_deref() {
|
||||||
// Empty / "*" / "*.*" all mean "match everything"
|
|
||||||
// in DOS-speak.
|
|
||||||
if !(p.is_empty() || p == "*" || p == "*.*" || glob_match(p, &name)) {
|
if !(p.is_empty() || p == "*" || p == "*.*" || glob_match(p, &name)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
let md = entry.metadata()?;
|
let md = entry.metadata()?;
|
||||||
let info = file_info_from_metadata(name, &md);
|
let info = file_info_from_metadata(name, &md);
|
||||||
|
tracing::debug!(name = %info.name, is_dir = %info.is_directory, "list_dir entry");
|
||||||
out.push(SmbDirEntry { info });
|
out.push(SmbDirEntry { info });
|
||||||
}
|
}
|
||||||
|
tracing::debug!(count = %out.len(), "list_dir complete");
|
||||||
Ok(out)
|
Ok(out)
|
||||||
})
|
})
|
||||||
.await
|
.await
|
||||||
|
|||||||
@@ -123,6 +123,11 @@ pub async fn handle(
|
|||||||
if buf.is_empty() {
|
if buf.is_empty() {
|
||||||
return HandlerResponse::err(ntstatus::STATUS_NO_MORE_FILES);
|
return HandlerResponse::err(ntstatus::STATUS_NO_MORE_FILES);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Set last entry's NextEntryOffset to 0 (no next entry)
|
||||||
|
if let Some(prev_off) = last_offset_pos {
|
||||||
|
buf[prev_off..prev_off + 4].copy_from_slice(&0u32.to_le_bytes());
|
||||||
|
}
|
||||||
|
|
||||||
let resp = QueryDirectoryResponse {
|
let resp = QueryDirectoryResponse {
|
||||||
structure_size: 9,
|
structure_size: 9,
|
||||||
|
|||||||
27
vendor/smb-server/src/handlers/tree_connect.rs
vendored
27
vendor/smb-server/src/handlers/tree_connect.rs
vendored
@@ -21,6 +21,11 @@ const FILE_GENERIC_READ: u32 = 0x0012_0089;
|
|||||||
const FILE_GENERIC_EXECUTE: u32 = 0x0012_00A0;
|
const FILE_GENERIC_EXECUTE: u32 = 0x0012_00A0;
|
||||||
const FILE_ALL_ACCESS: u32 = 0x001F_01FF;
|
const FILE_ALL_ACCESS: u32 = 0x001F_01FF;
|
||||||
|
|
||||||
|
const SMB2_SHAREFLAG_MANUAL_CACHING: u32 = 0x00000000;
|
||||||
|
const SMB2_SHAREFLAG_ACCESS_BASED_DIRECTORY_ENUM: u32 = 0x00080000;
|
||||||
|
|
||||||
|
const SMB2_SHARE_CAP_DFS: u32 = 0x00000001;
|
||||||
|
|
||||||
pub async fn handle(
|
pub async fn handle(
|
||||||
server: &Arc<ServerState>,
|
server: &Arc<ServerState>,
|
||||||
conn: &Arc<Connection>,
|
conn: &Arc<Connection>,
|
||||||
@@ -119,6 +124,24 @@ pub async fn handle(
|
|||||||
tracing::info!(share = %share.name, uuid = %uuid, "Time Machine enabled");
|
tracing::info!(share = %share.name, uuid = %uuid, "Time Machine enabled");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let share_flags = if share.is_ipc {
|
||||||
|
0
|
||||||
|
} else {
|
||||||
|
SMB2_SHAREFLAG_MANUAL_CACHING | SMB2_SHAREFLAG_ACCESS_BASED_DIRECTORY_ENUM
|
||||||
|
};
|
||||||
|
|
||||||
|
let capabilities = if share.is_ipc {
|
||||||
|
0
|
||||||
|
} else {
|
||||||
|
0 // 普通磁盘 share,不是 DFS share
|
||||||
|
};
|
||||||
|
|
||||||
|
let capabilities = if share.is_ipc {
|
||||||
|
0
|
||||||
|
} else {
|
||||||
|
SMB2_SHARE_CAP_DFS // Basic DFS support for Finder
|
||||||
|
};
|
||||||
|
|
||||||
let resp = TreeConnectResponse {
|
let resp = TreeConnectResponse {
|
||||||
structure_size: 16,
|
structure_size: 16,
|
||||||
share_type: if share.is_ipc {
|
share_type: if share.is_ipc {
|
||||||
@@ -127,8 +150,8 @@ pub async fn handle(
|
|||||||
SHARE_TYPE_DISK
|
SHARE_TYPE_DISK
|
||||||
},
|
},
|
||||||
reserved: 0,
|
reserved: 0,
|
||||||
share_flags: 0,
|
share_flags,
|
||||||
capabilities: 0,
|
capabilities,
|
||||||
maximal_access,
|
maximal_access,
|
||||||
};
|
};
|
||||||
let mut buf = Vec::new();
|
let mut buf = Vec::new();
|
||||||
|
|||||||
3
vendor/smb-server/src/info_class.rs
vendored
3
vendor/smb-server/src/info_class.rs
vendored
@@ -371,8 +371,7 @@ pub fn encode_dir_entry(class: u8, entry: &DirEntry, file_index: u64) -> Vec<u8>
|
|||||||
out.push(0); // ShortNameLength
|
out.push(0); // ShortNameLength
|
||||||
out.push(0); // Reserved1
|
out.push(0); // Reserved1
|
||||||
out.extend_from_slice(&[0u8; 24]); // ShortName
|
out.extend_from_slice(&[0u8; 24]); // ShortName
|
||||||
out.extend_from_slice(&0u16.to_le_bytes()); // Reserved2
|
out.extend_from_slice(&file_index.to_le_bytes()); // FileId (8 bytes)
|
||||||
out.extend_from_slice(&file_index.to_le_bytes()); // FileId
|
|
||||||
out.extend_from_slice(&name_u16);
|
out.extend_from_slice(&name_u16);
|
||||||
out
|
out
|
||||||
}
|
}
|
||||||
|
|||||||
2
vendor/smb-server/src/server.rs
vendored
2
vendor/smb-server/src/server.rs
vendored
@@ -78,7 +78,7 @@ impl ShareBindings {
|
|||||||
Self::new(
|
Self::new(
|
||||||
"IPC$".to_string(),
|
"IPC$".to_string(),
|
||||||
Arc::new(crate::backend::NotSupportedBackend),
|
Arc::new(crate::backend::NotSupportedBackend),
|
||||||
ShareMode::PublicReadOnly,
|
ShareMode::Public, // 允许 named pipe communication (ReadWrite)
|
||||||
HashMap::new(),
|
HashMap::new(),
|
||||||
true,
|
true,
|
||||||
false,
|
false,
|
||||||
|
|||||||
2
vendor/smb-server/src/unicode_mapping.rs
vendored
2
vendor/smb-server/src/unicode_mapping.rs
vendored
@@ -8,7 +8,7 @@ pub const FRUIT_ENC_PRIVATE: bool = false;
|
|||||||
|
|
||||||
const APPLE_SLASH: u16 = 0xF026;
|
const APPLE_SLASH: u16 = 0xF026;
|
||||||
const APPLE_COLON: u16 = 0xF02A;
|
const APPLE_COLON: u16 = 0xF02A;
|
||||||
const APPLE_ASTERISK: u16 = 0xF02A;
|
const APPLE_ASTERISK: u16 = 0xF02B;
|
||||||
const APPLE_QUESTION: u16 = 0xF03F;
|
const APPLE_QUESTION: u16 = 0xF03F;
|
||||||
const APPLE_QUOTE: u16 = 0xF022;
|
const APPLE_QUOTE: u16 = 0xF022;
|
||||||
const APPLE_LESS_THAN: u16 = 0xF03C;
|
const APPLE_LESS_THAN: u16 = 0xF03C;
|
||||||
|
|||||||
Reference in New Issue
Block a user