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