1use serde_json::value::Value;
2use serde::{Deserialize, Serialize};
3use ldap3::SearchEntry;
4use log::{debug, error, trace};
5use std::collections::HashMap;
6use x509_parser::prelude::*;
7use std::error::Error;
8
9use crate::enums::regex::{OBJECT_SID_RE1, SID_PART1_RE1};
10use crate::objects::common::{LdapObject, AceTemplate, SPNTarget, Link, Member};
11use crate::utils::date::{convert_timestamp, string_to_epoch};
12use crate::utils::crypto::convert_encryption_types;
13use crate::enums::acl::{parse_ntsecuritydescriptor, parse_gmsa};
14use crate::enums::secdesc::LdapSid;
15use crate::enums::sid::sid_maker;
16use crate::enums::spntasks::check_spn;
17use crate::enums::uacflags::get_flag;
18
19#[derive(Debug, Clone, Deserialize, Serialize, Default)]
21pub struct User {
22 #[serde(rename ="ObjectIdentifier")]
23 object_identifier: String,
24 #[serde(rename ="IsDeleted")]
25 is_deleted: bool,
26 #[serde(rename ="IsACLProtected")]
27 is_acl_protected: bool,
28 #[serde(rename ="Properties")]
29 properties: UserProperties,
30 #[serde(rename ="PrimaryGroupSID")]
31 primary_group_sid: String,
32 #[serde(rename ="SPNTargets")]
33 spn_targets: Vec<SPNTarget>,
34 #[serde(rename ="UnconstrainedDelegation")]
35 unconstrained_delegation: bool,
36 #[serde(rename ="DomainSID")]
37 domain_sid: String,
38 #[serde(rename ="Aces")]
39 aces: Vec<AceTemplate>,
40 #[serde(rename ="AllowedToDelegate")]
41 allowed_to_delegate: Vec<Member>,
42 #[serde(rename ="HasSIDHistory")]
43 has_sid_history: Vec<String>,
44 #[serde(rename ="ContainedBy")]
45 contained_by: Option<Member>,
46}
47
48impl User {
49 pub fn new() -> Self {
51 Self { ..Default::default()}
52 }
53
54 pub fn properties(&self) -> &UserProperties {
56 &self.properties
57 }
58 pub fn aces(&self) -> &Vec<AceTemplate> {
59 &self.aces
60 }
61
62 pub fn properties_mut(&mut self) -> &mut UserProperties {
64 &mut self.properties
65 }
66 pub fn aces_mut(&mut self) -> &mut Vec<AceTemplate> {
67 &mut self.aces
68 }
69 pub fn object_identifier_mut(&mut self) -> &mut String {
70 &mut self.object_identifier
71 }
72
73 pub fn parse(
76 &mut self,
77 result: SearchEntry,
78 domain: &str,
79 dn_sid: &mut HashMap<String, String>,
80 sid_type: &mut HashMap<String, String>,
81 domain_sid: &str
82 ) -> Result<(), Box<dyn Error>> {
83 let result_dn: String = result.dn.to_uppercase();
84 let result_attrs: HashMap<String, Vec<String>> = result.attrs;
85 let result_bin: HashMap<String, Vec<Vec<u8>>> = result.bin_attrs;
86
87 debug!("Parse user: {result_dn}");
89
90 for (key, value) in &result_attrs {
92 trace!(" {key:?}:{value:?}");
93 }
94 for (key, value) in &result_bin {
96 trace!(" {key:?}:{value:?}");
97 }
98
99 self.properties.domain = domain.to_uppercase();
101 self.properties.distinguishedname = result_dn;
102 self.properties.enabled = true;
103 self.domain_sid = domain_sid.to_string();
104
105 let mut group_id: String ="".to_owned();
107 for (key, value) in &result_attrs {
108 match key.as_str() {
109 "sAMAccountName" => {
110 let name = &value[0];
111 let email = format!("{}@{}",name.to_owned(),domain);
112 self.properties.name = email.to_uppercase();
113 self.properties.samaccountname = name.to_string();
114 }
115 "description" => {
116 self.properties.description = Some(value[0].to_owned());
117 }
118 "mail" => {
119 self.properties.email = value[0].to_owned();
120 }
121 "title" => {
122 self.properties.title = value[0].to_owned();
123 }
124 "userPassword" => {
125 self.properties.userpassword = value[0].to_owned();
126 }
127 "unixUserPassword" => {
128 self.properties.unixpassword = value[0].to_owned();
129 }
130 "unicodepwd" => {
131 self.properties.unicodepassword = value[0].to_owned();
132 }
133 "sfupassword" => {
134 }
136 "displayName" => {
137 self.properties.displayname = value[0].to_owned();
138 }
139 "adminCount" => {
140 let isadmin = &value[0];
141 let mut admincount = false;
142 if isadmin =="1" {
143 admincount = true;
144 }
145 self.properties.admincount = admincount;
146 }
147 "homeDirectory" => {
148 self.properties.homedirectory = value[0].to_owned();
149 }
150 "scriptpath" => {
151 self.properties.logonscript = value[0].to_owned();
152 }
153 "userAccountControl" => {
154 let uac = &value[0].parse::<u32>().unwrap_or(0);
155 self.properties.useraccountcontrol = *uac;
156 let uac_flags = get_flag(*uac);
157 for flag in uac_flags {
159 if flag.contains("AccountDisable") {
160 self.properties.enabled = false;
161 };
162 if flag.contains("PasswordNotRequired") {
164 self.properties.passwordnotreqd = true;
165 };
166 if flag.contains("DontExpirePassword") {
167 self.properties.pwdneverexpires = true;
168 };
169 if flag.contains("DontReqPreauth") {
170 self.properties.dontreqpreauth = true;
171 };
172 if flag.contains("TrustedForDelegation") {
174 self.properties.unconstraineddelegation = true;
175 self.unconstrained_delegation = true;
176 };
177 if flag.contains("NotDelegated") {
178 self.properties.sensitive = true;
179 };
180 if flag.contains("TrustedToAuthForDelegation") {
182 self.properties.trustedtoauth = true;
183 };
184 }
185 }
186 "msDS-AllowedToDelegateTo" => {
187 let mut vec_members2: Vec<Member> = Vec::new();
191 for objet in value {
192 let mut member_allowed_to_delegate = Member::new();
193 let split = objet.split("/");
194 let fqdn = split.collect::<Vec<&str>>()[1];
195 let mut checker = false;
196 for member in &vec_members2 {
197 if member.object_identifier().contains(fqdn.to_uppercase().as_str()) {
198 checker = true;
199 }
200 }
201 if !checker {
202 *member_allowed_to_delegate.object_identifier_mut() = fqdn.to_uppercase().to_owned().to_uppercase();
203 *member_allowed_to_delegate.object_type_mut() ="Computer".to_owned();
204 vec_members2.push(member_allowed_to_delegate.to_owned());
205 }
206 }
207 self.allowed_to_delegate = vec_members2;
209 }
210 "lastLogon" => {
211 let lastlogon = &value[0].parse::<i64>().unwrap_or(0);
212 if lastlogon.is_positive() {
213 let epoch = convert_timestamp(*lastlogon);
214 self.properties.lastlogon = epoch;
215 }
216 }
217 "lastLogonTimestamp" => {
218 let lastlogontimestamp = &value[0].parse::<i64>().unwrap_or(0);
219 if lastlogontimestamp.is_positive() {
220 let epoch = convert_timestamp(*lastlogontimestamp);
221 self.properties.lastlogontimestamp = epoch;
222 }
223 }
224 "pwdLastSet" => {
225 let pwdlastset = &value[0].parse::<i64>().unwrap_or(0);
226 if pwdlastset.is_positive() {
227 let epoch = convert_timestamp(*pwdlastset);
228 self.properties.pwdlastset = epoch;
229 }
230 }
231 "whenCreated" => {
232 let epoch = string_to_epoch(&value[0])?;
233 if epoch.is_positive() {
234 self.properties.whencreated = epoch;
235 }
236 }
237 "servicePrincipalName" => {
238 let mut targets: Vec<SPNTarget> = Vec::new();
240 let mut result: Vec<String> = Vec::new();
241 let mut added: bool = false;
242 for v in value {
243 result.push(v.to_owned());
244 let _target = match check_spn(v).to_owned() {
246 Some(_target) => {
247 if !added {
248 targets.push(_target.to_owned());
249 added = true;
250 }
251 },
252 None => {}
253 };
254 }
255 self.properties.serviceprincipalnames = result;
256 self.properties.hasspn = true;
257 self.spn_targets = targets;
258 }
259 "primaryGroupID" => {
260 group_id = value[0].to_owned();
261 }
262 "IsDeleted" => {
263 self.is_deleted = true;
267 }
268 "msDS-SupportedEncryptionTypes" => {
269 self.properties.supportedencryptiontypes = convert_encryption_types(value[0].parse::<i32>().unwrap_or(0));
270 }
271 _ => {}
272 }
273 }
274
275 let mut sid: String = "".to_owned();
277 for (key, value) in &result_bin {
278 match key.as_str() {
279 "objectSid" => {
280 sid = sid_maker(LdapSid::parse(&value[0]).unwrap().1, domain);
281 self.object_identifier = sid.to_owned();
282
283 for domain_sid in OBJECT_SID_RE1.captures_iter(&sid) {
284 self.properties.domainsid = domain_sid[0].to_owned().to_string();
285 }
286 }
287 "nTSecurityDescriptor" => {
288 let relations_ace = parse_ntsecuritydescriptor(
290 self,
291 &value[0],
292 "User",
293 &result_attrs,
294 &result_bin,
295 domain,
296 );
297 self.aces_mut().extend(relations_ace);
298 }
299 "sIDHistory" => {
300 let mut list_sid_history: Vec<String> = Vec::new();
303 for bsid in value {
304 debug!("sIDHistory: {:?}", &bsid);
305 list_sid_history.push(sid_maker(LdapSid::parse(bsid).unwrap().1, domain));
306 }
308 self.properties.sidhistory = list_sid_history;
309 }
310 "msDS-GroupMSAMembership" => {
311 let mut relations_ace = parse_ntsecuritydescriptor(
313 self,
314 &value[0],
315 "User",
316 &result_attrs,
317 &result_bin,
318 domain,
319 );
320 parse_gmsa(&mut relations_ace, self);
323 }
325 "userCertificate" => {
326 let res = X509Certificate::from_der(&value[0]);
329 match res {
330 Ok((_rem, _cert)) => {},
331 _ => error!("CA x509 certificate parsing failed: {:?}", res),
332 }
333 }
334 _ => {}
335 }
336 }
337
338 #[allow(irrefutable_let_patterns)]
340 if let id = group_id {
341 if let Some(part1) = SID_PART1_RE1.find(&sid) {
342 self.primary_group_sid = format!("{}{}", part1.as_str(), id);
343 } else {
344 eprintln!("[!] Regex did not match any part of the SID");
345 }
346 }
347
348 dn_sid.insert(
350 self.properties.distinguishedname.to_owned(),
351 self.object_identifier.to_owned(),
352 );
353 sid_type.insert(
355 self.object_identifier.to_owned(),
356 "User".to_string(),
357 );
358
359 Ok(())
362 }
363}
364
365impl LdapObject for User {
367 fn to_json(&self) -> Value {
369 serde_json::to_value(self).unwrap()
370 }
371
372 fn get_object_identifier(&self) -> &String {
374 &self.object_identifier
375 }
376 fn get_is_acl_protected(&self) -> &bool {
377 &self.is_acl_protected
378 }
379 fn get_aces(&self) -> &Vec<AceTemplate> {
380 &self.aces
381 }
382 fn get_spntargets(&self) -> &Vec<SPNTarget> {
383 &self.spn_targets
384 }
385 fn get_allowed_to_delegate(&self) -> &Vec<Member> {
386 &self.allowed_to_delegate
387 }
388 fn get_links(&self) -> &Vec<Link> {
389 panic!("Not used by current object.");
390 }
391 fn get_contained_by(&self) -> &Option<Member> {
392 &self.contained_by
393 }
394 fn get_child_objects(&self) -> &Vec<Member> {
395 panic!("Not used by current object.");
396 }
397 fn get_haslaps(&self) -> &bool {
398 &false
399 }
400
401 fn get_aces_mut(&mut self) -> &mut Vec<AceTemplate> {
403 &mut self.aces
404 }
405 fn get_spntargets_mut(&mut self) -> &mut Vec<SPNTarget> {
406 &mut self.spn_targets
407 }
408 fn get_allowed_to_delegate_mut(&mut self) -> &mut Vec<Member> {
409 &mut self.allowed_to_delegate
410 }
411
412 fn set_is_acl_protected(&mut self, is_acl_protected: bool) {
414 self.is_acl_protected = is_acl_protected;
415 self.properties.isaclprotected = is_acl_protected;
416 }
417 fn set_aces(&mut self, aces: Vec<AceTemplate>) {
418 self.aces = aces;
419 }
420 fn set_spntargets(&mut self, spn_targets: Vec<SPNTarget>) {
421 self.spn_targets = spn_targets;
422 }
423 fn set_allowed_to_delegate(&mut self, allowed_to_delegate: Vec<Member>) {
424 self.allowed_to_delegate = allowed_to_delegate;
425 }
426 fn set_links(&mut self, _links: Vec<Link>) {
427 }
429 fn set_contained_by(&mut self, contained_by: Option<Member>) {
430 self.contained_by = contained_by;
431 }
432 fn set_child_objects(&mut self, _child_objects: Vec<Member>) {
433 }
435}
436
437#[derive(Debug, Clone, Deserialize, Serialize, Default)]
439pub struct UserProperties {
440 domain: String,
441 name: String,
442 domainsid: String,
443 isaclprotected: bool,
444 distinguishedname: String,
445 highvalue: bool,
446 description: Option<String>,
447 whencreated: i64,
448 sensitive: bool,
449 dontreqpreauth: bool,
450 passwordnotreqd: bool,
451 unconstraineddelegation: bool,
452 pwdneverexpires: bool,
453 enabled: bool,
454 trustedtoauth: bool,
455 lastlogon: i64,
456 lastlogontimestamp: i64,
457 pwdlastset: i64,
458 serviceprincipalnames: Vec<String>,
459 hasspn: bool,
460 displayname: String,
461 email: String,
462 title: String,
463 homedirectory: String,
464 logonscript: String,
465 useraccountcontrol: u32,
466 samaccountname: String,
467 userpassword: String,
468 unixpassword: String,
469 unicodepassword: String,
470 sfupassword: String,
471 admincount: bool,
472 supportedencryptiontypes: Vec<String>,
473 sidhistory: Vec<String>,
474 allowedtodelegate: Vec<String>
475}
476
477impl UserProperties {
478 pub fn name(&self) -> &String {
480 &self.name
481 }
482 pub fn domainsid(&self) -> &String {
483 &self.domainsid
484 }
485 pub fn isaclprotected(&self) -> &bool {
486 &self.isaclprotected
487 }
488
489 pub fn name_mut(&mut self) -> &mut String {
491 &mut self.name
492 }
493 pub fn domainsid_mut(&mut self) -> &mut String {
494 &mut self.domainsid
495 }
496 pub fn isaclprotected_mut(&mut self) -> &mut bool {
497 &mut self.isaclprotected
498 }
499}