Skip to main content

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