rusthound_ce/objects/
fsp.rs

1use serde_json::value::Value;
2use serde::{Deserialize, Serialize};
3use ldap3::SearchEntry;
4use log::{debug, trace};
5use std::collections::HashMap;
6use std::error::Error;
7
8use crate::enums::regex::OBJECT_SID_RE1;
9use crate::objects::common::{LdapObject, AceTemplate, SPNTarget, Link, Member};
10use crate::utils::date::string_to_epoch;
11use crate::enums::secdesc::LdapSid;
12use crate::enums::sid::{objectsid_to_vec8, sid_maker};
13
14/// FSP (ForeignSecurityPrincipal) structure
15#[derive(Debug, Clone, Deserialize, Serialize, Default)]
16pub struct Fsp {
17    #[serde(rename = "Properties")]
18    properties: FspProperties,
19    #[serde(rename = "Aces")]
20    aces: Vec<AceTemplate>,
21    #[serde(rename = "ObjectIdentifier")]
22    object_identifier: String,
23    #[serde(rename = "IsDeleted")]
24    is_deleted: bool,
25    #[serde(rename = "IsACLProtected")]
26    is_acl_protected: bool,
27    #[serde(rename = "ContainedBy")]
28    contained_by: Option<Member>,
29}
30
31impl Fsp {
32    // New FSP
33    pub fn new() -> Self { 
34        Self { ..Default::default() } 
35    }
36
37    /// Function to parse and replace value in json template for ForeignSecurityPrincipal object.
38    pub fn parse(
39        &mut self,
40        result: SearchEntry,
41        domain: &str,
42        dn_sid: &mut HashMap<String, String>,
43        sid_type: &mut HashMap<String, String>,
44        domain_sid: &str,
45    ) -> Result<(), Box<dyn Error>> {
46        let result_dn: String = result.dn.to_uppercase();
47        let result_attrs: HashMap<String, Vec<String>> = result.attrs;
48        let result_bin: HashMap<String, Vec<Vec<u8>>> = result.bin_attrs;
49
50        // Debug for current object
51        debug!("Parse ForeignSecurityPrincipal: {result_dn}");
52
53        // Trace all result attributes
54        for (key, value) in &result_attrs {
55            trace!("  {key:?}:{value:?}");
56        }
57        // Trace all bin result attributes
58        for (key, value) in &result_bin {
59            trace!("  {key:?}:{value:?}");
60        }
61
62        // Change all values...
63        self.properties.domain = domain.to_uppercase();
64        self.properties.distinguishedname = result_dn;    
65        self.properties.domainsid = domain_sid.to_string();
66
67        #[allow(unused_assignments)]
68        let mut sid: String = "".to_owned();
69        let mut ftype: &str = "Base";
70
71        // With a check
72        for (key, value) in &result_attrs {
73            match key.as_str() {
74                "name" => {
75                    let name = format!("{}-{}", domain, &value.first().unwrap_or(&"".to_owned()));
76                    self.properties.name = name.to_uppercase();
77
78                    // Type for group Member maker
79                    // based on https://docs.microsoft.com/fr-fr/troubleshoot/windows-server/identity/security-identifiers-in-windows
80                    let split = value[0].split("-").collect::<Vec<&str>>();
81
82                    // Not currently used:
83                    //let last = split.iter().last().unwrap_or(&"0").parse::<i32>().unwrap_or(0);
84                    if split.len() >= 17 {
85                        ftype = "User";
86                    } else {
87                        ftype = "Group";
88                    }
89                }
90                "whenCreated" => {
91                    let epoch = string_to_epoch(&value[0])?;
92                    if epoch.is_positive() {
93                        self.properties.whencreated = epoch;
94                    }
95                }
96                "objectSid" => {
97                    //objectSid to vec and raw to string
98                    let vec_sid = objectsid_to_vec8(&value[0]);
99                    sid = sid_maker(LdapSid::parse(&vec_sid).unwrap().1, domain);
100                    self.object_identifier = sid.to_owned();
101
102                    for domain_sid in OBJECT_SID_RE1.captures_iter(&sid) {
103                        self.properties.domainsid = domain_sid[0].to_owned().to_string();
104                    }
105                }
106                "IsDeleted" => {
107                    self.is_deleted = true;
108                }
109                _ => {}
110            }
111        }
112
113        // Push DN and SID in HashMap
114        if self.object_identifier != "SID" {
115            dn_sid.insert(
116                self.properties.distinguishedname.to_string(),
117                self.object_identifier.to_string()
118            );
119            // Push DN and Type
120            sid_type.insert(self.object_identifier.to_string(), ftype.to_string());
121        }
122
123        // Trace and return Fsp struct
124        // trace!("JSON OUTPUT: {:?}",serde_json::to_string(&self).unwrap());
125        Ok(())
126    }
127}
128
129/// Default FSP properties structure
130#[derive(Debug, Clone, Deserialize, Serialize, Default)]
131pub struct FspProperties {
132   domain: String,
133   name: String,
134   distinguishedname: String,
135   domainsid: String,
136   isaclprotected: bool,
137   highvalue: bool,
138   description: Option<String>,
139   whencreated: i64,
140}
141
142impl FspProperties {
143   // New default properties.
144   pub fn new(domain: String) -> Self { 
145      Self { 
146         domain,
147         whencreated: -1,
148         ..Default::default() }
149   }
150
151   // Immutable access.
152   pub fn domain(&self) -> &String {
153      &self.domain
154   }
155   pub fn name(&self) -> &String {
156      &self.name
157   }
158   pub fn distinguishedname(&self) -> &String {
159      &self.distinguishedname
160   }
161   pub fn domainsid(&self) -> &String {
162      &self.domainsid
163   }
164   pub fn highvalue(&self) -> &bool {
165      &self.highvalue
166   }
167   pub fn description(&self) -> &Option<String> {
168      &self.description
169   }
170   pub fn whencreated(&self) -> &i64 {
171      &self.whencreated
172   }
173
174   // Mutable access.
175   pub fn domain_mut(&mut self) -> &mut String {
176      &mut self.domain
177   }
178   pub fn name_mut(&mut self) -> &mut String {
179      &mut self.name
180   }
181   pub fn distinguishedname_mut(&mut self) -> &mut String {
182      &mut self.distinguishedname
183   }
184   pub fn domainsid_mut(&mut self) -> &mut String {
185      &mut self.domainsid
186   }
187   pub fn highvalue_mut(&mut self) -> &mut bool {
188      &mut self.highvalue
189   }
190   pub fn description_mut(&mut self) -> &mut Option<String> {
191      &mut self.description
192   }
193   pub fn whencreated_mut(&mut self) -> &mut i64 {
194      &mut self.whencreated
195   }
196}
197
198impl LdapObject for Fsp {
199    // To JSON
200    fn to_json(&self) -> Value {
201        serde_json::to_value(self).unwrap()
202    }
203
204    // Get values
205    fn get_object_identifier(&self) -> &String {
206        &self.object_identifier
207    }
208    fn get_is_acl_protected(&self) -> &bool {
209        &self.is_acl_protected
210    }
211    fn get_aces(&self) -> &Vec<AceTemplate> {
212        &self.aces
213    }
214    fn get_spntargets(&self) -> &Vec<SPNTarget> {
215        panic!("Not used by current object.");
216    }
217    fn get_allowed_to_delegate(&self) -> &Vec<Member> {
218        panic!("Not used by current object.");
219    }
220    fn get_links(&self) -> &Vec<Link> {
221        panic!("Not used by current object.");
222    }
223    fn get_contained_by(&self) -> &Option<Member> {
224        &self.contained_by
225    }
226    fn get_child_objects(&self) -> &Vec<Member> {
227        panic!("Not used by current object.");
228    }
229    fn get_haslaps(&self) -> &bool {
230        &false
231    }
232    
233    // Get mutable values
234    fn get_aces_mut(&mut self) -> &mut Vec<AceTemplate> {
235        &mut self.aces
236    }
237    fn get_spntargets_mut(&mut self) -> &mut Vec<SPNTarget> {
238        panic!("Not used by current object.");
239    }
240    fn get_allowed_to_delegate_mut(&mut self) -> &mut Vec<Member> {
241        panic!("Not used by current object.");
242    }
243    
244    // Edit values
245    fn set_is_acl_protected(&mut self, is_acl_protected: bool) {
246        self.is_acl_protected = is_acl_protected;
247        self.properties.isaclprotected = is_acl_protected;
248    }
249    fn set_aces(&mut self, aces: Vec<AceTemplate>) {
250        self.aces = aces;
251    }
252    fn set_spntargets(&mut self, _spn_targets: Vec<SPNTarget>) {
253        // Not used by current object.
254    }
255    fn set_allowed_to_delegate(&mut self, _allowed_to_delegate: Vec<Member>) {
256        // Not used by current object.
257    }
258    fn set_links(&mut self, _links: Vec<Link>) {
259        // Not used by current object.
260    }
261    fn set_contained_by(&mut self, contained_by: Option<Member>) {
262        self.contained_by = contained_by;
263    }
264    fn set_child_objects(&mut self, _child_objects: Vec<Member>) {
265        // Not used by current object.
266    }
267}