smb_server_proto_smb1/
header.rs1use smb_server_proto::types::Status;
5
6pub use crate::consts::{flags, flags2};
7
8#[derive(Debug, Clone)]
10pub struct Header {
11 pub command: u8,
13 pub status: Status,
15 pub flags: u8,
17 pub flags2: u16,
19 pub pid_high: u16,
21 pub tid: u16,
23 pub pid: u16,
25 pub uid: u16,
27 pub mid: u16,
29}
30
31pub const HDR_LEN: usize = 32;
33
34pub const SMB_MAGIC: [u8; 4] = [0xFF, b'S', b'M', b'B'];
36
37pub fn parse_header(buf: &[u8]) -> Option<(Header, usize)> {
40 if buf.len() < HDR_LEN + 1 || buf[0..4] != SMB_MAGIC {
41 return None;
42 }
43 let hdr = Header {
44 command: buf[4],
45 status: Status(u32::from_le_bytes(buf[5..9].try_into().ok()?)),
46 flags: buf[9],
47 flags2: u16::from_le_bytes(buf[10..12].try_into().ok()?),
48 pid_high: u16::from_le_bytes(buf[12..14].try_into().ok()?),
49 tid: u16::from_le_bytes(buf[24..26].try_into().ok()?),
50 pid: u16::from_le_bytes(buf[26..28].try_into().ok()?),
51 uid: u16::from_le_bytes(buf[28..30].try_into().ok()?),
52 mid: u16::from_le_bytes(buf[30..32].try_into().ok()?),
53 };
54 Some((hdr, HDR_LEN))
55}
56
57#[derive(Debug, Clone)]
61pub struct RespBody {
62 pub command: u8,
64 pub params: Vec<u8>,
66 pub bytes: Vec<u8>,
68 pub tid_override: Option<u16>,
70 pub uid_override: Option<u16>,
72}
73
74impl RespBody {
75 pub fn new(command: u8, params: Vec<u8>, bytes: Vec<u8>) -> Self {
77 RespBody { command, params, bytes, tid_override: None, uid_override: None }
78 }
79}
80
81fn is_andx_capable(cmd: u8) -> bool {
82 matches!(
83 cmd,
84 crate::consts::COM_SESSION_SETUP_ANDX
85 | crate::consts::COM_TREE_CONNECT_ANDX
86 | crate::consts::COM_READ_ANDX
87 | crate::consts::COM_WRITE_ANDX
88 | crate::consts::COM_LOGOFF_ANDX
89 | crate::consts::COM_LOCKING_ANDX
90 | crate::consts::COM_NT_CREATE_ANDX
91 )
92}
93
94pub fn build_response(req_hdr: &Header, status: Status, mut bodies: Vec<RespBody>) -> Vec<u8> {
100 if bodies.is_empty() {
101 bodies.push(RespBody::new(req_hdr.command, Vec::new(), Vec::new()));
102 }
103
104 for i in 0..bodies.len() {
106 if is_andx_capable(bodies[i].command)
107 && bodies[i].params.len() >= 4
108 && i + 1 >= bodies.len()
109 {
110 bodies[i].params[0] = 0xFF;
111 bodies[i].params[1] = 0;
112 bodies[i].params[2..4].copy_from_slice(&0u16.to_le_bytes());
113 }
114 }
115
116 let mut out = Vec::with_capacity(HDR_LEN + 64);
117 out.extend_from_slice(&SMB_MAGIC);
118 out.push(bodies[0].command);
119 if req_hdr.flags2 & flags2::NT_STATUS != 0 {
120 out.extend_from_slice(&status.raw().to_le_bytes());
121 } else {
122 let (class, code) = status.to_dos();
123 out.extend_from_slice(&[code, 0, class, 0]);
124 }
125 out.push(flags::RESPONSE | (req_hdr.flags & flags::CASE_SENSITIVE));
126 let mut flags2 = req_hdr.flags2 & (flags2::UNICODE | flags2::LONG_NAMES | flags2::NT_STATUS);
127 flags2 |= flags2::LONG_NAMES;
128 out.extend_from_slice(&flags2.to_le_bytes());
129 out.extend_from_slice(&req_hdr.pid_high.to_le_bytes());
130 out.extend_from_slice(&[0u8; 8]); out.extend_from_slice(&[0u8; 2]); out.extend_from_slice(&bodies[0].tid_override.unwrap_or(req_hdr.tid).to_le_bytes());
133 out.extend_from_slice(&req_hdr.pid.to_le_bytes());
134 out.extend_from_slice(&bodies[0].uid_override.unwrap_or(req_hdr.uid).to_le_bytes());
135 out.extend_from_slice(&req_hdr.mid.to_le_bytes());
136
137 for (i, body) in bodies.iter().enumerate() {
138 let body_start = out.len();
139 debug_assert!(body.params.len() % 2 == 0);
140 out.push((body.params.len() / 2) as u8);
141 out.extend_from_slice(&body.params);
142 out.extend_from_slice(&(body.bytes.len() as u16).to_le_bytes());
143 out.extend_from_slice(&body.bytes);
144
145 if is_andx_capable(body.command) && body.params.len() >= 4 {
146 match bodies.get(i + 1) {
147 Some(next) => {
148 let next_off = out.len();
149 out[body_start + 1] = next.command;
150 out[body_start + 2] = 0;
151 out[body_start + 3..body_start + 5]
152 .copy_from_slice(&(next_off as u16).to_le_bytes());
153 }
154 None => {
155 let end = out.len() as u16;
157 out[body_start + 3..body_start + 5].copy_from_slice(&end.to_le_bytes());
158 out[body_start + 1] = 0xFF;
159 }
160 }
161 }
162 }
163 out
164}