rusthound_ce/objects/
inssuancepolicie.rs

1use serde_json::value::Value;
2use serde::{Deserialize, Serialize};
3
4use crate::enums::{decode_guid_le, parse_ntsecuritydescriptor};
5use crate::utils::date::string_to_epoch;
6use crate::objects::common::{
7    LdapObject,
8    AceTemplate,
9    SPNTarget,
10    Link,
11    Member
12};
13
14use ldap3::SearchEntry;
15use log::{debug, trace};
16use std::collections::HashMap;
17use std::error::Error;
18
19/// IssuancePolicie structure
20#[derive(Debug, Clone, Deserialize, Serialize, Default)]
21pub struct IssuancePolicie {
22    #[serde(rename = "Properties")]
23    properties: IssuancePolicieProperties,
24    #[serde(rename = "GroupLink")]
25    group_link: GroupLink,
26    #[serde(rename = "Aces")]
27    aces: Vec<AceTemplate>,
28    #[serde(rename = "ObjectIdentifier")]
29    object_identifier: String,
30    #[serde(rename = "IsDeleted")]
31    is_deleted: bool,
32    #[serde(rename = "IsACLProtected")]
33    is_acl_protected: bool,
34    #[serde(rename = "ContainedBy")]
35    contained_by: Option<Member>,
36}
37
38impl IssuancePolicie {
39    // New IssuancePolicie
40    pub fn new() -> Self { 
41        Self {
42            ..Default::default() 
43        } 
44    }
45
46    /// Function to parse and replace value in json template for IssuancePolicie object.
47    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 for current object
60        debug!("Parse IssuancePolicie: {}", result_dn);
61        // Trace all result attributes
62        for (key, value) in &result_attrs {
63            trace!("  {:?}:{:?}", key, value);
64        }
65        // Trace all bin result attributes
66        for (key, value) in &result_bin {
67            trace!("  {:?}:{:?}", key, value);
68        }
69
70        // Change all values...
71        self.properties.domain = domain.to_uppercase();
72        self.properties.distinguishedname = result_dn;    
73        self.properties.domainsid = domain_sid.to_string();
74
75        // With a check
76        for (key, value) in &result_attrs {
77            match key.as_str() {
78                "description" => {
79                    self.properties.description = Some(value[0].to_owned());
80                }
81                "whenCreated" => {
82                    let epoch = string_to_epoch(&value[0])?;
83                    if epoch.is_positive() {
84                        self.properties.whencreated = epoch;
85                    }
86                }
87                "IsDeleted" => {
88                    self.is_deleted = true.into();
89                }
90                "displayName" => {
91                    self.properties.name = format!("{}@{}",&value[0],domain).to_uppercase();
92                    self.properties.displayname = value[0].to_owned();
93                }
94                "msPKI-Cert-Template-OID" => {
95                    self.properties.certtemplateoid = value[0].to_owned();
96                }
97                _ => {}
98            }
99        }
100
101        // For all, bins attributs
102        for (key, value) in &result_bin {
103            match key.as_str() {
104                "objectGUID" => {
105                    // objectGUID raw to string
106                    let guid = decode_guid_le(&value[0]);
107                    self.object_identifier = guid.to_owned().into();
108                }
109                "nTSecurityDescriptor" => {
110                    // Needed with acl
111                    let entry_type = "IssuancePolicie".to_string();
112                    // nTSecurityDescriptor raw to string
113                    let relations_ace = parse_ntsecuritydescriptor(
114                        self,
115                         &value[0],
116                        entry_type,
117                         &result_attrs,
118                         &result_bin,
119                         &domain,
120                    );
121                    self.aces = relations_ace;
122                }
123                _ => {}
124            }
125        }
126
127        // Push DN and SID in HashMap
128        if self.object_identifier.to_string() != "SID" {
129            dn_sid.insert(
130                self.properties.distinguishedname.to_owned(),
131                self.object_identifier.to_owned()
132            );
133            // Push DN and Type
134            sid_type.insert(
135                self.object_identifier.to_owned(),
136                "IssuancePolicie".to_string()
137            );
138        }
139
140        // Trace and return IssuancePolicie struct
141        // trace!("JSON OUTPUT: {:?}",serde_json::to_string(&self).unwrap());
142        Ok(())
143    }
144}
145
146impl LdapObject for IssuancePolicie {
147    // To JSON
148    fn to_json(&self) -> Value {
149        serde_json::to_value(&self).unwrap()
150    }
151
152    // Get values
153    fn get_object_identifier(&self) -> &String {
154         &self.object_identifier
155    }
156    fn get_is_acl_protected(&self) -> &bool {
157         &self.is_acl_protected
158    }
159    fn get_aces(&self) -> &Vec<AceTemplate> {
160         &self.aces
161    }
162    fn get_spntargets(&self) -> &Vec<SPNTarget> {
163        panic!("Not used by current object.");
164    }
165    fn get_allowed_to_delegate(&self) -> &Vec<Member> {
166        panic!("Not used by current object.");
167    }
168    fn get_links(&self) -> &Vec<Link> {
169        panic!("Not used by current object.");
170    }
171    fn get_contained_by(&self) -> &Option<Member> {
172         &self.contained_by
173    }
174    fn get_child_objects(&self) -> &Vec<Member> {
175        panic!("Not used by current object.");
176    }
177    fn get_haslaps(&self) -> &bool {
178         &false
179    }
180    
181    // Get mutable values
182    fn get_aces_mut(&mut self) -> &mut Vec<AceTemplate> {
183         &mut self.aces
184    }
185    fn get_spntargets_mut(&mut self) -> &mut Vec<SPNTarget> {
186        panic!("Not used by current object.");
187    }
188    fn get_allowed_to_delegate_mut(&mut self) -> &mut Vec<Member> {
189        panic!("Not used by current object.");
190    }
191    
192    // Edit values
193    fn set_is_acl_protected(&mut self, is_acl_protected: bool) {
194        self.is_acl_protected = is_acl_protected;
195        self.properties.isaclprotected = is_acl_protected;
196    }
197    fn set_aces(&mut self, aces: Vec<AceTemplate>) {
198        self.aces = aces;
199    }
200    fn set_spntargets(&mut self, _spn_targets: Vec<SPNTarget>) {
201        // Not used by current object.
202    }
203    fn set_allowed_to_delegate(&mut self, _allowed_to_delegate: Vec<Member>) {
204        // Not used by current object.
205    }
206    fn set_links(&mut self, _links: Vec<Link>) {
207        // Not used by current object.
208    }
209    fn set_contained_by(&mut self, contained_by: Option<Member>) {
210        self.contained_by = contained_by;
211    }
212    fn set_child_objects(&mut self, _child_objects: Vec<Member>) {
213        // Not used by current object.
214    }
215}
216
217
218// IssuancePolicie properties structure
219#[derive(Debug, Clone, Deserialize, Serialize)]
220pub struct IssuancePolicieProperties {
221    domain: String,
222    name: String,
223    distinguishedname: String,
224    domainsid: String,
225    isaclprotected: bool,
226    description: Option<String>,
227    whencreated: i64,
228    displayname: String,
229    certtemplateoid: String,
230}
231
232impl Default for IssuancePolicieProperties {
233    fn default() -> IssuancePolicieProperties {
234        IssuancePolicieProperties {
235            domain: String::from(""),
236            name: String::from(""),
237            distinguishedname: String::from(""),
238            domainsid: String::from(""),
239            isaclprotected: false,
240            description: None,
241            whencreated: -1,
242            displayname: String::from(""),
243            certtemplateoid: String::from(""),
244        }
245    }
246}
247/// GroupLink structure
248#[derive(Debug, Clone, Deserialize, Serialize)]
249pub struct GroupLink {
250    #[serde(rename = "ObjectIdentifier")]
251    object_identifier: Option<String>,
252    #[serde(rename = "ObjectType")]
253    object_type: String,
254}
255
256impl GroupLink {
257    // New object.
258    pub fn new(object_identifier: Option<String>, object_type: String) -> Self { Self { object_identifier, object_type } }
259
260    // Immutable access.
261    pub fn object_identifier(&self) -> &Option<String> {
262        &self.object_identifier
263    }
264    pub fn object_type(&self) -> &String {
265        &self.object_type
266    }
267 
268    // Mutable access.
269    pub fn object_identifier_mut(&mut self) -> &mut Option<String> {
270        &mut self.object_identifier
271    }
272    pub fn object_type_mut(&mut self) -> &mut String {
273        &mut self.object_type
274    }
275}
276
277// Implement Default trait for GroupLink
278impl Default for GroupLink {
279    fn default() -> Self {
280        Self {
281            object_identifier: None,
282            object_type: "Base".to_string(),
283        }
284    }
285}