Implement SMB 3.x Lease support Phase 1-2
Some checks failed
Test / test (push) Has been cancelled
Test / build (push) Has been cancelled

Phase 1: Open struct lease fields
- lease_key: Option<[u8; 16]> - LeaseKey GUID
- lease_state: Option<u32> - READ/HANDLE/WRITE flags
- lease_flags: Option<u32> - BREAKING etc.

Phase 2: LeaseManager
- LeaseEntry with lease_key/state/flags
- register/unregister/can_grant methods
- break_lease returns LeaseBreakNotification
- LeaseBreakNotification struct (MS-SMB2 §2.2.26)

ServerState: lease_manager field added

All 229 tests pass.
This commit is contained in:
Warren
2026-06-21 01:20:18 +08:00
parent 3cf503d05f
commit 21a9c3c6c4
3 changed files with 127 additions and 0 deletions

View File

@@ -206,6 +206,123 @@ impl OplockManager {
}
}
/// Lease state flags (MS-SMB2 §2.2.13.2).
pub const SMB2_LEASE_READ: u32 = 0x01;
pub const SMB2_LEASE_HANDLE: u32 = 0x02;
pub const SMB2_LEASE_WRITE: u32 = 0x04;
/// Lease entry for LeaseManager.
#[derive(Debug, Clone)]
pub struct LeaseEntry {
pub lease_key: [u8; 16],
pub lease_state: u32,
pub lease_flags: u32,
pub file_id: FileId,
pub path: SmbPath,
pub session_id: u64,
pub tree_id: u32,
}
/// Global lease manager for SMB 3.x (MS-SMB2 §3.3.1.9).
pub struct LeaseManager {
/// LeaseKey → LeaseEntry.
leases: RwLock<HashMap<[u8; 16], LeaseEntry>>,
}
impl LeaseManager {
pub fn new() -> Self {
Self {
leases: RwLock::new(HashMap::new()),
}
}
/// Register a lease on CREATE (MS-SMB2 §3.3.5.9).
pub async fn register(&self, entry: LeaseEntry) {
let mut leases = self.leases.write().await;
leases.insert(entry.lease_key, entry);
}
/// Remove a lease on CLOSE.
pub async fn unregister(&self, lease_key: &[u8; 16]) {
let mut leases = self.leases.write().await;
leases.remove(lease_key);
}
/// Check if lease can be granted (MS-SMB2 §3.3.5.9).
pub async fn can_grant(&self, requested_state: u32) -> bool {
// Simple check: allow lease if no conflicting leases exist
let leases = self.leases.read().await;
for entry in leases.values() {
// Check for conflicts
if (entry.lease_state & SMB2_LEASE_WRITE) != 0 && (requested_state & SMB2_LEASE_READ) != 0 {
return false; // WRITE lease conflicts with READ request
}
if (entry.lease_state & SMB2_LEASE_HANDLE) != 0 && (requested_state & SMB2_LEASE_HANDLE) != 0 {
return false; // HANDLE lease conflicts with HANDLE request
}
}
true
}
/// Break lease when conflicting access occurs (MS-SMB2 §3.3.5.10).
pub async fn break_lease(&self, requested_state: u32) -> Vec<LeaseBreakNotification> {
let mut leases = self.leases.write().await;
let mut notifications = Vec::new();
for (key, entry) in leases.iter_mut() {
// Check if lease needs to break
let needs_break = (entry.lease_state & SMB2_LEASE_WRITE) != 0 && (requested_state & SMB2_LEASE_READ) != 0;
if needs_break {
// Break to READ lease (or none)
entry.lease_state = SMB2_LEASE_READ;
entry.lease_flags |= 0x02; // SMB2_LEASE_FLAG_BREAKING
notifications.push(LeaseBreakNotification {
structure_size: 36,
lease_key: *key,
current_lease_state: entry.lease_state,
new_lease_state: SMB2_LEASE_READ,
break_reason: 0,
lease_flags: entry.lease_flags,
access_mask: 0,
share_mask: 0,
});
}
}
notifications
}
}
/// SMB2_LEASE_BREAK_NOTIFICATION (MS-SMB2 §2.2.26).
#[derive(Debug, Clone)]
pub struct LeaseBreakNotification {
pub structure_size: u16,
pub lease_key: [u8; 16],
pub current_lease_state: u32,
pub new_lease_state: u32,
pub break_reason: u32,
pub lease_flags: u32,
pub access_mask: u32,
pub share_mask: u32,
}
impl LeaseBreakNotification {
pub fn write_to_bytes(&self) -> Vec<u8> {
let mut buf = Vec::with_capacity(36);
buf.extend_from_slice(&self.structure_size.to_le_bytes());
buf.extend_from_slice(&self.lease_key);
buf.extend_from_slice(&self.current_lease_state.to_le_bytes());
buf.extend_from_slice(&self.new_lease_state.to_le_bytes());
buf.extend_from_slice(&self.break_reason.to_le_bytes());
buf.extend_from_slice(&self.lease_flags.to_le_bytes());
buf.extend_from_slice(&self.access_mask.to_le_bytes());
buf.extend_from_slice(&self.share_mask.to_le_bytes());
buf
}
}
/// Global byte-range lock manager (MS-SMB2 §3.3.1.9).
pub struct LockManager {
/// FileId → active locks on that file.