use pretty_assertions::assert_eq;
use smb3::*;
fn assert_bytes_equal(expected: &[u8], actual: &[u8]) {
if expected != actual {
assert_eq!(
format!("{expected:x?}"),
format!("{actual:x?}"),
"expected != actual"
);
}
}
#[test]
fn negotiate_request() {
let header = RequestHeader {
protocol_id: ProtocolId::new(),
header_length: 64,
credit_charge: Credits(0),
channel_sequence: 0,
command: Command::Negotiate,
credits_requested: Credits(10),
flags: HeaderFlags::new(),
chain_offset: 0,
message_id: MessageId(0),
process_id: ProcessId(0xb75),
tree_id: TreeId(0),
session_id: SessionId(0),
signature: Signature([0; 16]),
};
let req = NegotiateRequest {
security_mode: SecurityMode::SIGNING_ENABLED,
capabilities: Capabilities::DFS
| Capabilities::LEASING
| Capabilities::LARGE_MTU
| Capabilities::MULTI_CHANNEL
| Capabilities::PERSISTENT_HANDLES
| Capabilities::DIRECTORY_LEASING
| Capabilities::ENCRYPTION,
client_guid: Uuid {
data1: u32::from_le_bytes([0xb2, 0x4b, 0xdf, 0xa8]),
data2: u16::from_le_bytes([0x77, 0x93]),
data3: u16::from_le_bytes([0xe6, 0x11]),
data4: [0xa0, 0x1d, 0x00, 0x0c, 0x29, 0x61, 0xf5, 0x5f],
},
dialects: vec![
Dialect::Smb2_0_2,
Dialect::Smb2_1,
Dialect::Smb3_0,
Dialect::Smb3_0_2,
Dialect::Smb3_1_1,
],
negotiate_contexts: vec![
NegotiateContext::Smb2PreauthIntegrityCapabilities(Smb2PreauthIntegrityCapabilities {
data_length: 38,
hash_algorithms: vec![HashAlgorithm::Sha512],
salt: vec![
0xd3, 0xe0, 0xee, 0xb4, 0xd9, 0xee, 0xe0, 0x3b, 0xc8, 0x5d, 0x56, 0xc6, 0x1b,
0x56, 0x7f, 0xf6, 0x6c, 0x56, 0x7e, 0x86, 0x82, 0xd1, 0x38, 0xcb, 0x24, 0x8b,
0x87, 0x73, 0x8f, 0xab, 0x80, 0xb4,
],
}),
NegotiateContext::Smb2EncryptionCapabilities(Smb2EncryptionCapabilities {
data_length: 6,
ciphers: vec![CipherId::Aes128Gcm, CipherId::Aes128Ccm],
}),
],
};
let actual = serde_smb::to_vec(&(&header, &req)).unwrap();
let expected = [
0xfe, 0x53, 0x4d, 0x42, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x75, 0x0b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x24, 0x00, 0x05, 0x00, 0x01, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00,
0x00, 0xb2, 0x4b, 0xdf, 0xa8, 0x77, 0x93, 0xe6, 0x11, 0xa0, 0x1d, 0x00, 0x0c, 0x29, 0x61,
0xf5, 0x5f, 0x70, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x02, 0x10, 0x02, 0x00,
0x03, 0x02, 0x03, 0x11, 0x03, 0x00, 0x00, 0x01, 0x00, 0x26, 0x00, 0x00, 0x00, 0x00, 0x00,
0x01, 0x00, 0x20, 0x00, 0x01, 0x00, 0xd3, 0xe0, 0xee, 0xb4, 0xd9, 0xee, 0xe0, 0x3b, 0xc8,
0x5d, 0x56, 0xc6, 0x1b, 0x56, 0x7f, 0xf6, 0x6c, 0x56, 0x7e, 0x86, 0x82, 0xd1, 0x38, 0xcb,
0x24, 0x8b, 0x87, 0x73, 0x8f, 0xab, 0x80, 0xb4, 0x00, 0x00, 0x02, 0x00, 0x06, 0x00, 0x00,
0x00, 0x00, 0x00, 0x02, 0x00, 0x02, 0x00, 0x01, 0x00,
];
assert_bytes_equal(&expected, &actual);
let deserialized: (RequestHeader, NegotiateRequest) =
serde_smb::from_slice(&expected[..]).unwrap();
assert_eq!(deserialized, (header, req));
}
#[test]
fn negotiate_response() {
let header = ResponseHeader {
protocol_id: ProtocolId::new(),
header_length: 64,
credit_charge: Credits(0),
nt_status: NtStatus::Success,
command: Command::Negotiate,
credits_granted: Credits(1),
flags: HeaderFlags::new().with_response(true),
chain_offset: 0,
message_id: MessageId(0),
process_id: ProcessId(0),
tree_id: TreeId(0),
session_id: SessionId(0),
signature: Signature([0; 16]),
};
let req = NegotiateResponse {
security_mode: SecurityMode::SIGNING_ENABLED,
dialect: Dialect::Smb3_1_1,
server_guid: Uuid {
data1: u32::from_le_bytes([0x6e, 0x61, 0x73, 0x75]),
data2: 0,
data3: 0,
data4: [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00],
},
capabilities: Capabilities::DFS | Capabilities::LEASING | Capabilities::LARGE_MTU,
max_transaction_size: 8388608,
max_read_size: 8388608,
max_write_size: 8388608,
current_time: Time {
intervals: 0x01d9ed17799268d8,
},
boot_time: Time { intervals: 0 },
security_blob: vec![
0x60, 0x48, 0x06, 0x06, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x02, 0xa0, 0x3e, 0x30, 0x3c,
0xa0, 0x0e, 0x30, 0x0c, 0x06, 0x0a, 0x2b, 0x06, 0x01, 0x04, 0x01, 0x82, 0x37, 0x02,
0x02, 0x0a, 0xa3, 0x2a, 0x30, 0x28, 0xa0, 0x26, 0x1b, 0x24, 0x6e, 0x6f, 0x74, 0x5f,
0x64, 0x65, 0x66, 0x69, 0x6e, 0x65, 0x64, 0x5f, 0x69, 0x6e, 0x5f, 0x52, 0x46, 0x43,
0x34, 0x31, 0x37, 0x38, 0x40, 0x70, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x5f, 0x69, 0x67,
0x6e, 0x6f, 0x72, 0x65,
],
negotiate_contexts: vec![NegotiateContext::Smb2PreauthIntegrityCapabilities(
Smb2PreauthIntegrityCapabilities {
data_length: 38,
hash_algorithms: vec![HashAlgorithm::Sha512],
salt: vec![
0x80, 0x13, 0x36, 0x10, 0xa3, 0xb5, 0xab, 0xb5, 0xe4, 0x02, 0xd7, 0xc8, 0x3f,
0x4e, 0xb6, 0x02, 0x06, 0x6c, 0x11, 0xd6, 0xe7, 0x4d, 0x72, 0xb3, 0x25, 0xe9,
0x29, 0x2e, 0xee, 0x82, 0x40, 0xab,
],
},
)],
};
let actual = serde_smb::to_vec(&(&header, &req)).unwrap();
let expected = [
0xfe, 0x53, 0x4d, 0x42, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x41, 0x00, 0x01, 0x00, 0x11, 0x03, 0x01, 0x00, 0x6e, 0x61, 0x73,
0x75, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00,
0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0xd8,
0x68, 0x92, 0x79, 0x17, 0xed, 0xd9, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x80, 0x00, 0x4a, 0x00, 0xd0, 0x00, 0x00, 0x00, 0x60, 0x48, 0x06, 0x06, 0x2b, 0x06, 0x01,
0x05, 0x05, 0x02, 0xa0, 0x3e, 0x30, 0x3c, 0xa0, 0x0e, 0x30, 0x0c, 0x06, 0x0a, 0x2b, 0x06,
0x01, 0x04, 0x01, 0x82, 0x37, 0x02, 0x02, 0x0a, 0xa3, 0x2a, 0x30, 0x28, 0xa0, 0x26, 0x1b,
0x24, 0x6e, 0x6f, 0x74, 0x5f, 0x64, 0x65, 0x66, 0x69, 0x6e, 0x65, 0x64, 0x5f, 0x69, 0x6e,
0x5f, 0x52, 0x46, 0x43, 0x34, 0x31, 0x37, 0x38, 0x40, 0x70, 0x6c, 0x65, 0x61, 0x73, 0x65,
0x5f, 0x69, 0x67, 0x6e, 0x6f, 0x72, 0x65, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00,
0x26, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x20, 0x00, 0x01, 0x00, 0x80, 0x13, 0x36,
0x10, 0xa3, 0xb5, 0xab, 0xb5, 0xe4, 0x02, 0xd7, 0xc8, 0x3f, 0x4e, 0xb6, 0x02, 0x06, 0x6c,
0x11, 0xd6, 0xe7, 0x4d, 0x72, 0xb3, 0x25, 0xe9, 0x29, 0x2e, 0xee, 0x82, 0x40, 0xab,
];
assert_bytes_equal(&expected, &actual);
let deserialized: (ResponseHeader, NegotiateResponse) =
serde_smb::from_slice(&expected[..]).unwrap();
assert_eq!(deserialized, (header, req));
}
#[test]
fn session_setup_request() {
let header = RequestHeader {
protocol_id: ProtocolId::new(),
header_length: 64,
credit_charge: Credits(0),
channel_sequence: 0,
command: Command::SessionSetup,
credits_requested: Credits(130),
flags: HeaderFlags::new(),
chain_offset: 0,
message_id: MessageId(1),
process_id: ProcessId(0xb75),
tree_id: TreeId(0),
session_id: SessionId(0),
signature: Signature([0; 16]),
};
let req = SessionSetupRequest {
session_binding_request: false,
security_mode: SecurityMode::SIGNING_ENABLED,
capabilities: Capabilities::DFS,
channel: 0,
previous_session_id: SessionId(0),
security_blob: vec![
0x4e, 0x54, 0x4c, 0x4d, 0x53, 0x53, 0x50, 0x00, 0x01, 0x00, 0x00, 0x00, 0x25, 0x02,
0x08, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00,
],
};
let actual = serde_smb::to_vec(&(&header, &req)).unwrap();
let expected = [
0xfe, 0x53, 0x4d, 0x42, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x82,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x75, 0x0b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x19, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x58, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4e, 0x54,
0x4c, 0x4d, 0x53, 0x53, 0x50, 0x00, 0x01, 0x00, 0x00, 0x00, 0x25, 0x02, 0x08, 0xe0, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
];
assert_bytes_equal(&expected, &actual);
let deserialized: (RequestHeader, SessionSetupRequest) =
serde_smb::from_slice(&expected[..]).unwrap();
assert_eq!(deserialized, (header, req));
}
#[test]
fn query_directory_response() {
let header = ResponseHeader {
protocol_id: ProtocolId::new(),
header_length: 64,
credit_charge: Credits(1),
nt_status: NtStatus::Success,
command: Command::QueryDirectory,
credits_granted: Credits(20),
flags: HeaderFlags::new().with_response(true).with_chained(true),
chain_offset: 0,
message_id: MessageId(735),
process_id: ProcessId(0xee62),
tree_id: TreeId(0x72b943ef),
session_id: SessionId(0x13abe4e9),
signature: Signature([0; 16]),
};
let res = QueryDirectoryResponse {
entries: vec![
FileIdBothDirectoryInformation {
file_index: 0,
creation_time: Time {
intervals: 0x01d9fb8c0ef7c013,
},
last_access_time: Time {
intervals: 0x01d9fb8c0fbe1e52,
},
last_write_time: Time {
intervals: 0x01d9fb8c14ad922f,
},
change_time: Time {
intervals: 0x01d9fb8c14ad922f,
},
end_of_file: 0,
allocation_size: 0,
file_attributes: FileAttributes::DIRECTORY,
ea_size: 0,
file_id: 0xf5084f8,
file_name: ".".into(),
}
.into(),
FileIdBothDirectoryInformation {
file_index: 0,
creation_time: Time {
intervals: 0x01d989bbd274e83a,
},
last_access_time: Time {
intervals: 0x01d9fb8c0fa2a6ef,
},
last_write_time: Time {
intervals: 0x01d9fb8c0efc53f9,
},
change_time: Time {
intervals: 0x01d9fb8c0efc53f9,
},
end_of_file: 0,
allocation_size: 0,
file_attributes: FileAttributes::DIRECTORY | FileAttributes::ARCHIVE,
ea_size: 0,
file_id: 0xeee0001,
file_name: "..".into(),
}
.into(),
FileIdBothDirectoryInformation {
file_index: 0,
creation_time: Time {
intervals: 0x01d9fb8c14a8fe49,
},
last_access_time: Time {
intervals: 0x01d9fb8c14a85f4a,
},
last_write_time: Time {
intervals: 0x01d9fb8c14a85f4a,
},
change_time: Time {
intervals: 0x01d9fb8c14a85f4a,
},
end_of_file: 0,
allocation_size: 0,
file_attributes: FileAttributes::ARCHIVE,
ea_size: 0,
file_id: 0xf5084fa,
file_name: "b".into(),
}
.into(),
FileIdBothDirectoryInformation {
file_index: 0,
creation_time: Time {
intervals: 0x01d9fb8c14ad922f,
},
last_access_time: Time {
intervals: 0x01d9fb8c14aca50c,
},
last_write_time: Time {
intervals: 0x01d9fb8c14aca50c,
},
change_time: Time {
intervals: 0x01d9fb8c14aca50c,
},
end_of_file: 0,
allocation_size: 0,
file_attributes: FileAttributes::ARCHIVE,
ea_size: 0,
file_id: 0xf5084fb,
file_name: "c".into(),
}
.into(),
FileIdBothDirectoryInformation {
file_index: 0,
creation_time: Time {
intervals: 0x01d9fb8c14a5f105,
},
last_access_time: Time {
intervals: 0x01d9fb8c14a5ee49,
},
last_write_time: Time {
intervals: 0x01d9fb8c14a5ee49,
},
change_time: Time {
intervals: 0x01d9fb8c14a5ee49,
},
end_of_file: 0,
allocation_size: 0,
file_attributes: FileAttributes::ARCHIVE,
ea_size: 0,
file_id: 0xf5084f9,
file_name: "a".into(),
}
.into(),
],
};
let actual = serde_smb::to_vec(&(&header, &res)).unwrap();
let expected = [
0xfe, 0x53, 0x4d, 0x42, 0x40, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x14,
0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xdf, 0x02, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x62, 0xee, 0x00, 0x00, 0xef, 0x43, 0xb9, 0x72, 0xe9, 0xe4, 0xab, 0x13, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x09, 0x00, 0x48, 0x00, 0xb2, 0x01, 0x00, 0x00, 0x58, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x13, 0xc0, 0xf7, 0x0e, 0x8c, 0xfb, 0xd9, 0x01, 0x52, 0x1e,
0xbe, 0x0f, 0x8c, 0xfb, 0xd9, 0x01, 0x2f, 0x92, 0xad, 0x14, 0x8c, 0xfb, 0xd9, 0x01, 0x2f,
0x92, 0xad, 0x14, 0x8c, 0xfb, 0xd9, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x84, 0x50, 0x0f, 0x00, 0x00,
0x00, 0x00, 0x2e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x58, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x3a, 0xe8, 0x74, 0xd2, 0xbb, 0x89, 0xd9, 0x01, 0xef, 0xa6, 0xa2, 0x0f,
0x8c, 0xfb, 0xd9, 0x01, 0xf9, 0x53, 0xfc, 0x0e, 0x8c, 0xfb, 0xd9, 0x01, 0xf9, 0x53, 0xfc,
0x0e, 0x8c, 0xfb, 0xd9, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0xee, 0x0e, 0x00, 0x00, 0x00, 0x00,
0x2e, 0x00, 0x2e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x58, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x49, 0xfe, 0xa8, 0x14, 0x8c, 0xfb, 0xd9, 0x01, 0x4a, 0x5f, 0xa8, 0x14, 0x8c, 0xfb,
0xd9, 0x01, 0x4a, 0x5f, 0xa8, 0x14, 0x8c, 0xfb, 0xd9, 0x01, 0x4a, 0x5f, 0xa8, 0x14, 0x8c,
0xfb, 0xd9, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0xfa, 0x84, 0x50, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x62, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x58, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2f,
0x92, 0xad, 0x14, 0x8c, 0xfb, 0xd9, 0x01, 0x0c, 0xa5, 0xac, 0x14, 0x8c, 0xfb, 0xd9, 0x01,
0x0c, 0xa5, 0xac, 0x14, 0x8c, 0xfb, 0xd9, 0x01, 0x0c, 0xa5, 0xac, 0x14, 0x8c, 0xfb, 0xd9,
0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0xfb, 0x84, 0x50, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x63, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0xf1, 0xa5,
0x14, 0x8c, 0xfb, 0xd9, 0x01, 0x49, 0xee, 0xa5, 0x14, 0x8c, 0xfb, 0xd9, 0x01, 0x49, 0xee,
0xa5, 0x14, 0x8c, 0xfb, 0xd9, 0x01, 0x49, 0xee, 0xa5, 0x14, 0x8c, 0xfb, 0xd9, 0x01, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x20, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0xf9, 0x84, 0x50, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x61, 0x00,
];
assert_bytes_equal(&expected, &actual);
let deserialized: (
ResponseHeader,
QueryDirectoryResponse<FileIdBothDirectoryInformation>,
) = serde_smb::from_slice(&expected[..]).unwrap();
assert_eq!(deserialized, (header, res), "actual != expected");
}
#[test]
fn create_request() {
let header = RequestHeader {
protocol_id: ProtocolId::new(),
header_length: 64,
credit_charge: Credits(1),
channel_sequence: 0,
command: Command::Create,
credits_requested: Credits(10),
flags: HeaderFlags::new(),
chain_offset: 0,
message_id: MessageId(2094),
process_id: ProcessId(0xe3a),
tree_id: TreeId(0x79ffa471),
session_id: SessionId(0xb19cb071),
signature: Signature([0; 16]),
};
let req = CreateRequest {
requested_oplock_level: OplockLevel::Lease,
impersonation_level: ImpersonationLevel::Impersonation,
desired_access: AccessMask::FILE_READ_ATTRIBUTES | AccessMask::GENERIC_WRITE,
file_attributes: FileAttributes::empty(),
share_access: FileShareAccess::READ | FileShareAccess::WRITE | FileShareAccess::DELETE,
create_disposition: FileCreateDisposition::OverwriteIf,
create_options: FileCreateOptions::NON_DIRECTORY_FILE,
name: "test\\A_FILE".into(),
create_contexts: vec![
CreateContext::RequestLease(RequestLease {
lease_key: LeaseKey([
0x3e, 0x0c, 0xde, 0xd3, 0xd1, 0xbc, 0x40, 0x37, 0xb5, 0x45, 0x6b, 0xf2, 0xa1,
0x70, 0xd9, 0xcb,
]),
lease_state: LeaseState::READ_CACHING
| LeaseState::HANDLE_CACHING
| LeaseState::WRITE_CACHING,
flags: LeaseFlags::empty(),
parent_lease_key: LeaseKey([0; 16]),
epoch: 0,
})
.into(),
CreateContext::DurableHandleRequest.into(),
CreateContext::QueryOnDiskId.into(),
],
};
let actual = serde_smb::to_vec(&(&header, &req)).unwrap();
let expected = [
0xfe, 0x53, 0x4d, 0x42, 0x40, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x0a,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2e, 0x08, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x3a, 0x0e, 0x00, 0x00, 0x71, 0xa4, 0xff, 0x79, 0x71, 0xb0, 0x9c, 0xb1, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x39, 0x00, 0x00, 0xff, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00,
0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x40,
0x00, 0x00, 0x00, 0x78, 0x00, 0x16, 0x00, 0x90, 0x00, 0x00, 0x00, 0x90, 0x00, 0x00, 0x00,
0x74, 0x00, 0x65, 0x00, 0x73, 0x00, 0x74, 0x00, 0x5c, 0x00, 0x41, 0x00, 0x5f, 0x00, 0x46,
0x00, 0x49, 0x00, 0x4c, 0x00, 0x45, 0x00, 0x00, 0x00, 0x50, 0x00, 0x00, 0x00, 0x10, 0x00,
0x04, 0x00, 0x00, 0x00, 0x18, 0x00, 0x34, 0x00, 0x00, 0x00, 0x52, 0x71, 0x4c, 0x73, 0x00,
0x00, 0x00, 0x00, 0x3e, 0x0c, 0xde, 0xd3, 0xd1, 0xbc, 0x40, 0x37, 0xb5, 0x45, 0x6b, 0xf2,
0xa1, 0x70, 0xd9, 0xcb, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x28,
0x00, 0x00, 0x00, 0x10, 0x00, 0x04, 0x00, 0x00, 0x00, 0x18, 0x00, 0x10, 0x00, 0x00, 0x00,
0x44, 0x48, 0x6e, 0x51, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00,
0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x51, 0x46, 0x69, 0x64, 0x00,
0x00, 0x00, 0x00,
];
assert_bytes_equal(&expected, &actual);
let deserialized: (RequestHeader, CreateRequest) =
serde_smb::from_slice(&expected[..]).unwrap();
assert_eq!(deserialized, (header, req));
}
#[test]
fn create_response() {
let header = ResponseHeader {
protocol_id: ProtocolId::new(),
header_length: 64,
credit_charge: Credits(1),
nt_status: NtStatus::Success,
command: Command::Create,
credits_granted: Credits(64),
flags: HeaderFlags::new().with_response(true).with_signing(true),
chain_offset: 0,
message_id: MessageId(4),
process_id: ProcessId(0),
tree_id: TreeId(0x9c0298a7),
session_id: SessionId(0x3a7db10a),
signature: Signature([
0x03, 0xff, 0x9f, 0xef, 0x4e, 0x00, 0x0f, 0x21, 0xe7, 0x09, 0x7a, 0x51, 0x56, 0x60,
0x6d, 0xe2,
]),
};
let res = CreateResponse {
oplock_level: OplockLevel::None,
reparse_point: false,
create_action: FileCreateAction::Created,
create_time: Time {
intervals: 0x01d9ff2eee773b2e,
},
last_access_time: Time {
intervals: 0x01d9ff2eee773b2e,
},
last_write_time: Time {
intervals: 0x01d9ff2eee773b2e,
},
change_time: Time {
intervals: 0x01d9ff2eee773b2e,
},
allocation_size: 0,
end_of_file: 0,
file_attributes: FileAttributes::ARCHIVE,
file_id: FileId {
persistent: 0x00000000337aedf0,
volatile: 0x00000000ba3ba09c,
},
create_contexts: vec![],
};
let actual = serde_smb::to_vec(&(&header, &res)).unwrap();
let expected = [
0xfe, 0x53, 0x4d, 0x42, 0x40, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x40,
0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa7, 0x98, 0x02, 0x9c, 0x0a, 0xb1, 0x7d, 0x3a, 0x00,
0x00, 0x00, 0x00, 0x03, 0xff, 0x9f, 0xef, 0x4e, 0x00, 0x0f, 0x21, 0xe7, 0x09, 0x7a, 0x51,
0x56, 0x60, 0x6d, 0xe2, 0x59, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x2e, 0x3b, 0x77,
0xee, 0x2e, 0xff, 0xd9, 0x01, 0x2e, 0x3b, 0x77, 0xee, 0x2e, 0xff, 0xd9, 0x01, 0x2e, 0x3b,
0x77, 0xee, 0x2e, 0xff, 0xd9, 0x01, 0x2e, 0x3b, 0x77, 0xee, 0x2e, 0xff, 0xd9, 0x01, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0xed, 0x7a, 0x33, 0x00, 0x00, 0x00,
0x00, 0x9c, 0xa0, 0x3b, 0xba, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00,
];
assert_bytes_equal(&expected, &actual);
let deserialized: (ResponseHeader, CreateResponse) =
serde_smb::from_slice(&expected[..]).unwrap();
assert_eq!(deserialized, (header, res), "actual != expected");
}