1use crate::fake_name::{from_fake_name, is_unique_name, to_fake_name};
9use crate::message::{Endian, Message};
10use crate::message_rewrite::{parse_match_rule_sender, rewrite_match_rule_sender};
11use crate::session::Bus;
12use anyhow::{bail, Result};
13use zvariant::{
14 serialized::{Context, Data},
15 to_bytes, Endian as ZEndian, BE, LE,
16};
17
18pub const METHODS_NEED_RESPONSE_REWRITE: &[&str] = &["Hello", "GetNameOwner", "ListQueuedOwners"];
20
21pub const METHODS_NEED_REQUEST_REWRITE: &[&str] = &[
23 "GetConnectionCredentials",
24 "GetConnectionUnixUser",
25 "GetConnectionUnixProcessID",
26 "GetConnectionSELinuxSecurityContext",
27 "GetAdtAuditSessionData",
28 "NameHasOwner",
29 "GetNameOwner",
30];
31
32pub const METHODS_NEED_MERGE: &[&str] = &["ListNames", "ListActivatableNames"];
34
35pub const SIGNALS_NEED_REWRITE: &[&str] = &["NameOwnerChanged"];
37
38pub fn needs_response_rewrite(member: &str) -> bool {
40 METHODS_NEED_RESPONSE_REWRITE.contains(&member)
41}
42
43pub fn needs_request_rewrite(member: &str) -> bool {
45 METHODS_NEED_REQUEST_REWRITE.contains(&member)
46}
47
48pub fn needs_merge(member: &str) -> bool {
50 METHODS_NEED_MERGE.contains(&member)
51}
52
53pub fn signal_needs_rewrite(member: &str) -> bool {
55 SIGNALS_NEED_REWRITE.contains(&member)
56}
57
58pub fn rewrite_match_rule_body(msg: &Message) -> Result<Option<Vec<u8>>> {
61 let body_start = msg.body_start();
62
63 if body_start >= msg.raw.len() {
64 return Ok(None);
65 }
66
67 let str_len = msg.header.endian.read_u32(&msg.raw[body_start..]) as usize;
69 let str_start = body_start + 4;
70 let str_end = str_start + str_len;
71
72 if str_end > msg.raw.len() {
73 return Ok(None);
74 }
75
76 let rule = String::from_utf8_lossy(&msg.raw[str_start..str_end]).to_string();
77
78 if let Some(sender) = parse_match_rule_sender(&rule) {
80 if let Some((real_sender, _bus)) = from_fake_name(&sender) {
81 let new_rule = rewrite_match_rule_sender(&rule, &sender, &real_sender);
83 tracing::trace!(
84 old_sender = %sender,
85 new_sender = %real_sender,
86 "Rewrote match rule sender"
87 );
88 return rebuild_message_with_string(&msg.raw, msg.header.endian, body_start, &new_rule)
89 .map(Some);
90 }
91 }
92
93 Ok(None)
94}
95
96pub fn rewrite_single_name_response(msg: &Message, source: Bus) -> Result<Vec<u8>> {
98 let body_start = msg.body_start();
99
100 if body_start >= msg.raw.len() {
101 return Ok(msg.raw.clone());
102 }
103
104 let str_len = msg.header.endian.read_u32(&msg.raw[body_start..]) as usize;
106 let str_start = body_start + 4;
107 let str_end = str_start + str_len;
108
109 if str_end > msg.raw.len() {
110 return Ok(msg.raw.clone());
111 }
112
113 let name = String::from_utf8_lossy(&msg.raw[str_start..str_end]).to_string();
114
115 if !is_unique_name(&name) {
117 return Ok(msg.raw.clone());
118 }
119
120 let fake_name = to_fake_name(&name, source);
121
122 rebuild_message_with_string(&msg.raw, msg.header.endian, body_start, &fake_name)
124}
125
126pub fn rewrite_string_array_response(msg: &Message, source: Bus) -> Result<Vec<u8>> {
128 let names = parse_string_array(msg)?;
129
130 if names.is_empty() {
131 return Ok(msg.raw.clone());
132 }
133
134 let rewritten: Vec<String> = names
136 .into_iter()
137 .map(|name| {
138 if is_unique_name(&name) {
139 to_fake_name(&name, source)
140 } else {
141 name
142 }
143 })
144 .collect();
145
146 let z_endian = match msg.header.endian {
148 Endian::Little => LE,
149 Endian::Big => BE,
150 };
151 let new_body = to_bytes(Context::new_dbus(z_endian, 0), &rewritten)?;
152
153 rebuild_message_with_body(&msg.raw, msg.header.endian, &new_body)
155}
156
157pub fn rewrite_unique_name_request(msg: &Message) -> Result<(Vec<u8>, Bus)> {
160 use crate::fake_name::from_fake_name;
161
162 let body_start = msg.body_start();
163
164 if body_start >= msg.raw.len() {
165 bail!("No body in message");
166 }
167
168 let str_len = msg.header.endian.read_u32(&msg.raw[body_start..]) as usize;
170 let str_start = body_start + 4;
171 let str_end = str_start + str_len;
172
173 if str_end > msg.raw.len() {
174 bail!("Invalid string in body");
175 }
176
177 let name = String::from_utf8_lossy(&msg.raw[str_start..str_end]).to_string();
178
179 if let Some((real_name, bus)) = from_fake_name(&name) {
181 let new_raw =
182 rebuild_message_with_string(&msg.raw, msg.header.endian, body_start, &real_name)?;
183 Ok((new_raw, bus))
184 } else {
185 Ok((msg.raw.clone(), Bus::Sandbox))
187 }
188}
189
190pub fn merge_list_names(host_names: Vec<String>, sandbox_names: Vec<String>) -> Vec<String> {
192 use std::collections::HashSet;
193
194 let mut seen: HashSet<String> = HashSet::new();
195 let mut result = Vec::new();
196
197 for name in sandbox_names {
199 let key = if is_unique_name(&name) {
200 to_fake_name(&name, Bus::Sandbox)
201 } else {
202 name.clone()
203 };
204 if seen.insert(key.clone()) {
205 result.push(key);
206 }
207 }
208
209 for name in host_names {
211 let key = if is_unique_name(&name) {
212 to_fake_name(&name, Bus::Host)
213 } else {
214 name.clone()
215 };
216 if seen.insert(key.clone()) {
217 result.push(key);
218 }
219 }
220
221 result
222}
223
224pub fn rewrite_name_owner_changed(msg: &Message, source: Bus) -> Result<Vec<u8>> {
227 let body_start = msg.body_start();
228
229 if body_start >= msg.raw.len() {
230 return Ok(msg.raw.clone());
231 }
232
233 let z_endian = match msg.header.endian {
234 Endian::Little => ZEndian::Little,
235 Endian::Big => ZEndian::Big,
236 };
237
238 let ctxt = Context::new_dbus(z_endian, body_start);
240 let body_data = &msg.raw[body_start..];
241 let data = Data::new(body_data, ctxt);
242
243 let (name, old_owner, new_owner): (String, String, String) =
244 match data.deserialize::<(String, String, String)>() {
245 Ok((tuple, _)) => tuple,
246 Err(e) => {
247 tracing::warn!("Failed to parse NameOwnerChanged: {}", e);
248 return Ok(msg.raw.clone());
249 }
250 };
251
252 let new_old_owner = if is_unique_name(&old_owner) && !old_owner.is_empty() {
254 to_fake_name(&old_owner, source)
255 } else {
256 old_owner
257 };
258
259 let new_new_owner = if is_unique_name(&new_owner) && !new_owner.is_empty() {
260 to_fake_name(&new_owner, source)
261 } else {
262 new_owner
263 };
264
265 let new_body = match msg.header.endian {
267 Endian::Little => to_bytes(
268 Context::new_dbus(LE, 0),
269 &(name, new_old_owner, new_new_owner),
270 )?,
271 Endian::Big => to_bytes(
272 Context::new_dbus(BE, 0),
273 &(name, new_old_owner, new_new_owner),
274 )?,
275 };
276
277 rebuild_message_with_body(&msg.raw, msg.header.endian, &new_body)
278}
279
280fn get_body_start(raw: &[u8], endian: Endian) -> usize {
282 let fixed_header_size = 12;
283 let array_len = endian.read_u32(&raw[fixed_header_size..]) as usize;
284 let header_end = 16 + array_len;
285 let padding = (8 - (header_end % 8)) % 8;
286 header_end + padding
287}
288
289fn rebuild_message_with_string(
291 raw: &[u8],
292 endian: Endian,
293 _body_start: usize,
294 new_str: &str,
295) -> Result<Vec<u8>> {
296 let new_len = new_str.len() as u32;
297 let new_len_bytes = match endian {
298 Endian::Little => new_len.to_le_bytes(),
299 Endian::Big => new_len.to_be_bytes(),
300 };
301
302 let mut new_body = Vec::with_capacity(4 + new_str.len() + 1);
304 new_body.extend_from_slice(&new_len_bytes);
305 new_body.extend_from_slice(new_str.as_bytes());
306 new_body.push(0);
307
308 rebuild_message_with_body(raw, endian, &new_body)
309}
310
311fn rebuild_message_with_body(raw: &[u8], endian: Endian, new_body: &[u8]) -> Result<Vec<u8>> {
313 let body_start = get_body_start(raw, endian);
314
315 let new_body_len = new_body.len() as u32;
317 let body_len_bytes = match endian {
318 Endian::Little => new_body_len.to_le_bytes(),
319 Endian::Big => new_body_len.to_be_bytes(),
320 };
321
322 let mut new_raw = Vec::with_capacity(body_start + new_body.len());
323 new_raw.extend_from_slice(&raw[..4]); new_raw.extend_from_slice(&body_len_bytes); new_raw.extend_from_slice(&raw[8..body_start]); new_raw.extend_from_slice(new_body);
327
328 Ok(new_raw)
329}
330
331pub fn parse_string_array(msg: &Message) -> Result<Vec<String>> {
333 let body_start = msg.body_start();
334
335 if body_start >= msg.raw.len() {
336 return Ok(vec![]);
337 }
338
339 let z_endian = match msg.header.endian {
340 Endian::Little => ZEndian::Little,
341 Endian::Big => ZEndian::Big,
342 };
343
344 let ctxt = Context::new_dbus(z_endian, body_start);
345 let body_data = &msg.raw[body_start..];
346 let data = Data::new(body_data, ctxt);
347
348 let names: Vec<String> = data
349 .deserialize::<Vec<String>>()
350 .map(|(names, _)| names)
351 .unwrap_or_default();
352
353 Ok(names)
354}
355
356pub fn build_list_names_response(
358 original_request: &Message,
359 names: Vec<String>,
360) -> Result<Vec<u8>> {
361 let endian = original_request.header.endian;
362
363 let body = match endian {
365 Endian::Little => to_bytes(Context::new_dbus(LE, 0), &names)?,
366 Endian::Big => to_bytes(Context::new_dbus(BE, 0), &names)?,
367 };
368
369 build_method_return(original_request, &body, Some("as"))
371}
372
373fn build_method_return(request: &Message, body: &[u8], signature: Option<&str>) -> Result<Vec<u8>> {
375 use zvariant::{Signature, Value};
376
377 let endian = request.header.endian;
378 let z_endian = match endian {
379 Endian::Little => LE,
380 Endian::Big => BE,
381 };
382
383 let mut fields: Vec<(u8, Value)> = vec![
385 (5, Value::U32(request.header.serial)), ];
387
388 if let Some(sig) = signature {
390 fields.push((8, Value::Signature(Signature::from_str_unchecked(sig)))); }
392
393 let ctxt = Context::new_dbus(z_endian, 12);
394 let fields_encoded = to_bytes(ctxt, &fields)?;
395 let array_len = (fields_encoded.len() - 4) as u32;
396
397 let header_end = 16 + array_len as usize;
399 let padding = (8 - (header_end % 8)) % 8;
400
401 let mut msg = Vec::with_capacity(16 + array_len as usize + padding + body.len());
403
404 msg.push(if endian == Endian::Little { b'l' } else { b'B' });
406 msg.push(2); msg.push(1); msg.push(1); let body_len_bytes = match endian {
412 Endian::Little => (body.len() as u32).to_le_bytes(),
413 Endian::Big => (body.len() as u32).to_be_bytes(),
414 };
415 msg.extend_from_slice(&body_len_bytes);
416
417 let serial = request.header.serial.wrapping_add(1000000);
419 let serial_bytes = match endian {
420 Endian::Little => serial.to_le_bytes(),
421 Endian::Big => serial.to_be_bytes(),
422 };
423 msg.extend_from_slice(&serial_bytes);
424
425 msg.extend_from_slice(&fields_encoded);
427
428 msg.resize(msg.len() + padding, 0);
430
431 msg.extend_from_slice(body);
433
434 Ok(msg)
435}
436
437#[cfg(test)]
438mod tests {
439 use super::*;
440
441 #[test]
442 fn test_merge_list_names() {
443 let host = vec![
444 "org.fcitx.Fcitx5".to_string(),
445 ":1.45".to_string(),
446 "org.freedesktop.DBus".to_string(),
447 ];
448 let sandbox = vec![
449 "org.example.App".to_string(),
450 ":1.23".to_string(),
451 "org.freedesktop.DBus".to_string(), ];
453
454 let merged = merge_list_names(host, sandbox);
455
456 assert!(merged.contains(&"org.example.App".to_string()));
458 assert!(merged.contains(&":s.1.23".to_string()));
459 assert!(merged.contains(&"org.freedesktop.DBus".to_string()));
460 assert!(merged.contains(&"org.fcitx.Fcitx5".to_string()));
461 assert!(merged.contains(&":h.1.45".to_string()));
462
463 assert_eq!(
465 merged
466 .iter()
467 .filter(|n| *n == "org.freedesktop.DBus")
468 .count(),
469 1
470 );
471 }
472
473 #[test]
474 fn test_needs_checks() {
475 assert!(needs_response_rewrite("GetNameOwner"));
476 assert!(needs_response_rewrite("Hello"));
477 assert!(!needs_response_rewrite("RequestName"));
478
479 assert!(needs_request_rewrite("GetConnectionCredentials"));
480 assert!(needs_request_rewrite("GetNameOwner"));
481 assert!(needs_request_rewrite("NameHasOwner"));
482
483 assert!(needs_merge("ListNames"));
484 assert!(!needs_merge("GetNameOwner"));
485
486 assert!(signal_needs_rewrite("NameOwnerChanged"));
487 assert!(!signal_needs_rewrite("NameAcquired"));
488 }
489}