smb_msg/
smb1.rs

1//! SMBv1 negotiation packet support.
2//!
3//! For multi-protocol negotiation only.
4
5use binrw::io::TakeSeekExt;
6use binrw::prelude::*;
7
8use smb_dtyp::binrw_util::prelude::*;
9
10#[binrw::binrw]
11#[derive(Debug)]
12#[brw(little)]
13#[brw(magic(b"\xffSMB"))]
14pub struct SMB1NegotiateMessage {
15    #[bw(calc = 0x72)]
16    #[br(assert(_command == 0x72))]
17    _command: u8,
18    status: u32,
19    flags: u8,
20    flags2: u16,
21    #[bw(calc = 0)]
22    #[br(assert(_pid_high == 0))]
23    _pid_high: u16,
24    security_features: [u8; 8],
25    #[bw(calc = 0)]
26    #[br(assert(_reserved == 0))]
27    _reserved: u16,
28    #[bw(calc = 0xffff)]
29    _tid: u16,
30    #[bw(calc = 1)]
31    #[br(assert(_pid_low == 1))]
32    _pid_low: u16,
33    #[bw(calc = 0)]
34    _uid: u16,
35    #[bw(calc = 0)]
36    _mid: u16,
37    // word count is always 0x0 according to MS-CIFS.
38    #[bw(calc = 0)]
39    #[br(assert(_word_count == 0))]
40    _word_count: u8,
41    byte_count: PosMarker<u16>,
42    #[br(map_stream = |s| s.take_seek(byte_count.value.into()), parse_with = binrw::helpers::until_eof)]
43    #[bw(write_with = PosMarker::write_size, args(byte_count))]
44    dialects: Vec<Smb1Dialect>,
45}
46
47impl SMB1NegotiateMessage {
48    pub fn is_smb2_supported(&self) -> bool {
49        self.dialects
50            .iter()
51            .any(|d| d.name.to_string() == "SMB 2.002")
52    }
53}
54
55impl Default for SMB1NegotiateMessage {
56    fn default() -> Self {
57        Self {
58            status: 0,
59            flags: 0x18,
60            flags2: 0xc853,
61            security_features: [0; 8],
62            byte_count: PosMarker::default(),
63            dialects: vec![
64                Smb1Dialect {
65                    name: binrw::NullString::from("NT LM 0.12"),
66                },
67                Smb1Dialect {
68                    name: binrw::NullString::from("SMB 2.002"),
69                },
70                Smb1Dialect {
71                    name: binrw::NullString::from("SMB 2.???"),
72                },
73            ],
74        }
75    }
76}
77
78#[derive(BinRead, BinWrite, Debug)]
79#[brw(magic(b"\x02"))]
80pub struct Smb1Dialect {
81    name: binrw::NullString,
82}
83
84impl TryInto<Vec<u8>> for SMB1NegotiateMessage {
85    type Error = binrw::Error;
86    fn try_into(self) -> Result<Vec<u8>, Self::Error> {
87        let mut buf = std::io::Cursor::new(Vec::new());
88        self.write(&mut buf)?;
89        Ok(buf.into_inner())
90    }
91}
92
93#[cfg(test)]
94mod tests {
95    use super::*;
96
97    #[test]
98    pub fn test_smb1_negotiate_req_write() {
99        let msg = SMB1NegotiateMessage::default();
100        let buf: Result<Vec<u8>, binrw::Error> = msg.try_into();
101        assert_eq!(
102            buf.unwrap(),
103            [
104                0xff, 0x53, 0x4d, 0x42, 0x72, 0x0, 0x0, 0x0, 0x0, 0x18, 0x53, 0xc8, 0x0, 0x0, 0x0,
105                0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff, 0x01, 0x00, 0x0, 0x0, 0x0,
106                0x0, 0x0, 0x22, 0x0, 0x2, 0x4e, 0x54, 0x20, 0x4c, 0x4d, 0x20, 0x30, 0x2e, 0x31,
107                0x32, 0x0, 0x2, 0x53, 0x4d, 0x42, 0x20, 0x32, 0x2e, 0x30, 0x30, 0x32, 0x0, 0x2,
108                0x53, 0x4d, 0x42, 0x20, 0x32, 0x2e, 0x3f, 0x3f, 0x3f, 0x0
109            ]
110        )
111    }
112}