use super::flags;
use crate::Result;
use nom::bytes::complete::{tag, take};
use nom::number::complete::{le_u16, le_u32, le_u64};
use std::convert::TryInto;
pub const SMB2_HEADER_SIZE: u16 = 64;
pub const SMB2_ID: [u8; 4] = [0xfe, 0x53, 0x4d, 0x42];
#[derive(Clone, Debug, PartialEq)]
pub struct Smb2Header {
pub credit_charge: u16,
pub status: u32,
pub command: u16,
pub credits: u16,
pub flags: u32,
pub next_command: u32,
pub message_id: u64,
pub reserved: u32,
pub tree_id: u32,
pub session_id: u64,
pub signature: [u8; 16],
}
impl Default for Smb2Header {
fn default() -> Self {
return Self {
credit_charge: 1,
status: 0,
command: 0,
credits: 0,
flags: 0,
next_command: 0,
message_id: 0,
reserved: 0,
tree_id: 0,
session_id: 0,
signature: [0; 16],
};
}
}
impl Smb2Header {
pub fn new(command: u16) -> Self {
let mut s = Self::default();
s.command = command;
return s;
}
pub fn is_response(&self) -> bool {
return (self.flags & flags::SMB2_FLAGS_SERVER_TO_REDIR) != 0;
}
pub fn is_request(&self) -> bool {
return !self.is_response();
}
pub fn parse(raw: &[u8]) -> Result<(&[u8], Self)> {
let (raw, _) = tag(&SMB2_ID[..])(raw)?;
let (raw, _) = le_u16(raw)?;
let (raw, credit_charge) = le_u16(raw)?;
let (raw, status) = le_u32(raw)?;
let (raw, command) = le_u16(raw)?;
let (raw, credits) = le_u16(raw)?;
let (raw, flags) = le_u32(raw)?;
let (raw, next_command) = le_u32(raw)?;
let (raw, message_id) = le_u64(raw)?;
let (raw, reserved) = le_u32(raw)?;
let (raw, tree_id) = le_u32(raw)?;
let (raw, session_id) = le_u64(raw)?;
let (raw, signature) = take(16usize)(raw)?;
return Ok((
raw,
Self {
credit_charge,
status,
command,
credits,
flags,
next_command,
message_id,
reserved,
tree_id,
session_id,
signature: signature.try_into().unwrap(),
},
));
}
pub fn build(&self) -> Vec<u8> {
let mut raw = SMB2_ID.to_vec();
raw.extend(&SMB2_HEADER_SIZE.to_le_bytes());
raw.extend(&self.credit_charge.to_le_bytes());
raw.extend(&self.status.to_le_bytes());
raw.extend(&self.command.to_le_bytes());
raw.extend(&self.credits.to_le_bytes());
raw.extend(&self.flags.to_le_bytes());
raw.extend(&self.next_command.to_le_bytes());
raw.extend(&self.message_id.to_le_bytes());
raw.extend(&self.reserved.to_le_bytes());
raw.extend(&self.tree_id.to_le_bytes());
raw.extend(&self.session_id.to_le_bytes());
raw.extend(&self.signature);
return raw;
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::smb2::header::flags::SMB2_FLAGS_SERVER_TO_REDIR;
const RAW_SMB2_HEADER: &'static [u8] = &[
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,
];
#[test]
fn test_parse_smb2_header() {
let mut header = Smb2Header::default();
header.credit_charge = 0;
header.credits = 1;
header.flags = SMB2_FLAGS_SERVER_TO_REDIR;
assert_eq!(header, Smb2Header::parse(&RAW_SMB2_HEADER).unwrap().1);
}
#[test]
fn test_build_smb2_header() {
let mut header = Smb2Header::default();
header.credit_charge = 0;
header.credits = 1;
header.flags = SMB2_FLAGS_SERVER_TO_REDIR;
assert_eq!(RAW_SMB2_HEADER, header.build());
}
}