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::objects::common::{LdapObject, AceTemplate, SPNTarget, Link, Member};
9use crate::enums::{decode_guid_le, get_pki_cert_name_flags, get_pki_enrollment_flags, parse_ntsecuritydescriptor};
10use crate::json::checker::common::get_name_from_full_distinguishedname;
11use crate::utils::date::{filetime_to_span, span_to_string, string_to_epoch};
12
13#[derive(Debug, Clone, Deserialize, Serialize, Default)]
15pub struct CertTemplate {
16 #[serde(rename = "Properties")]
17 properties: CertTemplateProperties,
18 #[serde(rename = "Aces")]
19 aces: Vec<AceTemplate>,
20 #[serde(rename = "ObjectIdentifier")]
21 object_identifier: String,
22 #[serde(rename = "IsDeleted")]
23 is_deleted: bool,
24 #[serde(rename = "IsACLProtected")]
25 is_acl_protected: bool,
26 #[serde(rename = "ContainedBy")]
27 contained_by: Option<Member>,
28}
29
30impl CertTemplate {
31 pub fn new() -> Self {
33 Self { ..Default::default() }
34 }
35
36 pub fn properties(&self) -> &CertTemplateProperties {
38 &self.properties
39 }
40 pub fn object_identifier(&self) -> &String {
41 &self.object_identifier
42 }
43
44 pub fn parse(
46 &mut self,
47 result: SearchEntry,
48 domain: &str,
49 dn_sid: &mut HashMap<String, String>,
50 sid_type: &mut HashMap<String, String>,
51 domain_sid: &str,
52 schema_guid_map: &HashMap<String, String>,
53 ) -> Result<(), Box<dyn Error>> {
54 let result_dn: String = result.dn.to_uppercase();
55 let result_attrs: HashMap<String, Vec<String>> = result.attrs;
56 let result_bin: HashMap<String, Vec<Vec<u8>>> = result.bin_attrs;
57
58 debug!("Parse CertTemplate: {result_dn}");
60
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 let _ca_name = get_name_from_full_distinguishedname(&self.properties.distinguishedname);
75
76 for (key, value) in &result_attrs {
78 match key.as_str() {
79 "name" => {
80 let name = format!("{}@{}",&value[0],domain);
81 self.properties.name = name.to_uppercase();
82 }
83 "description" => {
84 self.properties.description = Some(value[0].to_owned());
85 }
86 "displayName" => {
87 self.properties.displayname = value[0].to_owned();
88 }
89 "msPKI-Certificate-Name-Flag" => {
90 if !value.is_empty() {
91 self.properties.certificatenameflag = get_pki_cert_name_flags(value[0].parse::<i64>().unwrap_or(0) as u64);
92 self.properties.enrolleesuppliessubject = self.properties.certificatenameflag.contains("ENROLLEE_SUPPLIES_SUBJECT");
93 self.properties.subjectaltrequireupn = self.properties.certificatenameflag.contains("SUBJECT_ALT_REQUIRE_UPN");
94 }
95 }
96 "msPKI-Enrollment-Flag" => {
97 if !value.is_empty() {
98 self.properties.enrollmentflag = get_pki_enrollment_flags(value[0].parse::<i64>().unwrap_or(0) as u64);
99 self.properties.requiresmanagerapproval = self.properties.enrollmentflag.contains("PEND_ALL_REQUESTS");
100 self.properties.nosecurityextension = self.properties.enrollmentflag.contains("NO_SECURITY_EXTENSION");
101 }
102 }
103 "msPKI-Private-Key-Flag" => {
104 }
108 "msPKI-RA-Signature" => {
109 if !value.is_empty() {
110 self.properties.authorizedsignatures = value.first().unwrap_or(&"0".to_string()).parse::<i64>().unwrap_or(0);
111 }
112 }
113 "msPKI-RA-Application-Policies" => {
114 if !value.is_empty() {
115 self.properties.applicationpolicies = value.to_owned();
116 }
117 }
118 "msPKI-Certificate-Application-Policy" => {
119 if !value.is_empty() {
120 self.properties.certificateapplicationpolicy = value.to_owned();
121 }
122 }
123 "msPKI-RA-Policies" => {
124 if !value.is_empty() {
125 self.properties.issuancepolicies = value.to_owned();
126 }
127 }
128 "msPKI-Cert-Template-OID" => {
129 if !value.is_empty() {
130 self.properties.oid = value[0].to_owned();
131 }
132 }
133 "pKIExtendedKeyUsage" => {
134 if !value.is_empty() {
135 self.properties.ekus = value.to_owned();
136 }
137 }
138 "msPKI-Template-Schema-Version" => {
139 self.properties.schemaversion = value[0].parse::<i64>().unwrap_or(0);
140 }
141 "whenCreated" => {
142 let epoch = string_to_epoch(&value[0])?;
143 if epoch.is_positive() {
144 self.properties.whencreated = epoch;
145 }
146 }
147 "IsDeleted" => {
148 self.is_deleted = true;
149 }
150 _ => {}
151 }
152 }
153
154 for (key, value) in &result_bin {
156 match key.as_str() {
157 "objectGUID" => {
158 let guid = decode_guid_le(&value[0]);
160 self.object_identifier = guid.to_owned();
161 }
162 "nTSecurityDescriptor" => {
163 let relations_ace = parse_ntsecuritydescriptor(
165 self,
166 &value[0],
167 "CertTemplate",
168 &result_attrs,
169 &result_bin,
170 domain,
171 schema_guid_map,
172 );
173 self.aces = relations_ace;
174 }
175 "pKIExpirationPeriod" => {
176 self.properties.validityperiod = span_to_string(filetime_to_span(value[0].to_owned())?);
177 }
178 "pKIOverlapPeriod" => {
179 self.properties.renewalperiod = span_to_string(filetime_to_span(value[0].to_owned())?);
180 }
181 _ => {}
182 }
183 }
184
185 self.properties.effectiveekus = Self::get_effectiveekus(
187 &self.properties.schemaversion,
188 &self.properties.ekus,
189 &self.properties.certificateapplicationpolicy,
190 );
191
192 self.properties.authenticationenabled = Self::authentication_is_enabled(self);
194
195 if self.object_identifier != "SID" {
197 dn_sid.insert(
198 self.properties.distinguishedname.to_string(),
199 self.object_identifier.to_string()
200 );
201 sid_type.insert(
203 self.object_identifier.to_string(),
204 "CertTemplate".to_string()
205 );
206 }
207
208 Ok(())
211 }
212
213 fn get_effectiveekus(
215 schema_version: &i64,
216 ekus: &[String],
217 certificateapplicationpolicy: &[String],
218 ) -> Vec<String> {
219 if schema_version == &1 && !ekus.is_empty() {
220 ekus.to_vec()
221 } else {
222 certificateapplicationpolicy.to_vec()
223 }
224 }
225
226 fn authentication_is_enabled(&mut self) -> bool {
228 let authentication_oids = [
229 "1.3.6.1.5.5.7.3.2", "1.3.6.1.5.2.3.4", "1.3.6.1.4.1.311.20.2.2", "2.5.29.37.0", ];
234 self.properties.effectiveekus.iter()
235 .any(|eku| authentication_oids.contains(&eku.as_str()))
236 || self.properties.effectiveekus.is_empty()
237 }
238}
239
240impl LdapObject for CertTemplate {
241 fn to_json(&self) -> Value {
243 serde_json::to_value(self).unwrap()
244 }
245
246 fn get_object_identifier(&self) -> &String {
248 &self.object_identifier
249 }
250 fn get_is_acl_protected(&self) -> &bool {
251 &self.is_acl_protected
252 }
253 fn get_aces(&self) -> &Vec<AceTemplate> {
254 &self.aces
255 }
256 fn get_spntargets(&self) -> &Vec<SPNTarget> {
257 panic!("Not used by current object.");
258 }
259 fn get_allowed_to_delegate(&self) -> &Vec<Member> {
260 panic!("Not used by current object.");
261 }
262 fn get_links(&self) -> &Vec<Link> {
263 panic!("Not used by current object.");
264 }
265 fn get_contained_by(&self) -> &Option<Member> {
266 &self.contained_by
267 }
268 fn get_child_objects(&self) -> &Vec<Member> {
269 panic!("Not used by current object.");
270 }
271 fn get_haslaps(&self) -> &bool {
272 &false
273 }
274
275 fn get_aces_mut(&mut self) -> &mut Vec<AceTemplate> {
277 &mut self.aces
278 }
279 fn get_spntargets_mut(&mut self) -> &mut Vec<SPNTarget> {
280 panic!("Not used by current object.");
281 }
282 fn get_allowed_to_delegate_mut(&mut self) -> &mut Vec<Member> {
283 panic!("Not used by current object.");
284 }
285
286 fn set_is_acl_protected(&mut self, is_acl_protected: bool) {
288 self.is_acl_protected = is_acl_protected;
289 self.properties.isaclprotected = is_acl_protected;
290 }
291 fn set_aces(&mut self, aces: Vec<AceTemplate>) {
292 self.aces = aces;
293 }
294 fn set_spntargets(&mut self, _spn_targets: Vec<SPNTarget>) {
295 }
297 fn set_allowed_to_delegate(&mut self, _allowed_to_delegate: Vec<Member>) {
298 }
300 fn set_links(&mut self, _links: Vec<Link>) {
301 }
303 fn set_contained_by(&mut self, contained_by: Option<Member>) {
304 self.contained_by = contained_by;
305 }
306 fn set_child_objects(&mut self, _child_objects: Vec<Member>) {
307 }
309}
310
311
312#[derive(Debug, Clone, Deserialize, Serialize)]
314pub struct CertTemplateProperties {
315 domain: String,
316 name: String,
317 distinguishedname: String,
318 domainsid: String,
319 isaclprotected: bool,
320 description: Option<String>,
321 whencreated: i64,
322 validityperiod: String,
323 renewalperiod: String,
324 schemaversion: i64,
325 displayname: String,
326 oid: String,
327 enrollmentflag: String,
328 requiresmanagerapproval: bool,
329 nosecurityextension: bool,
330 certificatenameflag: String,
331 enrolleesuppliessubject: bool,
332 subjectaltrequireupn: bool,
333 ekus: Vec<String>,
334 certificateapplicationpolicy: Vec<String>,
335 authorizedsignatures: i64,
336 applicationpolicies: Vec<String>,
337 issuancepolicies: Vec<String>,
338 effectiveekus: Vec<String>,
339 authenticationenabled: bool,
340}
341
342impl Default for CertTemplateProperties {
343 fn default() -> CertTemplateProperties {
344 CertTemplateProperties {
345 domain: String::from(""),
346 name: String::from(""),
347 distinguishedname: String::from(""),
348 domainsid: String::from(""),
349 isaclprotected: false,
350 description: None,
351 whencreated: -1,
352 validityperiod: String::from(""),
353 renewalperiod: String::from(""),
354 schemaversion: 1,
355 displayname: String::from(""),
356 oid: String::from(""),
357 enrollmentflag: String::from(""),
358 requiresmanagerapproval: false,
359 nosecurityextension: false,
360 certificatenameflag: String::from(""),
361 enrolleesuppliessubject: false,
362 subjectaltrequireupn: true,
363 ekus: Vec::new(),
364 certificateapplicationpolicy: Vec::new(),
365 authorizedsignatures: 0,
366 applicationpolicies: Vec::new(),
367 issuancepolicies: Vec::new(),
368 effectiveekus: Vec::new(),
369 authenticationenabled: false,
370 }
371 }
372 }
373
374impl CertTemplateProperties {
375 pub fn name(&self) -> &String {
377 &self.name
378 }
379}