adhammer_core/
snapshot.rs1use crate::object::AdObject;
5use crate::sid::Sid;
6use std::collections::HashMap;
7
8#[derive(Clone, Debug, Default)]
9pub struct DomainInfo {
10 pub domain_dn: String, pub domain_sid: Option<Sid>,
12 pub netbios: Option<String>,
13 pub functional_level: Option<i64>,
14 pub machine_account_quota: Option<i64>,
15}
16
17#[derive(Clone, Debug, Default)]
18pub struct Snapshot {
19 pub domain: DomainInfo,
20 pub objects: Vec<AdObject>,
21 dn_index: HashMap<String, usize>,
23}
24
25impl Snapshot {
26 pub fn new(domain: DomainInfo, objects: Vec<AdObject>) -> Self {
27 let dn_index = objects
28 .iter()
29 .enumerate()
30 .map(|(i, o)| (o.dn.to_ascii_lowercase(), i))
31 .collect();
32 Snapshot {
33 domain,
34 objects,
35 dn_index,
36 }
37 }
38
39 pub fn by_dn(&self, dn: &str) -> Option<&AdObject> {
40 self.dn_index
41 .get(&dn.to_ascii_lowercase())
42 .map(|&i| &self.objects[i])
43 }
44
45 pub fn by_sid(&self, sid: &Sid) -> Option<&AdObject> {
47 self.objects
48 .iter()
49 .find(|o| o.bin1("objectSid").and_then(Sid::from_bytes).as_ref() == Some(sid))
50 }
51
52 pub fn by_sam(&self, sam: &str) -> Option<&AdObject> {
55 self.objects.iter().find(|o| {
56 o.one("sAMAccountName")
57 .is_some_and(|s| s.eq_ignore_ascii_case(sam))
58 })
59 }
60
61 pub fn iter_class<'a>(&'a self, class: &'a str) -> impl Iterator<Item = &'a AdObject> {
62 self.objects.iter().filter(move |o| o.has_class(class))
63 }
64
65 pub fn by_rid(&self, rid: u32) -> Option<&AdObject> {
67 let dsid = self.domain.domain_sid.as_ref()?;
68 self.objects.iter().find(|o| {
69 o.bin1("objectSid")
70 .and_then(Sid::from_bytes)
71 .map(|s| {
72 s.rid() == Some(rid)
73 && s.sub_authorities[..s.sub_authorities.len() - 1]
74 == dsid.sub_authorities[..]
75 })
76 .unwrap_or(false)
77 })
78 }
79}