Skip to main content

smb_server_proto_smb1/
tree_connect.rs

1//! `SMB_COM_TREE_CONNECT_ANDX` (§2.2.4.7) and `TREE_DISCONNECT` (0x71).
2
3use smb_server_proto::buf::Reader;
4
5use crate::session_setup::BodyError;
6
7/// Parsed tree connect request (WC=4: AndX triple, Flags, PasswordLength).
8#[derive(Debug)]
9pub struct TreeConnectReq {
10    /// UNC path (`\\server\share`).
11    pub path: String,
12    /// Service string (`A:`, `IPC`, `?????`, …).
13    pub service: String,
14}
15
16impl TreeConnectReq {
17    /// Parse from words/data. `data_base` is the absolute frame offset of
18    /// `data[0]` for Unicode parity.
19    pub fn parse(
20        words: &[u8],
21        data: &[u8],
22        unicode: bool,
23        data_base: usize,
24    ) -> Result<Self, BodyError> {
25        use super::session_setup::BodyError;
26        if words.len() < 8 || data.is_empty() {
27            return Err(BodyError::TooShort);
28        }
29        let pw_len = u16le(words, 6) as usize;
30        if pw_len > data.len() {
31            return Err(BodyError::BadBlob);
32        }
33        // Cursor over the whole data area; password occupies the front.
34        // `base` = absolute frame offset of data[0]; zstring() adds its own
35        // cursor position for parity, so do NOT pre-add it here.
36        let mut rd = Reader::new(data, pw_len);
37        let path = rd.zstring(unicode, data_base);
38        let service = rd.zstring(false, data_base);
39        Ok(Self { path, service })
40    }
41}
42
43fn u16le(w: &[u8], off: usize) -> u16 {
44    w.get(off..off + 2)
45        .map(|s| u16::from_le_bytes(s.try_into().unwrap()))
46        .unwrap_or(0)
47}
48
49/// Build the WC=4 response (AndX triple + OptionalSupport) with the service
50/// and native-filesystem strings in the buffer.
51pub fn build_response(
52    optional_support: u16,
53    service: &str,
54    native_fs: &str,
55    unicode: bool,
56    params_base_abs: usize,
57) -> (Vec<u8>, Vec<u8>) {
58    let mut params = Vec::with_capacity(8);
59    params.push(0xFF);
60    params.push(0);
61    params.extend_from_slice(&0u16.to_le_bytes());
62    params.extend_from_slice(&optional_support.to_le_bytes());
63
64    let bytes_start_abs = params_base_abs;
65    let mut bytes = Vec::new();
66    // Service string is always ASCII.
67    bytes.extend_from_slice(service.as_bytes());
68    bytes.push(0);
69    while (bytes_start_abs + bytes.len()) & 1 != 0 && unicode {
70        bytes.push(0);
71    }
72    if unicode {
73        for u in native_fs.encode_utf16() {
74            bytes.extend_from_slice(&u.to_le_bytes());
75        }
76        bytes.extend_from_slice(&[0, 0]);
77    } else {
78        bytes.extend_from_slice(native_fs.as_bytes());
79        bytes.push(0);
80    }
81    (params, bytes)
82}