Skip to main content

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