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