1use std::collections::HashMap;
11use windows_sddl::sid::Guid;
12
13pub mod names {
15 pub const LAPS_LEGACY: &str = "ms-Mcs-AdmPwd";
17 pub const LAPS_PASSWORD: &str = "msLAPS-Password";
19 pub const LAPS_ENCRYPTED: &str = "msLAPS-EncryptedPassword";
21 pub const MANAGED_PASSWORD: &str = "msDS-ManagedPassword";
23 pub const DMSA_CLASS: &str = "msDS-DelegatedManagedServiceAccount";
25}
26
27#[derive(Clone, Debug, Default)]
29pub struct SchemaMap {
30 by_guid: HashMap<Guid, String>,
31 by_name: HashMap<String, Guid>,
32}
33
34impl SchemaMap {
35 pub fn new() -> Self {
36 Self::default()
37 }
38
39 pub fn from_entries<I, S>(entries: I) -> Self
41 where
42 I: IntoIterator<Item = (S, Guid)>,
43 S: AsRef<str>,
44 {
45 let mut m = SchemaMap::new();
46 for (name, guid) in entries {
47 m.insert(name.as_ref(), guid);
48 }
49 m
50 }
51
52 pub fn insert(&mut self, name: &str, guid: Guid) {
53 self.by_guid.insert(guid, name.to_string());
54 self.by_name.insert(name.to_ascii_lowercase(), guid);
55 }
56
57 pub fn is_empty(&self) -> bool {
58 self.by_name.is_empty()
59 }
60
61 pub fn name(&self, g: &Guid) -> Option<&str> {
63 self.by_guid.get(g).map(String::as_str)
64 }
65
66 pub fn guid(&self, name: &str) -> Option<Guid> {
68 self.by_name.get(&name.to_ascii_lowercase()).copied()
69 }
70
71 pub fn is_laps_attr(&self, g: &Guid) -> bool {
73 matches!(
74 self.name(g),
75 Some(n) if n.eq_ignore_ascii_case(names::LAPS_LEGACY)
76 || n.eq_ignore_ascii_case(names::LAPS_PASSWORD)
77 || n.eq_ignore_ascii_case(names::LAPS_ENCRYPTED)
78 )
79 }
80
81 pub fn is_managed_password_attr(&self, g: &Guid) -> bool {
83 matches!(self.name(g), Some(n) if n.eq_ignore_ascii_case(names::MANAGED_PASSWORD))
84 }
85
86 pub fn is_dmsa_class(&self, g: &Guid) -> bool {
88 matches!(self.name(g), Some(n) if n.eq_ignore_ascii_case(names::DMSA_CLASS))
89 }
90}