1use crate::{Result, SmbError};
5
6fn utf16le(s: &str) -> Vec<u8> {
7 s.encode_utf16().flat_map(u16::to_le_bytes).collect()
8}
9fn u16(b: &[u8], o: usize) -> u16 {
10 u16::from_le_bytes([b[o], b[o + 1]])
11}
12fn u32(b: &[u8], o: usize) -> u32 {
13 u32::from_le_bytes([b[o], b[o + 1], b[o + 2], b[o + 3]])
14}
15
16pub fn negotiate(client_guid: &[u8; 16]) -> Vec<u8> {
20 let dialects: [u16; 2] = [0x0202, 0x0210];
28 let mut b = Vec::new();
29 b.extend_from_slice(&36u16.to_le_bytes()); b.extend_from_slice(&(dialects.len() as u16).to_le_bytes()); b.extend_from_slice(&0x0001u16.to_le_bytes()); b.extend_from_slice(&0u16.to_le_bytes()); b.extend_from_slice(&0u32.to_le_bytes()); b.extend_from_slice(client_guid);
35 b.extend_from_slice(&0u64.to_le_bytes()); for dialect in dialects {
37 b.extend_from_slice(&dialect.to_le_bytes());
38 }
39 b
40}
41
42pub fn session_setup(token: &[u8]) -> Vec<u8> {
46 let mut b = Vec::new();
47 b.extend_from_slice(&25u16.to_le_bytes()); b.push(0); b.push(0x01); b.extend_from_slice(&0u32.to_le_bytes()); b.extend_from_slice(&0u32.to_le_bytes()); let sec_off = 64u16 + 24; b.extend_from_slice(&sec_off.to_le_bytes()); b.extend_from_slice(&(token.len() as u16).to_le_bytes()); b.extend_from_slice(&0u64.to_le_bytes()); b.extend_from_slice(token);
57 b
58}
59
60pub fn session_setup_token(msg: &[u8]) -> Result<Vec<u8>> {
62 let body = msg.get(64..).ok_or(SmbError::Truncated)?;
64 let off = u16(body, 4) as usize; let len = u16(body, 6) as usize;
66 msg.get(off..off + len)
67 .map(|s| s.to_vec())
68 .ok_or(SmbError::Truncated)
69}
70
71pub fn tree_connect(path: &str) -> Vec<u8> {
74 let name = utf16le(path);
75 let mut b = Vec::new();
76 b.extend_from_slice(&9u16.to_le_bytes()); b.extend_from_slice(&0u16.to_le_bytes()); let path_off = 64u16 + 8;
79 b.extend_from_slice(&path_off.to_le_bytes()); b.extend_from_slice(&(name.len() as u16).to_le_bytes()); b.extend_from_slice(&name);
82 b
83}
84
85pub fn create_pipe(name: &str) -> Vec<u8> {
89 let n = utf16le(name);
90 let mut b = Vec::new();
91 b.extend_from_slice(&57u16.to_le_bytes()); b.push(0); b.push(0); b.extend_from_slice(&2u32.to_le_bytes()); b.extend_from_slice(&0u64.to_le_bytes()); b.extend_from_slice(&0u64.to_le_bytes()); b.extend_from_slice(&0x0012_019Fu32.to_le_bytes()); b.extend_from_slice(&0u32.to_le_bytes()); b.extend_from_slice(&0x0000_0007u32.to_le_bytes()); b.extend_from_slice(&0x0000_0001u32.to_le_bytes()); b.extend_from_slice(&0u32.to_le_bytes()); let name_off = 64u16 + 56;
103 b.extend_from_slice(&name_off.to_le_bytes()); b.extend_from_slice(&(n.len() as u16).to_le_bytes()); b.extend_from_slice(&0u32.to_le_bytes()); b.extend_from_slice(&0u32.to_le_bytes()); b.extend_from_slice(&n);
108 b
109}
110
111pub fn create_file(path: &str, access: u32, share: u32, disposition: u32, options: u32) -> Vec<u8> {
114 let n = utf16le(path);
115 let mut b = Vec::new();
116 b.extend_from_slice(&57u16.to_le_bytes()); b.push(0); b.push(0); b.extend_from_slice(&2u32.to_le_bytes()); b.extend_from_slice(&0u64.to_le_bytes()); b.extend_from_slice(&0u64.to_le_bytes()); b.extend_from_slice(&access.to_le_bytes()); b.extend_from_slice(&0u32.to_le_bytes()); b.extend_from_slice(&share.to_le_bytes()); b.extend_from_slice(&disposition.to_le_bytes()); b.extend_from_slice(&options.to_le_bytes()); let name_off = 64u16 + 56;
128 b.extend_from_slice(&name_off.to_le_bytes()); b.extend_from_slice(&(n.len() as u16).to_le_bytes()); b.extend_from_slice(&0u32.to_le_bytes()); b.extend_from_slice(&0u32.to_le_bytes()); b.extend_from_slice(&n);
133 b
134}
135
136pub fn read_req(file_id: &[u8; 16], offset: u64, length: u32) -> Vec<u8> {
138 let mut b = Vec::new();
139 b.extend_from_slice(&49u16.to_le_bytes()); b.push(0); b.push(0); b.extend_from_slice(&length.to_le_bytes()); b.extend_from_slice(&offset.to_le_bytes()); b.extend_from_slice(file_id);
145 b.extend_from_slice(&0u32.to_le_bytes()); b.extend_from_slice(&0u32.to_le_bytes()); b.extend_from_slice(&0u32.to_le_bytes()); b.extend_from_slice(&0u16.to_le_bytes()); b.extend_from_slice(&0u16.to_le_bytes()); b.push(0); b
152}
153
154pub fn read_output(msg: &[u8]) -> Result<Vec<u8>> {
156 let body = msg.get(64..).ok_or(SmbError::Truncated)?;
157 let data_off = *body.get(2).ok_or(SmbError::Truncated)? as usize; let data_len = u32(body, 4) as usize;
159 msg.get(data_off..data_off + data_len)
160 .map(|s| s.to_vec())
161 .ok_or(SmbError::Truncated)
162}
163
164pub fn write_req(file_id: &[u8; 16], offset: u64, data: &[u8]) -> Vec<u8> {
166 let mut b = Vec::new();
167 b.extend_from_slice(&49u16.to_le_bytes()); b.extend_from_slice(&(64u16 + 48).to_le_bytes()); b.extend_from_slice(&(data.len() as u32).to_le_bytes()); b.extend_from_slice(&offset.to_le_bytes()); b.extend_from_slice(file_id);
172 b.extend_from_slice(&0u32.to_le_bytes()); b.extend_from_slice(&0u32.to_le_bytes()); b.extend_from_slice(&0u16.to_le_bytes()); b.extend_from_slice(&0u16.to_le_bytes()); b.extend_from_slice(&0u32.to_le_bytes()); b.extend_from_slice(data);
178 b
179}
180
181pub fn close_req(file_id: &[u8; 16]) -> Vec<u8> {
183 let mut b = Vec::new();
184 b.extend_from_slice(&24u16.to_le_bytes()); b.extend_from_slice(&0u16.to_le_bytes()); b.extend_from_slice(&0u32.to_le_bytes()); b.extend_from_slice(file_id);
188 b
189}
190
191pub fn create_file_id(msg: &[u8]) -> Result<[u8; 16]> {
193 msg.get(128..144)
195 .map(|s| s.try_into().unwrap())
196 .ok_or(SmbError::Truncated)
197}
198
199pub const FSCTL_PIPE_TRANSCEIVE: u32 = 0x0011_C017;
202
203pub fn ioctl_transceive(file_id: &[u8; 16], input: &[u8]) -> Vec<u8> {
205 let mut b = Vec::new();
206 b.extend_from_slice(&57u16.to_le_bytes()); b.extend_from_slice(&0u16.to_le_bytes()); b.extend_from_slice(&FSCTL_PIPE_TRANSCEIVE.to_le_bytes()); b.extend_from_slice(file_id);
210 let input_off = 64u32 + 56;
211 b.extend_from_slice(&input_off.to_le_bytes()); b.extend_from_slice(&(input.len() as u32).to_le_bytes()); b.extend_from_slice(&0u32.to_le_bytes()); b.extend_from_slice(&input_off.to_le_bytes()); b.extend_from_slice(&0u32.to_le_bytes()); b.extend_from_slice(&0x0001_0000u32.to_le_bytes()); b.extend_from_slice(&0x0000_0001u32.to_le_bytes()); b.extend_from_slice(&0u32.to_le_bytes()); b.extend_from_slice(input);
220 b
221}
222
223pub fn ioctl_output(msg: &[u8]) -> Result<Vec<u8>> {
225 let body = msg.get(64..).ok_or(SmbError::Truncated)?;
228 let out_off = u32(body, 32) as usize; let out_len = u32(body, 36) as usize;
230 msg.get(out_off..out_off + out_len)
231 .map(|s| s.to_vec())
232 .ok_or(SmbError::Truncated)
233}
234
235#[cfg(test)]
236mod tests {
237 use super::*;
238
239 #[test]
240 fn negotiate_offers_dialect_210() {
241 let b = negotiate(&[0; 16]);
242 assert_eq!(u16(&b, 0), 36); assert_eq!(u16(&b, 2), 2); assert_eq!(u16(&b, 36), 0x0202);
246 assert_eq!(u16(&b, 38), 0x0210);
247 }
248
249 #[test]
250 fn create_pipe_name_offset_correct() {
251 let b = create_pipe("samr");
252 assert_eq!(u16(&b, 0), 57);
253 assert_eq!(u16(&b, 44), 64 + 56); assert_eq!(u16(&b, 46), 8); }
256
257 #[test]
258 fn ioctl_uses_transceive_ctlcode() {
259 let b = ioctl_transceive(&[0; 16], &[1, 2, 3]);
260 assert_eq!(u32(&b, 4), FSCTL_PIPE_TRANSCEIVE);
261 assert_eq!(u32(&b, 28), 3); }
263
264 #[test]
265 fn create_file_carries_access_and_options() {
266 let b = create_file("Windows\\Temp\\x.out", 0x0013_0081, 0x7, 1, 0x1060);
267 assert_eq!(u16(&b, 0), 57); assert_eq!(u32(&b, 24), 0x0013_0081); assert_eq!(u32(&b, 32), 0x7); assert_eq!(u32(&b, 36), 1); assert_eq!(u32(&b, 40), 0x1060); assert_eq!(u16(&b, 44), 64 + 56); assert_eq!(
274 u16(&b, 46),
275 "Windows\\Temp\\x.out".chars().count() as u16 * 2
276 );
277 }
278
279 #[test]
280 fn read_req_offset_and_length() {
281 let b = read_req(&[0xAB; 16], 0x1_0000, 0x4000);
282 assert_eq!(u16(&b, 0), 49); assert_eq!(u32(&b, 4), 0x4000); assert_eq!(u32(&b, 8), 0x1_0000); assert_eq!(&b[16..32], &[0xAB; 16]); }
287
288 #[test]
289 fn close_req_shape() {
290 let b = close_req(&[0xCD; 16]);
291 assert_eq!(u16(&b, 0), 24); assert_eq!(&b[8..24], &[0xCD; 16]); }
294}