From 344d13435e0fdce7790c784c244060d3a3e05dbc Mon Sep 17 00:00:00 2001 From: Warren Date: Sun, 21 Jun 2026 01:23:32 +0800 Subject: [PATCH] Implement SMB 3.x Lease support Phase 3 - CREATE handler parse RqLs create context - Extract LeaseKey (16 bytes) + LeaseState (4 bytes) - Check can_grant() before registration - Register with LeaseManager - Set Open.lease_key/lease_state fields All 229 tests pass. --- vendor/smb-server/src/handlers/create.rs | 54 +++++++++++++++++++++++- 1 file changed, 53 insertions(+), 1 deletion(-) diff --git a/vendor/smb-server/src/handlers/create.rs b/vendor/smb-server/src/handlers/create.rs index b223f7c..f0d3804 100644 --- a/vendor/smb-server/src/handlers/create.rs +++ b/vendor/smb-server/src/handlers/create.rs @@ -182,6 +182,49 @@ pub async fn handle( }).await; } + // Phase 3: Check for lease request in create contexts (SMB 3.x) + let (lease_key, lease_state) = if !req.create_contexts.is_empty() { + use crate::proto::messages::CreateContext; + let contexts = CreateContext::parse_chain(&req.create_contexts).unwrap_or_default(); + + // Find RqLs (REQUEST_LEASE) context + let lease_ctx = contexts.iter().find(|ctx| ctx.name == CreateContext::NAME_RQLS); + + if let Some(ctx) = lease_ctx { + // Parse lease request (MS-SMB2 ยง2.2.13.2) + // Data format: LeaseKey (16 bytes) + LeaseState (4 bytes) + LeaseFlags (4 bytes) + if ctx.data.len() >= 24 { + let lease_key_bytes: [u8; 16] = ctx.data[0..16].try_into().unwrap_or([0; 16]); + let lease_state = u32::from_le_bytes([ctx.data[16], ctx.data[17], ctx.data[18], ctx.data[19]]); + + // Check if lease can be granted + if server.lease_manager.can_grant(lease_state).await { + // Register lease + use crate::oplock::LeaseEntry; + server.lease_manager.register(LeaseEntry { + lease_key: lease_key_bytes, + lease_state, + lease_flags: 0, + file_id, + path: path.clone(), + session_id: hdr.session_id, + tree_id: tree.id, + }).await; + + (Some(lease_key_bytes), Some(lease_state)) + } else { + (None, None) + } + } else { + (None, None) + } + } else { + (None, None) + } + } else { + (None, None) + }; + let open = Open::new( file_id, handle, @@ -192,8 +235,17 @@ pub async fn handle( granted_oplock, // oplock_level req.share_access, // share_access ); + + // Phase 3: Set lease fields if granted let open_arc = Arc::new(tokio::sync::RwLock::new(open)); - tree.opens.write().await.insert(file_id, open_arc); + if lease_key.is_some() { + let mut open_mut = open_arc.write().await; + open_mut.lease_key = lease_key; + open_mut.lease_state = lease_state; + open_mut.lease_flags = Some(0); + } + + tree.opens.write().await.insert(file_id, open_arc.clone()); drop(tree); let create_action = match intent {