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