rusthound_ce/objects/
container.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::objects::common::{LdapObject, AceTemplate, SPNTarget, Link, Member};
9use crate::enums::acl::parse_ntsecuritydescriptor;
10use crate::enums::sid::decode_guid_le;
11use crate::utils::date::string_to_epoch;
12
13
14#[derive(Debug, Clone, Deserialize, Serialize, Default)]
16pub struct Container {
17 #[serde(rename = "Properties")]
18 properties: ContainerProperties,
19 #[serde(rename = "ChildObjects")]
20 child_objects: Vec<Member>,
21 #[serde(rename = "Aces")]
22 aces: Vec<AceTemplate>,
23 #[serde(rename = "ObjectIdentifier")]
24 object_identifier: String,
25 #[serde(rename = "IsDeleted")]
26 is_deleted: bool,
27 #[serde(rename = "IsACLProtected")]
28 is_acl_protected: bool,
29 #[serde(rename = "ContainedBy")]
30 contained_by: Option<Member>,
31 }
32
33impl Container {
34 pub fn new() -> Self {
36 Self { ..Default::default() }
37 }
38
39 pub fn parse(
41 &mut self,
42 result: SearchEntry,
43 domain: &str,
44 dn_sid: &mut HashMap<String, String>,
45 sid_type: &mut HashMap<String, String>,
46 domain_sid: &str
47 ) -> Result<(), Box<dyn Error>> {
48 let result_dn: String = result.dn.to_uppercase();
49 let result_attrs: HashMap<String, Vec<String>> = result.attrs;
50 let result_bin: HashMap<String, Vec<Vec<u8>>> = result.bin_attrs;
51
52 debug!("Parse Container: {result_dn}");
54
55 for (key, value) in &result_attrs {
57 trace!(" {key:?}:{value:?}");
58 }
59 for (key, value) in &result_bin {
61 trace!(" {key:?}:{value:?}");
62 }
63
64 self.properties.domain = domain.to_uppercase();
66 self.properties.distinguishedname = result_dn;
67 self.properties.domainsid = domain_sid.to_string();
68
69 for (key, value) in &result_attrs {
71 match key.as_str() {
72 "name" => {
73 let name = &value[0];
74 let email = format!("{}@{}",name.to_owned(),domain);
75 self.properties.name = email.to_uppercase();
76 }
77 "description" => {
78 self.properties.description = Some(value[0].to_owned());
79 }
80 "whenCreated" => {
81 let epoch = string_to_epoch(&value[0])?;
82 if epoch.is_positive() {
83 self.properties.whencreated = epoch;
84 }
85 }
86 _ => {}
87 }
88 }
89 for (key, value) in &result_bin {
91 match key.as_str() {
92 "objectGUID" => {
93 let guid = decode_guid_le(&value[0]);
94 self.object_identifier = guid.to_owned();
95 }
96 "nTSecurityDescriptor" => {
97 let relations_ace = parse_ntsecuritydescriptor(
99 self,
100 &value[0],
101 "Container",
102 &result_attrs,
103 &result_bin,
104 domain,
105 );
106 self.aces = relations_ace;
107 }
108 "IsDeleted" => {
109 self.is_deleted = true;
110 }
111 _ => {}
112 }
113 }
114
115 dn_sid.insert(
117 self.properties.distinguishedname.to_string(),
118 self.object_identifier.to_string()
119 );
120 sid_type.insert(
122 self.object_identifier.to_string(),
123 "Container".to_string(),
124 );
125
126 Ok(())
129 }
130}
131
132#[derive(Debug, Clone, Deserialize, Serialize, Default)]
134pub struct ContainerProperties {
135 domain: String,
136 name: String,
137 distinguishedname: String,
138 domainsid: String,
139 isaclprotected: bool,
140 highvalue: bool,
141 description: Option<String>,
142 whencreated: i64,
143}
144
145impl LdapObject for Container {
146 fn to_json(&self) -> Value {
148 serde_json::to_value(self).unwrap()
149 }
150
151 fn get_object_identifier(&self) -> &String {
153 &self.object_identifier
154 }
155 fn get_is_acl_protected(&self) -> &bool {
156 &self.is_acl_protected
157 }
158 fn get_aces(&self) -> &Vec<AceTemplate> {
159 &self.aces
160 }
161 fn get_spntargets(&self) -> &Vec<SPNTarget> {
162 panic!("Not used by current object.");
163 }
164 fn get_allowed_to_delegate(&self) -> &Vec<Member> {
165 panic!("Not used by current object.");
166 }
167 fn get_links(&self) -> &Vec<Link> {
168 panic!("Not used by current object.");
169 }
170 fn get_contained_by(&self) -> &Option<Member> {
171 &self.contained_by
172 }
173 fn get_child_objects(&self) -> &Vec<Member> {
174 &self.child_objects
175 }
176 fn get_haslaps(&self) -> &bool {
177 &false
178 }
179
180 fn get_aces_mut(&mut self) -> &mut Vec<AceTemplate> {
182 &mut self.aces
183 }
184 fn get_spntargets_mut(&mut self) -> &mut Vec<SPNTarget> {
185 panic!("Not used by current object.");
186 }
187 fn get_allowed_to_delegate_mut(&mut self) -> &mut Vec<Member> {
188 panic!("Not used by current object.");
189 }
190
191 fn set_is_acl_protected(&mut self, is_acl_protected: bool) {
193 self.is_acl_protected = is_acl_protected;
194 self.properties.isaclprotected = is_acl_protected;
195 }
196 fn set_aces(&mut self, aces: Vec<AceTemplate>) {
197 self.aces = aces;
198 }
199 fn set_spntargets(&mut self, _spn_targets: Vec<SPNTarget>) {
200 }
202 fn set_allowed_to_delegate(&mut self, _allowed_to_delegate: Vec<Member>) {
203 }
205 fn set_links(&mut self, _links: Vec<Link>) {
206 }
208 fn set_contained_by(&mut self, contained_by: Option<Member>) {
209 self.contained_by = contained_by;
210 }
211 fn set_child_objects(&mut self, child_objects: Vec<Member>) {
212 self.child_objects = child_objects
213 }
214}