rusthound_ce/objects/
fsp.rs1use 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#[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 pub fn new() -> Self {
35 Self { ..Default::default() }
36 }
37
38 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!("Parse ForeignSecurityPrincipal: {result_dn}");
53
54 for (key, value) in &result_attrs {
56 trace!(" {key:?}:{value:?}");
57 }
58 for (key, value) in &result_bin {
60 trace!(" {key:?}:{value:?}");
61 }
62
63 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 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 let split = value[0].split("-").collect::<Vec<&str>>();
82
83 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 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 (key, value) in &result_bin {
117 match key.as_str() {
118 "objectGUID" => {
119 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 if self.object_identifier != "SID" {
130 dn_sid.insert(
131 self.properties.distinguishedname.to_string(),
132 self.object_identifier.to_string()
133 );
134 sid_type.insert(self.object_identifier.to_string(), ftype.to_string());
136 }
137
138 Ok(())
141 }
142}
143
144#[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 pub fn new(domain: String) -> Self {
163 Self {
164 domain,
165 whencreated: -1,
166 ..Default::default() }
167 }
168
169 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 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 fn to_json(&self) -> Value {
219 serde_json::to_value(self).unwrap()
220 }
221
222 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 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 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 }
273 fn set_allowed_to_delegate(&mut self, _allowed_to_delegate: Vec<Member>) {
274 }
276 fn set_links(&mut self, _links: Vec<Link>) {
277 }
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 }
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}