red_smb 0.0.2

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