smb_msg/
smb1.rs

1//! SMBv1 negotiation packet support.
2//!
3//! For multi-protocol negotiation only.
4
5#[cfg(feature = "server")]
6use binrw::io::TakeSeekExt;
7use binrw::prelude::*;
8
9use smb_dtyp::binrw_util::prelude::*;
10use smb_msg_derive::smb_request_binrw;
11
12/// A (very) minimal SMB1 negotiation message,
13///
14/// See [`SMB1NegotiateMessage::default`] for a default message that
15/// announces support for SMB2/3, as a part of multi-protocol negotiation.
16#[smb_request_binrw]
17#[brw(little)]
18#[brw(magic(b"\xffSMB"))]
19pub struct SMB1NegotiateMessage {
20    #[bw(calc = 0x72)]
21    #[br(assert(_command == 0x72))]
22    #[br(temp)]
23    _command: u8,
24    status: u32,
25    flags: u8,
26    flags2: u16,
27    #[bw(calc = 0)]
28    #[br(assert(_pid_high == 0))]
29    #[br(temp)]
30    _pid_high: u16,
31    security_features: [u8; 8],
32    reserved: u16,
33    #[bw(calc = 0xffff)]
34    #[br(temp)]
35    _tid: u16,
36    #[bw(calc = 1)]
37    #[br(assert(_pid_low == 1))]
38    #[br(temp)]
39    _pid_low: u16,
40    /// uid
41    reserved: u16,
42    /// mid
43    reserved: u16,
44    // word count is always 0x0 according to MS-CIFS.
45    #[bw(calc = 0)]
46    #[br(assert(_word_count == 0))]
47    #[br(temp)]
48    _word_count: u8,
49    byte_count: PosMarker<u16>,
50    #[br(map_stream = |s| s.take_seek(byte_count.value.into()), parse_with = binrw::helpers::until_eof)]
51    #[bw(write_with = PosMarker::write_size, args(byte_count))]
52    dialects: Vec<Smb1Dialect>,
53}
54
55impl SMB1NegotiateMessage {
56    /// Check if SMB2 is supported in the dialects list.
57    pub fn is_smb2_supported(&self) -> bool {
58        self.dialects
59            .iter()
60            .any(|d| d.name.to_string() == "SMB 2.002")
61    }
62}
63
64impl Default for SMB1NegotiateMessage {
65    fn default() -> Self {
66        Self {
67            status: 0,
68            flags: 0x18,
69            flags2: 0xc853,
70            security_features: [0; 8],
71            byte_count: PosMarker::default(),
72            dialects: vec![
73                Smb1Dialect {
74                    name: binrw::NullString::from("NT LM 0.12"),
75                },
76                Smb1Dialect {
77                    name: binrw::NullString::from("SMB 2.002"),
78                },
79                Smb1Dialect {
80                    name: binrw::NullString::from("SMB 2.???"),
81                },
82            ],
83        }
84    }
85}
86
87/// SMB1 Dialect String
88#[derive(BinRead, BinWrite, Debug, PartialEq, Eq, Clone)]
89#[brw(magic(b"\x02"))]
90pub struct Smb1Dialect {
91    name: binrw::NullString,
92}
93
94#[cfg(feature = "client")]
95impl TryInto<Vec<u8>> for SMB1NegotiateMessage {
96    type Error = binrw::Error;
97    fn try_into(self) -> Result<Vec<u8>, Self::Error> {
98        let mut buf = std::io::Cursor::new(Vec::new());
99        self.write(&mut buf)?;
100        Ok(buf.into_inner())
101    }
102}
103
104#[cfg(test)]
105mod tests {
106    #[cfg(feature = "client")]
107    use super::*;
108    #[cfg(feature = "client")]
109    smb_tests::test_binrw_write! {
110        SMB1NegotiateMessage: SMB1NegotiateMessage::default() =>
111            "ff534d4272000000001853c8000000000000000000000000ffff010000000000002200024e54204c4d20302e31320002534d4220322e3030320002534d4220322e3f3f3f00"
112    }
113}