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 ) -> Result<(), Box<dyn Error>> {
53 let result_dn: String = result.dn.to_uppercase();
54 let result_attrs: HashMap<String, Vec<String>> = result.attrs;
55 let result_bin: HashMap<String, Vec<Vec<u8>>> = result.bin_attrs;
56
57 debug!("Parse CertTemplate: {result_dn}");
59
60 for (key, value) in &result_attrs {
62 trace!(" {key:?}:{value:?}");
63 }
64 for (key, value) in &result_bin {
66 trace!(" {key:?}:{value:?}");
67 }
68
69 self.properties.domain = domain.to_uppercase();
71 self.properties.distinguishedname = result_dn;
72 self.properties.domainsid = domain_sid.to_string();
73 let _ca_name = get_name_from_full_distinguishedname(&self.properties.distinguishedname);
74
75 for (key, value) in &result_attrs {
77 match key.as_str() {
78 "name" => {
79 let name = format!("{}@{}",&value[0],domain);
80 self.properties.name = name.to_uppercase();
81 }
82 "description" => {
83 self.properties.description = Some(value[0].to_owned());
84 }
85 "displayName" => {
86 self.properties.displayname = value[0].to_owned();
87 }
88 "msPKI-Certificate-Name-Flag" => {
89 if !value.is_empty() {
90 self.properties.certificatenameflag = get_pki_cert_name_flags(value[0].parse::<i64>().unwrap_or(0) as u64);
91 self.properties.enrolleesuppliessubject = self.properties.certificatenameflag.contains("ENROLLEE_SUPPLIES_SUBJECT");
92 self.properties.subjectaltrequireupn = self.properties.certificatenameflag.contains("SUBJECT_ALT_REQUIRE_UPN");
93 }
94 }
95 "msPKI-Enrollment-Flag" => {
96 if !value.is_empty() {
97 self.properties.enrollmentflag = get_pki_enrollment_flags(value[0].parse::<i64>().unwrap_or(0) as u64);
98 self.properties.requiresmanagerapproval = self.properties.enrollmentflag.contains("PEND_ALL_REQUESTS");
99 self.properties.nosecurityextension = self.properties.enrollmentflag.contains("NO_SECURITY_EXTENSION");
100 }
101 }
102 "msPKI-Private-Key-Flag" => {
103 }
107 "msPKI-RA-Signature" => {
108 if !value.is_empty() {
109 self.properties.authorizedsignatures = value.first().unwrap_or(&"0".to_string()).parse::<i64>().unwrap_or(0);
110 }
111 }
112 "msPKI-RA-Application-Policies" => {
113 if !value.is_empty() {
114 self.properties.applicationpolicies = value.to_owned();
115 }
116 }
117 "msPKI-Certificate-Application-Policy" => {
118 if !value.is_empty() {
119 self.properties.certificateapplicationpolicy = value.to_owned();
120 }
121 }
122 "msPKI-RA-Policies" => {
123 if !value.is_empty() {
124 self.properties.issuancepolicies = value.to_owned();
125 }
126 }
127 "msPKI-Cert-Template-OID" => {
128 if !value.is_empty() {
129 self.properties.oid = value[0].to_owned();
130 }
131 }
132 "pKIExtendedKeyUsage" => {
133 if !value.is_empty() {
134 self.properties.ekus = value.to_owned();
135 }
136 }
137 "msPKI-Template-Schema-Version" => {
138 self.properties.schemaversion = value[0].parse::<i64>().unwrap_or(0);
139 }
140 "whenCreated" => {
141 let epoch = string_to_epoch(&value[0])?;
142 if epoch.is_positive() {
143 self.properties.whencreated = epoch;
144 }
145 }
146 "IsDeleted" => {
147 self.is_deleted = true;
148 }
149 _ => {}
150 }
151 }
152
153 for (key, value) in &result_bin {
155 match key.as_str() {
156 "objectGUID" => {
157 let guid = decode_guid_le(&value[0]);
159 self.object_identifier = guid.to_owned();
160 }
161 "nTSecurityDescriptor" => {
162 let relations_ace = parse_ntsecuritydescriptor(
164 self,
165 &value[0],
166 "CertTemplate",
167 &result_attrs,
168 &result_bin,
169 domain,
170 );
171 self.aces = relations_ace;
172 }
173 "pKIExpirationPeriod" => {
174 self.properties.validityperiod = span_to_string(filetime_to_span(value[0].to_owned())?);
175 }
176 "pKIOverlapPeriod" => {
177 self.properties.renewalperiod = span_to_string(filetime_to_span(value[0].to_owned())?);
178 }
179 _ => {}
180 }
181 }
182
183 self.properties.effectiveekus = Self::get_effectiveekus(
185 &self.properties.schemaversion,
186 &self.properties.ekus,
187 &self.properties.certificateapplicationpolicy,
188 );
189
190 self.properties.authenticationenabled = Self::authentication_is_enabled(self);
192
193 if self.object_identifier != "SID" {
195 dn_sid.insert(
196 self.properties.distinguishedname.to_string(),
197 self.object_identifier.to_string()
198 );
199 sid_type.insert(
201 self.object_identifier.to_string(),
202 "CertTemplate".to_string()
203 );
204 }
205
206 Ok(())
209 }
210
211 fn get_effectiveekus(
213 schema_version: &i64,
214 ekus: &[String],
215 certificateapplicationpolicy: &[String],
216 ) -> Vec<String> {
217 if schema_version == &1 && !ekus.is_empty() {
218 ekus.to_vec()
219 } else {
220 certificateapplicationpolicy.to_vec()
221 }
222 }
223
224 fn authentication_is_enabled(&mut self) -> bool {
226 let authentication_oids = [
227 "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", ];
232 self.properties.effectiveekus.iter()
233 .any(|eku| authentication_oids.contains(&eku.as_str()))
234 || self.properties.effectiveekus.is_empty()
235 }
236}
237
238impl LdapObject for CertTemplate {
239 fn to_json(&self) -> Value {
241 serde_json::to_value(self).unwrap()
242 }
243
244 fn get_object_identifier(&self) -> &String {
246 &self.object_identifier
247 }
248 fn get_is_acl_protected(&self) -> &bool {
249 &self.is_acl_protected
250 }
251 fn get_aces(&self) -> &Vec<AceTemplate> {
252 &self.aces
253 }
254 fn get_spntargets(&self) -> &Vec<SPNTarget> {
255 panic!("Not used by current object.");
256 }
257 fn get_allowed_to_delegate(&self) -> &Vec<Member> {
258 panic!("Not used by current object.");
259 }
260 fn get_links(&self) -> &Vec<Link> {
261 panic!("Not used by current object.");
262 }
263 fn get_contained_by(&self) -> &Option<Member> {
264 &self.contained_by
265 }
266 fn get_child_objects(&self) -> &Vec<Member> {
267 panic!("Not used by current object.");
268 }
269 fn get_haslaps(&self) -> &bool {
270 &false
271 }
272
273 fn get_aces_mut(&mut self) -> &mut Vec<AceTemplate> {
275 &mut self.aces
276 }
277 fn get_spntargets_mut(&mut self) -> &mut Vec<SPNTarget> {
278 panic!("Not used by current object.");
279 }
280 fn get_allowed_to_delegate_mut(&mut self) -> &mut Vec<Member> {
281 panic!("Not used by current object.");
282 }
283
284 fn set_is_acl_protected(&mut self, is_acl_protected: bool) {
286 self.is_acl_protected = is_acl_protected;
287 self.properties.isaclprotected = is_acl_protected;
288 }
289 fn set_aces(&mut self, aces: Vec<AceTemplate>) {
290 self.aces = aces;
291 }
292 fn set_spntargets(&mut self, _spn_targets: Vec<SPNTarget>) {
293 }
295 fn set_allowed_to_delegate(&mut self, _allowed_to_delegate: Vec<Member>) {
296 }
298 fn set_links(&mut self, _links: Vec<Link>) {
299 }
301 fn set_contained_by(&mut self, contained_by: Option<Member>) {
302 self.contained_by = contained_by;
303 }
304 fn set_child_objects(&mut self, _child_objects: Vec<Member>) {
305 }
307}
308
309
310#[derive(Debug, Clone, Deserialize, Serialize)]
312pub struct CertTemplateProperties {
313 domain: String,
314 name: String,
315 distinguishedname: String,
316 domainsid: String,
317 isaclprotected: bool,
318 description: Option<String>,
319 whencreated: i64,
320 validityperiod: String,
321 renewalperiod: String,
322 schemaversion: i64,
323 displayname: String,
324 oid: String,
325 enrollmentflag: String,
326 requiresmanagerapproval: bool,
327 nosecurityextension: bool,
328 certificatenameflag: String,
329 enrolleesuppliessubject: bool,
330 subjectaltrequireupn: bool,
331 ekus: Vec<String>,
332 certificateapplicationpolicy: Vec<String>,
333 authorizedsignatures: i64,
334 applicationpolicies: Vec<String>,
335 issuancepolicies: Vec<String>,
336 effectiveekus: Vec<String>,
337 authenticationenabled: bool,
338}
339
340impl Default for CertTemplateProperties {
341 fn default() -> CertTemplateProperties {
342 CertTemplateProperties {
343 domain: String::from(""),
344 name: String::from(""),
345 distinguishedname: String::from(""),
346 domainsid: String::from(""),
347 isaclprotected: false,
348 description: None,
349 whencreated: -1,
350 validityperiod: String::from(""),
351 renewalperiod: String::from(""),
352 schemaversion: 1,
353 displayname: String::from(""),
354 oid: String::from(""),
355 enrollmentflag: String::from(""),
356 requiresmanagerapproval: false,
357 nosecurityextension: false,
358 certificatenameflag: String::from(""),
359 enrolleesuppliessubject: false,
360 subjectaltrequireupn: true,
361 ekus: Vec::new(),
362 certificateapplicationpolicy: Vec::new(),
363 authorizedsignatures: 0,
364 applicationpolicies: Vec::new(),
365 issuancepolicies: Vec::new(),
366 effectiveekus: Vec::new(),
367 authenticationenabled: false,
368 }
369 }
370 }
371
372impl CertTemplateProperties {
373 pub fn name(&self) -> &String {
375 &self.name
376 }
377}