red_smb 0.0.2

Library to play with SMB
Documentation
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());
    }
}