1use std::collections::VecDeque;
7
8use ms_ndr::NdrEncoder;
9
10#[derive(Debug, Clone)]
12pub struct ShareInfo {
13 pub netname: String,
15 pub shi_type: u32,
17 pub remark: String,
19}
20
21pub struct Pipe {
23 pub name: String,
25 inbound: Vec<u8>,
26 outbound: VecDeque<Vec<u8>>,
27}
28
29impl Pipe {
30 pub fn new(name: &str) -> Self {
32 Self { name: name.to_lowercase(), inbound: Vec::new(), outbound: VecDeque::new() }
33 }
34
35 pub fn pending(&self) -> usize {
37 self.outbound.front().map_or(0, |v| v.len())
38 }
39
40 pub fn take(&mut self, max: usize) -> Vec<u8> {
42 match self.outbound.front_mut() {
43 Some(msg) => {
44 let n = msg.len().min(max);
45 let out = msg.drain(..n).collect();
46 if msg.is_empty() { self.outbound.pop_front(); }
47 out
48 }
49 None => Vec::new(),
50 }
51 }
52
53 #[cfg_attr(dylint_lib = "no_magic_numbers", allow(no_magic_numbers))] pub fn on_write(&mut self, data: &[u8], shares: &[ShareInfo]) {
57 self.inbound.extend_from_slice(data);
58 loop {
59 if self.inbound.len() < 16 { break; }
60 let frag_len = u16::from_le_bytes([self.inbound[8], self.inbound[9]]) as usize;
61 if self.inbound.len() < frag_len { break; }
62 let pdu: Vec<u8> = self.inbound.drain(..frag_len).collect();
63 let ptype = pdu[2];
64 let call_id = u32::from_le_bytes([pdu[12], pdu[13], pdu[14], pdu[15]]);
65 let reply = match ptype {
66 11 => Some(build_bind_ack(call_id)),
67 14 => None,
68 0 if pdu.len() >= 24 => {
69 let opnum = u16::from_le_bytes([pdu[22], pdu[23]]);
70 tracing::debug!(opnum, "rpc request");
71 let body = match opnum {
72 15 => netshareenum_stub(shares),
73 _ => build_fault(call_id),
74 };
75 Some(response_pdu(call_id, &body))
76 }
77 _ => None,
78 };
79 if let Some(r) = reply {
80 self.outbound.push_back(r);
81 }
82 }
83 }
84}
85
86#[cfg_attr(dylint_lib = "no_magic_numbers", allow(no_magic_numbers))] fn pdu_header(ptype: u8, call_id: u32, body: &[u8]) -> Vec<u8> {
88 let mut p = Vec::with_capacity(16 + body.len());
89 p.extend_from_slice(&[5, 0]);
90 p.push(ptype);
91 p.push(0x03);
92 p.extend_from_slice(&0x0000_0010u32.to_le_bytes());
93 p.extend_from_slice(&((body.len() + 16) as u16).to_le_bytes());
94 p.extend_from_slice(&0u16.to_le_bytes());
95 p.extend_from_slice(&call_id.to_le_bytes());
96 p.extend_from_slice(body);
97 p
98}
99
100#[cfg_attr(dylint_lib = "no_magic_numbers", allow(no_magic_numbers))] fn response_pdu(call_id: u32, stub: &[u8]) -> Vec<u8> {
102 let mut body = Vec::with_capacity(8 + stub.len());
103 body.extend_from_slice(&(stub.len() as u32).to_le_bytes());
104 body.extend_from_slice(&0u16.to_le_bytes());
105 body.push(0); body.push(0);
106 body.extend_from_slice(stub);
107 pdu_header(2, call_id, &body)
108}
109
110#[cfg_attr(dylint_lib = "no_magic_numbers", allow(no_magic_numbers))] fn build_fault(call_id: u32) -> Vec<u8> {
112 let mut body = vec![0u8; 4];
113 body.extend_from_slice(&0u16.to_le_bytes());
114 body.push(0); body.push(0);
115 body.extend_from_slice(&0x1C01_0006u32.to_le_bytes());
116 pdu_header(3, call_id, &body)
117}
118
119#[cfg_attr(dylint_lib = "no_magic_numbers", allow(no_magic_numbers))] fn build_bind_ack(call_id: u32) -> Vec<u8> {
121 let sec_addr = b"\\pipe\\srvsvc\0";
122 let mut b = Vec::new();
123 b.extend_from_slice(&0x10b8u16.to_le_bytes());
124 b.extend_from_slice(&0x10b8u16.to_le_bytes());
125 b.extend_from_slice(&0x12345678u32.to_le_bytes());
126 b.extend_from_slice(&(sec_addr.len() as u16).to_le_bytes());
127 b.extend_from_slice(sec_addr);
128 while b.len() % 4 != 0 { b.push(0); }
129 b.extend_from_slice(&1u16.to_le_bytes());
130 b.push(0); b.push(0);
131 b.extend_from_slice(&0u16.to_le_bytes()); b.extend_from_slice(&0u16.to_le_bytes()); b.extend_from_slice(&[
134 0x04, 0x5d, 0x88, 0x8a, 0xeb, 0x1c, 0xc9, 0x11,
135 0x9f, 0xe8, 0x08, 0x00, 0x2b, 0x10, 0x48, 0x60,
136 ]);
137 b.extend_from_slice(&2u32.to_le_bytes());
138 pdu_header(12, call_id, &b)
139}
140
141pub fn netshareenum_stub(shares: &[ShareInfo]) -> Vec<u8> {
153 let n = shares.len() as u32;
154 let mut e = NdrEncoder::new();
155
156 e.u32(1); e.u32(1); e.referent(); e.u32(n); e.referent(); e.u32(n); for sh in shares {
165 e.referent(); e.u32(sh.shi_type);
167 e.referent(); }
169
170 for sh in shares {
172 e.conformant_varying_wstr(&sh.netname);
173 e.conformant_varying_wstr(&sh.remark);
174 }
175
176 e.u32(n); e.referent(); e.u32(0); e.u32(0); e.into_bytes()
181}
182
183#[cfg(test)]
184mod tests {
185 use super::*;
186 use ms_ndr::NdrDecoder;
187
188 fn reference_shares() -> Vec<ShareInfo> {
189 vec![
190 ShareInfo { netname: "public".into(), shi_type: 0, remark: String::new() },
191 ShareInfo {
192 netname: "IPC$".into(),
193 shi_type: 0x8000_0003,
194 remark: "IPC Service (ref)".into(),
195 },
196 ]
197 }
198
199 fn decode_and_check(shares: &[ShareInfo]) {
204 let stub = netshareenum_stub(shares);
205 assert_eq!(stub.len() % 4, 0, "stub stays 4-byte aligned");
206
207 let n = shares.len() as u32;
208 let mut d = NdrDecoder::new(&stub);
209 assert_eq!(d.u32().unwrap(), 1, "Level");
210 assert_eq!(d.u32().unwrap(), 1, "union switch");
211 assert_ne!(d.u32().unwrap(), 0, "container pointer non-null");
212 assert_eq!(d.u32().unwrap(), n, "EntriesRead");
213 assert_ne!(d.u32().unwrap(), 0, "buffer pointer non-null");
214 assert_eq!(d.u32().unwrap(), n, "array MaxCount");
215
216 let mut types = Vec::new();
217 for _ in 0..n {
218 assert_ne!(d.u32().unwrap(), 0, "netname pointer non-null");
219 types.push(d.u32().unwrap());
220 assert_ne!(d.u32().unwrap(), 0, "remark pointer non-null");
221 }
222
223 let mut decoded = Vec::new();
224 for _ in 0..n {
225 let netname = d.conformant_varying_wstr().unwrap();
226 let remark = d.conformant_varying_wstr().unwrap();
227 decoded.push((netname, remark));
228 }
229
230 assert_eq!(d.u32().unwrap(), n, "TotalEntries");
231 assert_ne!(d.u32().unwrap(), 0, "resume-handle pointer non-null");
232 assert_eq!(d.u32().unwrap(), 0, "resume-handle value");
233 assert_eq!(d.u32().unwrap(), 0, "return WERROR = ERROR_SUCCESS");
234 assert_eq!(d.remaining(), 0, "no trailing bytes");
235
236 for (i, sh) in shares.iter().enumerate() {
237 assert_eq!(types[i], sh.shi_type, "share {i} type");
238 assert_eq!(decoded[i].0, sh.netname, "share {i} netname");
239 assert_eq!(decoded[i].1, sh.remark, "share {i} remark");
240 }
241 }
242
243 #[test]
244 fn netshareenum_round_trips_reference_shares() {
245 decode_and_check(&reference_shares());
246 }
247
248 #[test]
249 fn netshareenum_scales_to_more_shares() {
250 let shares = vec![
251 ShareInfo { netname: "alpha".into(), shi_type: 0, remark: "one".into() },
252 ShareInfo { netname: "beta".into(), shi_type: 0, remark: "two".into() },
253 ShareInfo { netname: "IPC$".into(), shi_type: 0x8000_0003, remark: String::new() },
254 ];
255 decode_and_check(&shares);
256
257 let stub = netshareenum_stub(&shares);
259 let mut refs = vec![
260 u32::from_le_bytes([stub[8], stub[9], stub[10], stub[11]]),
261 u32::from_le_bytes([stub[16], stub[17], stub[18], stub[19]]),
262 ];
263 for i in 0..shares.len() {
264 let base = 24 + i * 12;
265 refs.push(u32::from_le_bytes([stub[base], stub[base + 1], stub[base + 2], stub[base + 3]]));
266 refs.push(u32::from_le_bytes([stub[base + 8], stub[base + 9], stub[base + 10], stub[base + 11]]));
267 }
268 let mut unique = refs.clone();
269 unique.sort_unstable();
270 unique.dedup();
271 assert_eq!(unique.len(), refs.len(), "referent ids must be unique");
272 }
273}