use crate::smb2::Smb2Header;
use crate::Result;
use nom::bytes::complete::{tag, take};
use nom::number::complete::{le_u16, le_u32, le_u64};
use std::convert::TryInto;
use crate::smb2::SMB2_HEADER_SIZE;
#[derive(Clone, Debug, Default, PartialEq)]
pub struct Smb2NegResp {
pub header: Smb2Header,
pub body: Smb2NegRespBody,
}
impl Smb2NegResp {
pub fn new(header: Smb2Header, body: Smb2NegRespBody) -> Self {
return Self { header, body };
}
pub fn parse(raw: &[u8]) -> Result<Self> {
let (raw, header) = Smb2Header::parse(raw)?;
let (_, body) = Smb2NegRespBody::parse(raw)?;
return Ok(Self { header, body });
}
}
const SMB2_NEG_RESP_SIZE: &'static [u8] = &[65, 0];
#[derive(Clone, Debug, Default, PartialEq)]
pub struct Smb2NegRespBody {
pub security_mode: u16,
pub dialect_revision: u16,
pub server_guid: [u8; 16],
pub capabilities: u32,
pub max_transact_size: u32,
pub max_read_size: u32,
pub max_write_size: u32,
pub system_time: u64,
pub server_start_time: u64,
pub buffer: Vec<u8>,
}
impl Smb2NegRespBody {
pub fn parse(raw: &[u8]) -> Result<(&[u8], Self)> {
let (raw, _) = tag(SMB2_NEG_RESP_SIZE)(raw)?;
let (raw, security_mode) = le_u16(raw)?;
let (raw, dialect_revision) = le_u16(raw)?;
let (raw, _) = le_u16(raw)?;
let (raw, server_guid) = take(16usize)(raw)?;
let (raw, capabilities) = le_u32(raw)?;
let (raw, max_transact_size) = le_u32(raw)?;
let (raw, max_read_size) = le_u32(raw)?;
let (raw, max_write_size) = le_u32(raw)?;
let (raw, system_time) = le_u64(raw)?;
let (raw, server_start_time) = le_u64(raw)?;
let (raw, sec_offset) = le_u16(raw)?;
let (raw, sec_length) = le_u16(raw)?;
let (raw, _) = le_u32(raw)?;
let sec_offset = SMB2_HEADER_SIZE + 64 - sec_offset;
let (raw, _) = take(sec_offset as usize)(raw)?;
let (raw, buffer) = take(sec_length as usize)(raw)?;
return Ok((
raw,
Self {
security_mode,
dialect_revision,
server_guid: server_guid.try_into().unwrap(),
capabilities,
max_transact_size,
max_read_size,
max_write_size,
system_time,
server_start_time,
buffer: buffer.to_vec(),
},
));
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::smb2::negotiate::SMB2_NEGOTIATE_SIGNING_ENABLED;
const SMB2_DIA_REV_2FF: u16 = 0x2ff;
const SMB2_GLOBAL_CAP_DFS: u32 = 0x00000001;
const SMB2_GLOBAL_CAP_LEASING: u32 = 0x00000002;
const SMB2_GLOBAL_CAP_LARGE_MTU: u32 = 0x00000004;
const RAW_SMB2_NEG_RESP_BODY: &'static [u8] = &[
0x41, 0x00, 0x01, 0x00, 0xff, 0x02, 0x00, 0x00, 0x07, 0x29, 0x91, 0x3b,
0x4f, 0xa6, 0x4f, 0x4e, 0x8a, 0xb9, 0x44, 0xc5, 0xca, 0x55, 0x2c, 0x04,
0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00,
0x00, 0x00, 0x80, 0x00, 0x2a, 0xac, 0xfd, 0xfc, 0x76, 0xef, 0xd6, 0x01,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x78, 0x00,
0x00, 0x00, 0x00, 0x00, 0x60, 0x76, 0x06, 0x06, 0x2b, 0x06, 0x01, 0x05,
0x05, 0x02, 0xa0, 0x6c, 0x30, 0x6a, 0xa0, 0x3c, 0x30, 0x3a, 0x06, 0x0a,
0x2b, 0x06, 0x01, 0x04, 0x01, 0x82, 0x37, 0x02, 0x02, 0x1e, 0x06, 0x09,
0x2a, 0x86, 0x48, 0x82, 0xf7, 0x12, 0x01, 0x02, 0x02, 0x06, 0x09, 0x2a,
0x86, 0x48, 0x86, 0xf7, 0x12, 0x01, 0x02, 0x02, 0x06, 0x0a, 0x2a, 0x86,
0x48, 0x86, 0xf7, 0x12, 0x01, 0x02, 0x02, 0x03, 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,
];
#[test]
fn test_parse_smb2_neg_resp() {
let mut neg_resp = Smb2NegRespBody::default();
neg_resp.security_mode = SMB2_NEGOTIATE_SIGNING_ENABLED;
neg_resp.dialect_revision = SMB2_DIA_REV_2FF;
neg_resp.server_guid = [
0x07, 0x29, 0x91, 0x3b, 0x4f, 0xa6, 0x4f, 0x4e, 0x8a, 0xb9, 0x44,
0xc5, 0xca, 0x55, 0x2c, 0x04,
];
neg_resp.capabilities = SMB2_GLOBAL_CAP_DFS
| SMB2_GLOBAL_CAP_LARGE_MTU
| SMB2_GLOBAL_CAP_LEASING;
neg_resp.max_transact_size = 0x800000;
neg_resp.max_read_size = 0x800000;
neg_resp.max_write_size = 0x800000;
neg_resp.system_time = 0x01d6ef76fcfdac2a;
neg_resp.buffer = vec![
0x60, 0x76, 0x06, 0x06, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x02, 0xa0,
0x6c, 0x30, 0x6a, 0xa0, 0x3c, 0x30, 0x3a, 0x06, 0x0a, 0x2b, 0x06,
0x01, 0x04, 0x01, 0x82, 0x37, 0x02, 0x02, 0x1e, 0x06, 0x09, 0x2a,
0x86, 0x48, 0x82, 0xf7, 0x12, 0x01, 0x02, 0x02, 0x06, 0x09, 0x2a,
0x86, 0x48, 0x86, 0xf7, 0x12, 0x01, 0x02, 0x02, 0x06, 0x0a, 0x2a,
0x86, 0x48, 0x86, 0xf7, 0x12, 0x01, 0x02, 0x02, 0x03, 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,
];
assert_eq!(
neg_resp,
Smb2NegRespBody::parse(RAW_SMB2_NEG_RESP_BODY).unwrap().1
);
}
}