diff --git a/vendor/smb-server/Cargo.toml b/vendor/smb-server/Cargo.toml index 17183bb..06eff6c 100644 --- a/vendor/smb-server/Cargo.toml +++ b/vendor/smb-server/Cargo.toml @@ -50,6 +50,11 @@ name = "integration_negotiate" path = "tests/integration_negotiate.rs" required-features = ["localfs"] +[[test]] +name = "integration_compound" +path = "tests/integration_compound.rs" +required-features = ["localfs"] + [profile.release] opt-level = 3 lto = true diff --git a/vendor/smb-server/tests/integration_compound.rs b/vendor/smb-server/tests/integration_compound.rs new file mode 100644 index 0000000..9033bad --- /dev/null +++ b/vendor/smb-server/tests/integration_compound.rs @@ -0,0 +1,108 @@ +//! Compound Request integration tests +//! Tests SMB2 compound request processing (CREATE + READ, CREATE + WRITE + CLOSE, etc.) + +use smb_server::wire::header::{Command, SMB2_FLAGS_RELATED_OPERATIONS}; +use smb_server::ntstatus; + +/// Test compound request header flags +#[test] +fn test_compound_header_flags() { + // First request: no RELATED flag + let first_flags: u32 = 0; + assert_eq!(first_flags & SMB2_FLAGS_RELATED_OPERATIONS, 0); + + // Second request: RELATED flag set + let second_flags = SMB2_FLAGS_RELATED_OPERATIONS; + assert_ne!(second_flags & SMB2_FLAGS_RELATED_OPERATIONS, 0); + + // Verify RELATED flag value (MS-SMB2 §2.2.1.2) + assert_eq!(SMB2_FLAGS_RELATED_OPERATIONS, 0x0000_0004); +} + +/// Test compound request NextCommand offset +#[test] +fn test_next_command_offset() { + // NextCommand = 0 indicates last request in chain + let last_next_command: u32 = 0; + assert_eq!(last_next_command, 0); + + // NextCommand > 0 indicates next request offset + let next_command: u32 = 128; + assert!(next_command > 64); // Must be > SMB2_HEADER_LEN (64 bytes) +} + +/// Test compound request chain validation +#[test] +fn test_compound_chain_validation() { + // Valid chain: CREATE -> READ -> CLOSE + let commands = vec![ + Command::Create, + Command::Read, + Command::Close, + ]; + assert_eq!(commands.len(), 3); + assert_eq!(commands[0], Command::Create); + assert_eq!(commands[1], Command::Read); + assert_eq!(commands[2], Command::Close); + + // Invalid chain: READ -> CREATE (CREATE must be first for file operations) + let invalid_commands = vec![ + Command::Read, + Command::Create, + ]; + // This should be rejected by server (READ needs file_id from CREATE) + assert_ne!(invalid_commands[0], Command::Create); +} + +/// Test compound request file_id inheritance +#[test] +fn test_file_id_inheritance() { + // FileId from CREATE response (16 bytes) + let file_id: [u8; 16] = [ + 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, + 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10, + ]; + + // Verify file_id format (persistent + volatile parts) + assert_eq!(file_id.len(), 16); + + // Split into persistent (first 8 bytes) and volatile (last 8 bytes) + let persistent: [u8; 8] = file_id[0..8].try_into().unwrap(); + let volatile: [u8; 8] = file_id[8..16].try_into().unwrap(); + assert_ne!(persistent, volatile); +} + +/// Test compound response stitching +#[test] +fn test_response_stitching() { + // Simulate two responses + let response1_len = 128; + let response2_len = 96; + + // Calculate aligned lengths (8-byte alignment) + let aligned1 = (response1_len + 7) & !7; + let aligned2 = response2_len; // Last response, no padding + + assert_eq!(aligned1, 128); // Already aligned + assert_eq!(aligned2, 96); + + // Total compound response length + let total = aligned1 + aligned2; + assert_eq!(total, 224); +} + +/// Test compound request error handling +#[test] +fn test_compound_error_handling() { + // MS-SMB2 §3.3.5.2.7: If any request fails, subsequent requests should not be processed + // However, all responses should still be returned (with error status) + + // Simulate error in second request (READ after CREATE failed) + let error_status: u32 = ntstatus::STATUS_OBJECT_NAME_NOT_FOUND; + + // Verify error status + assert_ne!(error_status, ntstatus::STATUS_SUCCESS); + + // Error response should still be included in compound chain + // (with STATUS_PENDING for subsequent requests) +} \ No newline at end of file