rusthound/json/parser/
bh_41.rs

1
2use colored::Colorize;
3use ldap3::SearchEntry;
4use log::{info, debug, trace, error};
5use regex::Regex;
6use serde_json::json;
7use std::collections::HashMap;
8use x509_parser::prelude::*;
9
10use crate::enums::acl::{parse_ntsecuritydescriptor,parse_gmsa};
11use crate::enums::date::{convert_timestamp,string_to_epoch};
12use crate::enums::forestlevel::get_forest_level;
13use crate::enums::gplink::parse_gplink;
14use crate::enums::secdesc::LdapSid;
15use crate::enums::sid::{decode_guid, objectsid_to_vec8, sid_maker};
16use crate::enums::spntasks::check_spn;
17use crate::enums::uacflags::get_flag;
18use crate::enums::trusts::get_trust_flag;
19
20use crate::json::templates::bh_41::*;
21//use crate::errors::{Error, Result};
22
23/*
24function 1 : users
25function 2 : groups
26function 3 : computers
27function 4 : ous
28function 5 : domains
29function 6 : gpos
30function 7 : ForeignSecurityPrincipal
31function 8 : containers
32function 9 : trust domain
33function 10: unknown values
34*/
35
36/*****************************************
37******************************************
381- Function to parse users information
39******************************************
40*****************************************/
41/// Function to parse and replace value in json template for user object.
42/// <https://bloodhound.readthedocs.io/en/latest/further-reading/json.html#users>
43pub fn parse_user(
44    result: SearchEntry,
45    domain: &String,
46    dn_sid: &mut HashMap<String, String>,
47    sid_type: &mut HashMap<String, String>,
48    adcs: bool,
49) -> serde_json::value::Value {
50
51    let result_dn: String;
52    result_dn = result.dn.to_uppercase();
53
54    let result_attrs: HashMap<String, Vec<String>>;
55    result_attrs = result.attrs;
56
57    let result_bin: HashMap<String, Vec<Vec<u8>>>;
58    result_bin = result.bin_attrs;
59
60    debug!("Parse user: {}", result_dn);
61    //for (key, value) in &result_attrs {
62    //    trace!("  {:?}:{:?}", key, value);
63    //}
64    //trace result bin
65    //for (key, value) in &result_bin {
66    //    trace!("bin  {:?}:{:?}", key, value);
67    //}
68
69    // json template for one user
70    let mut user_json = prepare_user_json_template();
71
72    // Change all values...
73    user_json["Properties"]["domain"] = domain.to_uppercase().into();
74    user_json["Properties"]["distinguishedname"] = result_dn.into();
75
76    // With a check
77    let mut group_id: String = "".to_owned();
78    for (key, value) in &result_attrs {
79        match key.as_str() {
80            "sAMAccountName" => {
81                let name = &value[0];
82                let email = format!("{}@{}",name.to_owned(),domain);
83                user_json["Properties"]["name"] = email.to_uppercase().into();
84                user_json["Properties"]["samaccountname"] = name.to_owned().into();
85            }
86            "description" => {
87                user_json["Properties"]["description"] = value[0].to_owned().into();
88            }
89            "mail" => {
90                user_json["Properties"]["email"] = value[0].to_owned().into();
91            }
92            "title" => {
93                user_json["Properties"]["title"] = value[0].to_owned().into();
94            }
95            "userPassword" => {
96                user_json["Properties"]["userpassword"] = value[0].to_owned().into();
97            }
98            "unixUserPassword" => {
99                user_json["Properties"]["unixpassword"] = value[0].to_owned().into();
100            }
101            "unicodepwd" => {
102                user_json["Properties"]["unicodepassword"] = value[0].to_owned().into();
103            }
104            "sfupassword" => {
105                //user_json["Properties"]["sfupassword"] = value[0].to_owned().into();
106            }
107            "displayName" => {
108                user_json["Properties"]["displayname"] = value[0].to_owned().into();
109            }
110            "adminCount" => {
111                let isadmin = &value[0];
112                let mut admincount = false;
113                if isadmin == "1" {
114                    admincount = true;
115                }
116                user_json["Properties"]["admincount"] = admincount.into();
117            }
118            "homeDirectory" => {
119                user_json["Properties"]["homedirectory"] = value[0].to_owned().into();
120            }
121            "scriptpath" => {
122                user_json["Properties"]["logonscript"] = value[0].to_owned().into();
123            }
124            "userAccountControl" => {
125                let uac = &value[0].parse::<u32>().unwrap_or(0);
126                let uac_flags = get_flag(*uac);
127                //trace!("UAC : {:?}",uac_flags);
128                for flag in uac_flags {
129                    if flag.contains("AccountDisable") {
130                        user_json["Properties"]["enabled"] = false.into();
131                    };
132                    //if flag.contains("Lockout") { let enabled = true; user_json["Properties"]["enabled"] = enabled.into(); };
133                    if flag.contains("PasswordNotRequired") {
134                        user_json["Properties"]["passwordnotreqd"] = true.into();
135                    };
136                    if flag.contains("DontExpirePassword") {
137                        user_json["Properties"]["pwdneverexpires"] = true.into();
138                    };
139                    if flag.contains("DontReqPreauth") {
140                        user_json["Properties"]["dontreqpreauth"] = true.into();
141                    };
142                    // KUD (Kerberos Unconstrained Delegation)
143                    if flag.contains("TrustedForDelegation") {
144                        user_json["Properties"]["unconstraineddelegation"] = true.into();
145                    };
146                    if flag.contains("NotDelegated") {
147                        user_json["Properties"]["sensitive"] = true.into();
148                    };
149                    //if flag.contains("PasswordExpired") { let password_expired = true; user_json["Properties"]["pwdneverexpires"] = password_expired.into(); };
150                    if flag.contains("TrustedToAuthForDelegation") {
151                        user_json["Properties"]["trustedtoauth"] = true.into();
152                    };
153                }
154            }
155            "msDS-AllowedToDelegateTo"  => {
156                // KCD (Kerberos Constrained Delegation)
157                //trace!(" AllowToDelegateTo: {:?}",&value);
158                user_json["Properties"]["allowedtodelegate"] = value.to_owned().into();
159                // AllowedToDelegate
160                let mut vec_members: Vec<serde_json::value::Value> = Vec::new();
161                let mut allowed_to_delegate = prepare_member_json_template();
162                for objet in value {
163                    let split = objet.split("/");
164                    let fqdn = split.collect::<Vec<&str>>()[1];
165                    let mut checker = false;
166                    for member in &vec_members {
167                        if member["ObjectIdentifier"].to_string().contains(fqdn.to_uppercase().as_str()) {
168                            checker = true;
169                        }
170                    }
171                    if !checker {
172                        allowed_to_delegate["ObjectIdentifier"] = fqdn.to_uppercase().to_owned().to_uppercase().into();
173                        allowed_to_delegate["ObjectType"] = "Computer".to_owned().into();
174                        vec_members.push(allowed_to_delegate.to_owned()); 
175                    }
176                }
177                user_json["AllowedToDelegate"] = vec_members.to_owned().into();
178            }
179            "lastLogon" => {
180                let lastlogon = &value[0].parse::<i64>().unwrap_or(0);
181                if lastlogon.is_positive() {
182                    let epoch = convert_timestamp(*lastlogon);
183                    user_json["Properties"]["lastlogon"] = epoch.into();
184                }
185            }
186            "lastLogonTimestamp" => {
187                let lastlogontimestamp = &value[0].parse::<i64>().unwrap_or(0);
188                if lastlogontimestamp.is_positive() {
189                    let epoch = convert_timestamp(*lastlogontimestamp);
190                    user_json["Properties"]["lastlogontimestamp"] = epoch.into();
191                }
192            }
193            "pwdLastSet" => {
194                let pwdlastset = &value[0].parse::<i64>().unwrap_or(0);
195                if pwdlastset.is_positive() {
196                    let epoch = convert_timestamp(*pwdlastset);
197                    user_json["Properties"]["pwdlastset"] = epoch.into();
198                }
199            }
200            "whenCreated" => {
201               let epoch = string_to_epoch(&value[0]);
202               if epoch.is_positive() {
203                   user_json["Properties"]["whencreated"] = epoch.into();
204               }
205           }
206            "servicePrincipalName" => {
207                let mut result: Vec<String> = Vec::new();
208                // SPNTargets values
209                let mut targets: Vec<serde_json::value::Value> = Vec::new();
210
211                let mut added: bool = false;
212                for v in value {
213                    result.push(v.to_owned());
214                    // Checking the spn for service-account (mssql?)
215                    let target = check_spn(v).to_owned();
216                    if target.to_string().contains("Port") && !added {
217                        targets.push(target.to_owned());
218                        added = true;
219                    }
220                }
221                user_json["Properties"]["serviceprincipalnames"] = result.to_owned().into();
222                user_json["Properties"]["hasspn"] = true.into();
223                user_json["SPNTargets"] = targets.into();
224            }
225            "primaryGroupID" => {
226                group_id = value[0].to_owned();
227            }
228            "IsDeleted" => {
229                // OID to use: 1.2.840.113556.1.4.417
230                // https://ldapwiki.com/wiki/IsDeleted
231                //trace!("isDeleted: {:?}",&value[0]);
232                user_json["IsDeleted"] = true.into();
233            }
234            _ => {}
235        }
236    }
237
238    // For all, bins attributs
239    let mut sid: String = "".to_owned();
240    for (key, value) in &result_bin {
241        match key.as_str() {
242            "objectSid" => {
243                sid = sid_maker(LdapSid::parse(&value[0]).unwrap().1, domain);
244                user_json["ObjectIdentifier"] = sid.to_owned().into();
245
246                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();
247                for domain_sid in re.captures_iter(&sid) 
248                {
249                    user_json["Properties"]["domainsid"] = domain_sid[0].to_owned().to_string().into();
250                }
251            }
252            "nTSecurityDescriptor" => {
253                // Needed with acl
254                let entry_type = "user".to_string();
255                // nTSecurityDescriptor raw to string
256                let relations_ace = parse_ntsecuritydescriptor(
257                    &mut user_json,
258                    &value[0],
259                    entry_type,
260                    &result_attrs,
261                    &result_bin,
262                    &domain,
263                );
264                user_json["Aces"] = relations_ace.into();
265            }
266            "sIDHistory" => {
267                // not tested! #tocheck
268                //debug!("sIDHistory: {:?}",&value[0]);
269                let mut list_sid_history: Vec<String> = Vec::new();
270                for bsid in value {
271                    debug!("sIDHistory: {:?}", &bsid);
272                    list_sid_history.push(sid_maker(LdapSid::parse(&bsid).unwrap().1, domain));
273                    // Todo function to add the sid history in user_json['HasSIDHistory']
274                }
275                user_json["Properties"]["sidhistory"] = list_sid_history.into();
276            }
277            "msDS-GroupMSAMembership" => {
278                let entry_type = "user".to_string();
279                // nTSecurityDescriptor raw to string
280                let mut relations_ace = parse_ntsecuritydescriptor(
281                    &mut user_json,
282                    &value[0],
283                    entry_type,
284                    &result_attrs,
285                    &result_bin,
286                    &domain,
287                );
288                // Now add the new ACE wich who can read GMSA password
289                let mut relations_ace_b = user_json["Aces"].as_array_mut().unwrap();
290                trace!("msDS-GroupMSAMembership ACE ? {:?}", relations_ace);
291                //trace!("user_json['Aces'] before : {:?}", relations_ace_b);
292                parse_gmsa(&mut relations_ace, &mut relations_ace_b);
293                //info!("user_json['Aces'] after : {:?}", relations_ace_b);
294            }
295            "userCertificate" => {
296                // <https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-adls/d66d1662-0b4f-44ab-a4c8-e788f3ae39cf>
297                // <https://docs.rs/x509-parser/latest/x509_parser/certificate/struct.X509Certificate.html>
298                if !adcs {
299                    let res = X509Certificate::from_der(&value[0]);
300                    match res {
301                        Ok((_rem, cert)) => {
302                            
303                            info!("ADCS found {}, use {} args to collect the certificate templates and certificate authority.",cert.issuer().to_string().replace(" ","").bold().green(),&"--adcs".bold().yellow());
304                        },
305                        _ => error!("CA x509 certificate parsing failed: {:?}", res),
306    
307                    }
308                }
309            }
310            _ => {}
311        }
312    }
313
314    // primaryGroupID if group_id is set
315    #[allow(irrefutable_let_patterns)]
316    if let id = group_id {
317        let re = Regex::new(r"S-.*-").unwrap();
318        let part1 = re.find(&sid).unwrap();
319        let mut primary_group_id: String = "".to_owned();
320        primary_group_id.push_str(&part1.as_str());
321        primary_group_id.push_str(&id.as_str());
322        user_json["PrimaryGroupSID"] = primary_group_id.to_owned().into();
323    }
324
325    // Push DN and SID in HashMap
326    dn_sid.insert(
327        user_json["Properties"]["distinguishedname"]
328            .as_str()
329            .unwrap()
330            .to_string(),
331        user_json["ObjectIdentifier"].as_str().unwrap().to_string(),
332    );
333    // Push DN and Type
334    sid_type.insert(
335        user_json["ObjectIdentifier"].as_str().unwrap().to_string(),
336        "User".to_string(),
337    );
338
339    return user_json;
340}
341
342/*****************************************
343******************************************
3442- Function to parse groups information
345******************************************
346*****************************************/
347/// Function to parse and replace value in json template for group object.
348/// <https://bloodhound.readthedocs.io/en/latest/further-reading/json.html#groups>
349pub fn parse_group(
350    result: SearchEntry,
351    domain: &String,
352    dn_sid: &mut HashMap<String, String>,
353    sid_type: &mut HashMap<String, String>,
354) -> serde_json::value::Value {
355    let result_dn: String;
356    result_dn = result.dn.to_uppercase();
357
358    let result_attrs: HashMap<String, Vec<String>>;
359    result_attrs = result.attrs;
360
361    let result_bin: HashMap<String, Vec<Vec<u8>>>;
362    result_bin = result.bin_attrs;
363
364    debug!("Parse group: {}", result_dn);
365    //for (key, value) in &result_attrs {
366    //    trace!("  {:?}:{:?}", key, value);
367    //}
368    ////trace result bin
369    //for (key, value) in &result_bin {
370    //    trace!("  {:?}:{:?}", key, value);
371    //}
372
373    // json template for one group
374    let mut group_json = prepare_group_json_template();
375
376    // json template for all members
377    let mut vec_members: Vec<serde_json::value::Value> = Vec::new();
378    let mut member_json = prepare_member_json_template();
379
380    // Change all values...
381    group_json["Properties"]["domain"] = domain.to_uppercase().into();
382    group_json["Properties"]["distinguishedname"] = result_dn.into();
383
384    #[allow(unused_assignments)]
385    let mut sid: String = "".to_owned();
386    // With a check
387    for (key, value) in &result_attrs {
388        match key.as_str() {
389            "name" => {
390                let name = &value[0];
391                let email = format!("{}@{}",name.to_owned(),domain);
392                group_json["Properties"]["name"] = email.to_uppercase().into();
393            }
394            "description" => {
395                group_json["Properties"]["description"] = value[0].to_owned().into();
396            }
397            "adminCount" => {
398                let isadmin = &value[0];
399                let mut admincount = false;
400                if isadmin == "1" {
401                    admincount = true;
402                }
403                group_json["Properties"]["admincount"] = admincount.into();
404            }
405            "sAMAccountName" => {
406                group_json["Properties"]["samaccountname"] = value[0].to_owned().into();
407            }
408            "member" => {
409                if value.len() > 0 {
410                    for member in value {
411                        member_json["ObjectIdentifier"] = member.to_owned().to_uppercase().into();
412                        if member_json["ObjectIdentifier"].as_str().unwrap_or("SID") != "SID" {
413                            vec_members.push(member_json.to_owned());
414                        }
415                    }
416                    group_json["Members"] = vec_members.to_owned().into();
417                }
418            }
419            "objectSid" => {
420                // objectSid to vec and raw to string
421                let vec_sid = objectsid_to_vec8(&value[0]);
422                sid = sid_maker(LdapSid::parse(&vec_sid).unwrap().1, domain);
423                group_json["ObjectIdentifier"] = sid.to_owned().into();
424
425                /*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();
426                for domain_sid in re.captures_iter(&sid) 
427                {
428                    group_json["Properties"]["domainsid"] = domain_sid[0].to_owned().to_string().into();
429                }*/
430
431                // highvalue
432                if sid.ends_with("-512") 
433                || sid.ends_with("-516") 
434                || sid.ends_with("-519") 
435                || sid.ends_with("-520") 
436                {
437                    group_json["Properties"]["highvalue"] = true.into();
438                }
439                else if sid.ends_with("S-1-5-32-544") 
440                || sid.ends_with("S-1-5-32-548") 
441                || sid.ends_with("S-1-5-32-549")
442                || sid.ends_with("S-1-5-32-550") 
443                || sid.ends_with("S-1-5-32-551") 
444                {
445                    group_json["Properties"]["highvalue"] = true.into();
446                }
447                else {
448                    group_json["Properties"]["highvalue"] = false.into();
449                }
450            }
451            "whenCreated" => {
452                let epoch = string_to_epoch(&value[0]);
453                if epoch.is_positive() {
454                    group_json["Properties"]["whencreated"] = epoch.into();
455                }
456            }
457            "IsDeleted" => {
458                group_json["IsDeleted"] = true.into();
459            }
460            _ => {}
461        }
462    }
463
464    // For all, bins attributs
465    for (key, value) in &result_bin {
466        match key.as_str() {
467            "objectSid" => {
468                // objectSid raw to string
469                sid = sid_maker(LdapSid::parse(&value[0]).unwrap().1, domain);
470                group_json["ObjectIdentifier"] = sid.to_owned().into();
471
472                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();
473                for domain_sid in re.captures_iter(&sid) 
474                {
475                    group_json["Properties"]["domainsid"] = domain_sid[0].to_owned().to_string().into();
476                }
477                
478                // highvalue
479                if sid.ends_with("-512") 
480                || sid.ends_with("-516") 
481                || sid.ends_with("-519") 
482                || sid.ends_with("-520") 
483                {
484                    group_json["Properties"]["highvalue"] = true.into();
485                }
486                else if sid.ends_with("S-1-5-32-544") 
487                || sid.ends_with("S-1-5-32-548") 
488                || sid.ends_with("S-1-5-32-549")
489                || sid.ends_with("S-1-5-32-550") 
490                || sid.ends_with("S-1-5-32-551") 
491                {
492                    group_json["Properties"]["highvalue"] = true.into();
493                }
494                else {
495                    group_json["Properties"]["highvalue"] = false.into();
496                }
497            }
498            "nTSecurityDescriptor" => {
499                // Needed with acl
500                let entry_type = "group".to_string();
501                // nTSecurityDescriptor raw to string
502                let relations_ace = parse_ntsecuritydescriptor(
503                    &mut group_json,
504                    &value[0],
505                    entry_type,
506                    &result_attrs,
507                    &result_bin,
508                    &domain,
509                );
510                group_json["Aces"] = relations_ace.into();
511            }
512            _ => {}
513        }
514    }
515
516    // Push DN and SID in HashMap
517    dn_sid.insert(
518        group_json["Properties"]["distinguishedname"]
519            .as_str()
520            .unwrap()
521            .to_string(),
522        group_json["ObjectIdentifier"].as_str().unwrap().to_string(),
523    );
524    // Push DN and Type
525    sid_type.insert(
526        group_json["ObjectIdentifier"].as_str().unwrap().to_string(),
527        "Group".to_string(),
528    );
529
530    return group_json;
531}
532
533/*****************************************
534******************************************
5353- Function to parse computers information
536******************************************
537*****************************************/
538/// Function to parse and replace value in json template for computer object.
539/// <https://bloodhound.readthedocs.io/en/latest/further-reading/json.html#computers>
540pub fn parse_computer(
541    result: SearchEntry,
542    domain: &String,
543    dn_sid: &mut HashMap<String, String>,
544    sid_type: &mut HashMap<String, String>,
545    fqdn_sid: &mut HashMap<String, String>,
546    fqdn_ip: &mut HashMap<String, String>,
547) -> serde_json::value::Value {
548    let result_dn: String;
549    result_dn = result.dn.to_uppercase();
550
551    let result_attrs: HashMap<String, Vec<String>>;
552    result_attrs = result.attrs;
553
554    let result_bin: HashMap<String, Vec<Vec<u8>>>;
555    result_bin = result.bin_attrs;
556
557    debug!("Parse computer: {}", result_dn);
558    //for (key, value) in &result_attrs {
559    //    trace!("  {:?}:{:?}", key, value);
560    //}
561    ////trace result bin
562    //for (key, value) in &result_bin {
563    //    trace!("  {:?}:{:?}", key, value);
564    //}
565
566    // json template for one computer
567    let mut computer_json = prepare_computer_json_template();
568
569    let mut vec_localadmins: Vec<serde_json::value::Value> = Vec::new();
570    let mut localadmin_json = json!({
571        "MemberId": "SID",
572        "MemberType": "Type"
573    });
574
575    // Change all values...
576    computer_json["Properties"]["domain"] = domain.to_uppercase().into();
577    computer_json["Properties"]["distinguishedname"] = result_dn.into();
578    let mut sid: String = "".to_owned();
579    let mut group_id: String = "".to_owned();
580    // With a check
581    for (key, value) in &result_attrs {
582        match key.as_str() {
583            "name" => {
584                let name = &value[0];
585                let email = format!("{}@{}",name.to_owned(),domain);
586                computer_json["Properties"]["name"] = email.to_uppercase().into();
587            }
588            "sAMAccountName" => {
589                computer_json["Properties"]["samaccountname"] = value[0].to_owned().into();
590            }
591            "dNSHostName" => {
592                computer_json["Properties"]["name"] = value[0].to_uppercase().into();
593            }
594            "description" => {
595                computer_json["Properties"]["description"] = value[0].to_owned().into();
596            }
597            "operatingSystem" => {
598                computer_json["Properties"]["operatingsystem"] = value[0].to_owned().into();
599            }
600            //"operatingSystemServicePack" => {
601            //    //operatingsystem
602            //    let mut operating_system_servicepack = "".to_owned();
603            //    //if result_attrs["operatingSystem"].len() > 0 {
604            //    //    operating_system_servicepack.push_str(&result_attrs["operatingSystem"][0]);
605            //    //}
606            //    //operating_system_servicepack.push_str(&" ");
607            //   operating_system_servicepack.push_str(&result_attrs["operatingSystemServicePack"][0]);
608            //    computer_json["Properties"]["operatingsystem"] = operating_system_servicepack.to_owned().into();
609            //}
610            "member" => {
611                for member in value {
612                    localadmin_json["MemberId"] = member.to_owned().into();
613                    vec_localadmins.push(localadmin_json.to_owned());
614                }
615                computer_json["Members"] = vec_localadmins.to_owned().into();
616            }
617            "lastLogon" => {
618                let lastlogon = &value[0].parse::<i64>().unwrap_or(0);
619                if lastlogon.is_positive() {
620                    let epoch = convert_timestamp(*lastlogon);
621                    computer_json["Properties"]["lastlogon"] = epoch.into();
622                }
623            }
624            "lastLogonTimestamp" => {
625                let lastlogontimestamp = &value[0].parse::<i64>().unwrap_or(0);
626                if lastlogontimestamp.is_positive() {
627                    let epoch = convert_timestamp(*lastlogontimestamp);
628                    computer_json["Properties"]["lastlogontimestamp"] = epoch.into();
629                }
630            }
631            "pwdLastSet" => {
632                let pwdlastset = &value[0].parse::<i64>().unwrap_or(0);
633                if pwdlastset.is_positive() {
634                    let epoch = convert_timestamp(*pwdlastset);
635                    computer_json["Properties"]["pwdlastset"] = epoch.into();
636                }
637            }
638            "whenCreated" => {
639                let epoch = string_to_epoch(&value[0]);
640                if epoch.is_positive() {
641                    computer_json["Properties"]["whencreated"] = epoch.into();
642                }
643            }
644            "servicePrincipalName" => {
645                //servicePrincipalName and hasspn
646                let mut result: Vec<String> = Vec::new();
647                for value in &result_attrs["servicePrincipalName"] {
648                    result.push(value.to_owned());
649                }
650                computer_json["Properties"]["serviceprincipalnames"] = result.to_owned().into();
651            }
652            "userAccountControl" => {
653                //userAccountControl
654                let uac = &value[0].parse::<u32>().unwrap();
655                let uac_flags = get_flag(*uac);
656                //trace!("UAC : {:?}",uac_flags);
657                for flag in uac_flags {
658                    if flag.contains("AccountDisable") {
659                        computer_json["Properties"]["enabled"] = false.into();
660                    };
661                    //if flag.contains("Lockout") { let enabled = true; computer_json["Properties"]["enabled"] = enabled.into(); };
662                    // KUD (Kerberos Unconstrained Delegation)
663                    if flag.contains("TrustedForDelegation") {
664                        computer_json["Properties"]["unconstraineddelegation"] = true.into();
665                    };
666                    //if flag.contains("PasswordExpired") { let password_expired = true; computer_json["Properties"]["pwdneverexpires"] = password_expired.into(); };
667                    if flag.contains("TrustedToAuthForDelegation") {
668                        computer_json["Properties"]["trustedtoauth"] = true.into();
669                    };
670                }
671            }
672            "msDS-AllowedToDelegateTo"  => {
673                // KCD (Kerberos Constrained Delegation)
674                //trace!(" AllowToDelegateTo: {:?}",&value);
675                computer_json["Properties"]["allowedtodelegate"] = value.to_owned().into();
676                // AllowedToDelegate
677                let mut vec_members: Vec<serde_json::value::Value> = Vec::new();
678                let mut allowed_to_delegate = prepare_member_json_template();
679                for objet in value {
680                    let split = objet.split("/");
681                    let fqdn = split.collect::<Vec<&str>>()[1];
682                    let mut checker = false;
683                    for member in &vec_members {
684                        if member["ObjectIdentifier"].to_string().contains(fqdn.to_uppercase().as_str()) {
685                            checker = true;
686                        }
687                    }
688                    if !checker {
689                        allowed_to_delegate["ObjectIdentifier"] = fqdn.to_uppercase().to_owned().to_uppercase().into();
690                        allowed_to_delegate["ObjectType"] = "Computer".to_owned().into();
691                        vec_members.push(allowed_to_delegate.to_owned()); 
692                    }
693                }
694                computer_json["AllowedToDelegate"] = vec_members.to_owned().into();
695            }
696            "ms-Mcs-AdmPwd" => {
697                // Laps is set, random password for local adminsitrator
698                // https://github.com/BloodHoundAD/SharpHound3/blob/7615860d963ba70751e1e5a00e02bb3fbca154c6/SharpHound3/Tasks/ACLTasks.cs#L313
699                info!(
700                    "Your user can read LAPS password on {}: {}",
701                    &result_attrs["name"][0].yellow().bold(),
702                    &result_attrs["ms-Mcs-AdmPwd"][0].yellow().bold()
703                );
704                computer_json["Properties"]["haslaps"] = true.into();
705            }
706            "ms-Mcs-AdmPwdExpirationTime" => {
707                // LAPS is set, random password for local adminsitrator
708                computer_json["Properties"]["haslaps"] = true.into();
709            }
710            "primaryGroupID" => {
711                group_id = value[0].to_owned();
712            }
713            "IsDeleted" => {
714                computer_json["IsDeleted"] = true.into();
715            }
716            _ => {}
717        }
718    }
719    // For all, bins attributs
720    for (key, value) in &result_bin {
721        match key.as_str() {
722            "objectSid" => {
723                // objectSid raw to string
724                sid = sid_maker(LdapSid::parse(&value[0]).unwrap().1, domain);
725                computer_json["ObjectIdentifier"] = sid.to_owned().into();
726
727                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();
728                for domain_sid in re.captures_iter(&sid) 
729                {
730                    computer_json["Properties"]["domainsid"] = domain_sid[0].to_owned().to_string().into();
731                }
732                
733            }
734            "nTSecurityDescriptor" => {
735                // Needed with acl
736                let entry_type = "computer".to_string();
737                // nTSecurityDescriptor raw to string
738                let relations_ace = parse_ntsecuritydescriptor(
739                    &mut computer_json,
740                    &value[0],
741                    entry_type,
742                    &result_attrs,
743                    &result_bin,
744                    &domain,
745                );
746                computer_json["Aces"] = relations_ace.into();
747            }
748            "msDS-AllowedToActOnBehalfOfOtherIdentity" => {
749                // RBCD (Resource-based constrained)
750                // Needed with acl
751                let entry_type = "computer".to_string();
752                // msDS-AllowedToActOnBehalfOfOtherIdentity parsing ACEs
753                let relations_ace = parse_ntsecuritydescriptor(
754                    &mut computer_json,
755                    &value[0],
756                    entry_type,
757                    &result_attrs,
758                    &result_bin,
759                    &domain,
760                );
761                let mut vec_members: Vec<serde_json::value::Value> = Vec::new();
762                let mut allowed_to_act = prepare_member_json_template();
763                for delegated in relations_ace {
764                    //trace!("msDS-AllowedToActOnBehalfOfOtherIdentity => ACE: {:?}",delegated);
765                    // delegated["RightName"] == "Owner" => continue
766                    if delegated["RightName"] == "GenericAll" {
767                        allowed_to_act["ObjectIdentifier"] = delegated["PrincipalSID"].as_str().unwrap().to_string().into();
768                        vec_members.push(allowed_to_act.to_owned()); 
769                        continue
770                    }
771                }
772                computer_json["AllowedToAct"] = vec_members.into();
773            }
774            _ => {}
775        }
776    }
777    // primaryGroupID if group_id is set
778    #[allow(irrefutable_let_patterns)]
779    if let id = group_id {
780        let re = Regex::new(r"S-.*-").unwrap();
781        let part1 = re.find(&sid).unwrap();
782        let mut primary_group_id: String = "".to_owned();
783        primary_group_id.push_str(&part1.as_str());
784        primary_group_id.push_str(&id.as_str());
785        computer_json["PrimaryGroupSID"] = primary_group_id.to_owned().into();
786    }
787
788    // Push DN and SID in HashMap
789    dn_sid.insert(
790        computer_json["Properties"]["distinguishedname"]
791            .as_str()
792            .unwrap()
793            .to_string(),
794        computer_json["ObjectIdentifier"]
795            .as_str()
796            .unwrap()
797            .to_string(),
798    );
799    // Push DN and Type
800    sid_type.insert(
801        computer_json["ObjectIdentifier"]
802            .as_str()
803            .unwrap()
804            .to_string(),
805        "Computer".to_string(),
806    );
807
808    fqdn_sid.insert(
809        computer_json["Properties"]["name"]
810            .as_str()
811            .unwrap()
812            .to_string(),
813        computer_json["ObjectIdentifier"]
814            .as_str()
815            .unwrap()
816            .to_string(),
817    );
818
819    fqdn_ip.insert(
820        computer_json["Properties"]["name"]
821            .as_str()
822            .unwrap()
823            .to_string(),
824        "".to_string(),
825    );
826
827    return computer_json;
828}
829
830/*****************************************
831******************************************
8324- Function to parse OUs information
833******************************************
834*****************************************/
835/// Function to parse and replace value in json template for OU object.
836/// <https://bloodhound.readthedocs.io/en/latest/further-reading/json.html#ous>
837pub fn parse_ou(
838    result: SearchEntry,
839    domain: &String,
840    dn_sid: &mut HashMap<String, String>,
841    sid_type: &mut HashMap<String, String>,
842) -> serde_json::value::Value {
843
844    let result_dn: String;
845    result_dn = result.dn.to_uppercase();
846
847    let result_attrs: HashMap<String, Vec<String>>;
848    result_attrs = result.attrs;
849
850    let result_bin: HashMap<String, Vec<Vec<u8>>>;
851    result_bin = result.bin_attrs;
852
853    // Debug for current object
854    debug!("Parse OU: {}", result_dn);
855    //for (key, value) in &result_attrs {
856    //    trace!("  {:?}:{:?}", key, value);
857    //}
858    ////trace result bin
859    //for (key, value) in &result_bin {
860    //    trace!("  {:?}:{:?}", key, value);
861    //}
862
863    // json template for one ou
864    let mut ou_json = prepare_ou_json_template();
865
866    ou_json["Properties"]["domain"] = domain.to_uppercase().into();
867    ou_json["Properties"]["distinguishedname"] = result_dn.into();
868    // Check and replace value
869    for (key, value) in &result_attrs {
870        match key.as_str() {
871            "name" => {
872                let name = &value[0];
873                let email = format!("{}@{}",name.to_owned(),domain);
874                ou_json["Properties"]["name"] = email.to_uppercase().into();
875            }
876            "description" => {
877                ou_json["Properties"]["description"] = value[0].to_owned().into();
878            }
879            "whenCreated" => {
880                let epoch = string_to_epoch(&value[0]);
881                if epoch.is_positive() {
882                    ou_json["Properties"]["whencreated"] = epoch.into();
883                }
884            }
885            "gPLink" => {
886                ou_json["Links"] = parse_gplink(value[0].to_string()).into();
887            }
888            "IsDeleted" => {
889                ou_json["IsDeleted"] = true.into();
890            }
891            _ => {}
892        }
893    }
894
895    // For all, bins attributs
896    #[allow(unused_assignments)]
897    let mut guid: String = "".to_owned();
898    for (key, value) in &result_bin {
899        match key.as_str() {
900            "objectGUID" => {
901                // objectGUID raw to string
902                guid = decode_guid(&value[0]);
903                ou_json["ObjectIdentifier"] = guid.to_owned().into();
904            }
905            "nTSecurityDescriptor" => {
906                trace!("nTSecurityDescriptor ACES ACLS ?");
907                // Needed with acl
908                let entry_type = "ou".to_string();
909                // nTSecurityDescriptor raw to string
910                let relations_ace = parse_ntsecuritydescriptor(
911                    &mut ou_json,
912                    &value[0],
913                    entry_type,
914                    &result_attrs,
915                    &result_bin,
916                    &domain,
917                );
918                ou_json["Aces"] = relations_ace.into();
919            }
920            _ => {}
921        }
922    }
923    // Push DN and SID in HashMap
924    dn_sid.insert(
925        ou_json["Properties"]["distinguishedname"]
926            .as_str()
927            .unwrap()
928            .to_string(),
929        ou_json["ObjectIdentifier"].as_str().unwrap().to_string(),
930    );
931    // Push DN and Type
932    sid_type.insert(
933        ou_json["ObjectIdentifier"].as_str().unwrap().to_string(),
934        "OU".to_string(),
935    );
936
937    return ou_json;
938}
939/*****************************************
940******************************************
9415- Function to parse domains information
942******************************************
943*****************************************/
944/// Function to parse and replace value in json template for domain object.
945/// <https://bloodhound.readthedocs.io/en/latest/further-reading/json.html#domains>
946pub fn parse_domain(
947    result: SearchEntry,
948    domain: &String,
949    dn_sid: &mut HashMap<String, String>,
950    sid_type: &mut HashMap<String, String>,
951) -> serde_json::value::Value {
952
953    let _result_dn: String;
954    _result_dn = result.dn.to_uppercase();
955
956    let result_attrs: HashMap<String, Vec<String>>;
957    result_attrs = result.attrs;
958
959    let result_bin: HashMap<String, Vec<Vec<u8>>>;
960    result_bin = result.bin_attrs;
961
962    // Debug for current object
963    //debug!("Parse domain: {}", _result_dn);
964    //for (key, value) in &result_attrs {
965    //    trace!("  {:?}:{:?}", key, value);
966    //}
967    ////trace result bin
968    //for (key, value) in &result_bin {
969    //    trace!("  {:?}:{:?}", key, value);
970    //}
971
972    // json template for one domain
973    let mut domain_json = prepare_domain_json_template();
974
975    // Change all values...
976    #[allow(unused_assignments)]
977    let mut sid: String = "".to_owned();
978    // With a check
979    for (key, value) in &result_attrs {
980        match key.as_str() {
981            "distinguishedName" => {
982                // name & domain & distinguishedname
983                domain_json["Properties"]["distinguishedname"] = value[0].to_owned().to_uppercase().into();
984                let split = value[0].split(",");
985                let vec = split.collect::<Vec<&str>>();
986                let first = vec[0].split("DC=");
987                let vec1 = first.collect::<Vec<&str>>();
988                let last = vec[1].split("DC=");
989                let vec2 = last.collect::<Vec<&str>>();
990                let mut name = "".to_string();
991                name.push_str(vec1[1]);
992                name.push_str(".");
993                name.push_str(vec2[1]);
994                domain_json["Properties"]["name"] = name.to_uppercase().into();
995                domain_json["Properties"]["domain"] = name.to_uppercase().into();
996            }
997            "msDS-Behavior-Version" => {
998                let level = get_forest_level(value[0].to_string());
999                domain_json["Properties"]["functionallevel"] = level.into();
1000            }
1001            "whenCreated" => {
1002                let epoch = string_to_epoch(&value[0]);
1003                if epoch.is_positive() {
1004                    domain_json["Properties"]["whencreated"] = epoch.into();
1005                }
1006            }
1007            "gPLink" => {
1008                domain_json["Links"] = parse_gplink(value[0].to_string()).into();
1009            }
1010            "isCriticalSystemObject" => {
1011                let mut iscriticalsystemobject = false;
1012                if value[0].contains("TRUE") {
1013                    iscriticalsystemobject = true;
1014                }
1015                domain_json["Properties"]["highvalue"] = iscriticalsystemobject.into();
1016            }
1017            // The number of computer accounts that a user is allowed to create in a domain.
1018            "ms-DS-MachineAccountQuota" => {
1019                let machine_account_quota = value[0].parse::<i32>().unwrap_or(0);
1020                if machine_account_quota > 0 {
1021                    info!("MachineAccountQuota: {}",machine_account_quota.to_string().yellow().bold());
1022                }
1023            }
1024            "IsDeleted" => {
1025                domain_json["IsDeleted"] = true.into();
1026            }
1027            _ => {}
1028        }
1029    }
1030    // For all, bins attributs
1031    for (key, value) in &result_bin {
1032        match key.as_str() {
1033            "objectSid" => {
1034                // objectSid raw to string
1035                sid = sid_maker(LdapSid::parse(&value[0]).unwrap().1, domain);
1036                domain_json["ObjectIdentifier"] = sid.to_owned().into();
1037
1038                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();
1039                for domain_sid in re.captures_iter(&sid) 
1040                {
1041                    domain_json["Properties"]["domainsid"] = domain_sid[0].to_owned().to_string().into();
1042                }
1043            }
1044            "nTSecurityDescriptor" => {
1045                // Needed with acl
1046                let entry_type = "domain".to_string();
1047                // nTSecurityDescriptor raw to string
1048                let relations_ace = parse_ntsecuritydescriptor(
1049                    &mut domain_json,
1050                    &value[0],
1051                    entry_type,
1052                    &result_attrs,
1053                    &result_bin,
1054                    &domain,
1055                );
1056                domain_json["Aces"] = relations_ace.into();
1057            }
1058            _ => {}
1059        }
1060    }
1061
1062    // Push DN and SID in HashMap
1063    dn_sid.insert(
1064        domain_json["Properties"]["distinguishedname"]
1065            .as_str()
1066            .unwrap()
1067            .to_string(),
1068        domain_json["ObjectIdentifier"]
1069            .as_str()
1070            .unwrap()
1071            .to_string(),
1072    );
1073    // Push DN and Type
1074    sid_type.insert(
1075        domain_json["ObjectIdentifier"]
1076            .as_str()
1077            .unwrap()
1078            .to_string(),
1079        "Domain".to_string(),
1080    );
1081
1082    return domain_json;
1083}
1084/*****************************************
1085******************************************
10866- Function to parse GPOs values
1087******************************************
1088*****************************************/
1089/// Function to parse and replace value in json template for GPO object.
1090/// <https://bloodhound.readthedocs.io/en/latest/further-reading/json.html#gpos>
1091pub fn parse_gpo(
1092    result: SearchEntry,
1093    domain: &String,
1094    dn_sid: &mut HashMap<String, String>,
1095    sid_type: &mut HashMap<String, String>,
1096) -> serde_json::value::Value {
1097
1098    let result_dn: String;
1099    result_dn = result.dn.to_uppercase();
1100
1101    let result_attrs: HashMap<String, Vec<String>>;
1102    result_attrs = result.attrs;
1103
1104    let result_bin: HashMap<String, Vec<Vec<u8>>>;
1105    result_bin = result.bin_attrs;
1106
1107    // Debug for current object
1108    debug!("Parse gpo: {}", result_dn);
1109    //for (key, value) in &result_attrs {
1110    //    trace!("  {:?}:{:?}", key, value);
1111    //}
1112    ////trace result bin
1113    //for (key, value) in &result_bin {
1114    //    trace!("  {:?}:{:?}", key, value);
1115    //}
1116
1117    // json template for one gpo
1118    let mut gpo_json = prepare_gpo_json_template();
1119    gpo_json["Properties"]["domain"] = domain.to_uppercase().into();
1120    gpo_json["Properties"]["distinguishedname"] = result_dn.into();
1121
1122    // Check and replace value
1123    for (key, value) in &result_attrs {
1124        match key.as_str() {
1125            "displayName" => {
1126                let name = &value[0];
1127                let email = format!("{}@{}",name.to_owned(),domain);
1128                gpo_json["Properties"]["name"] = email.to_uppercase().into();
1129            }
1130            "description" => {
1131                gpo_json["Properties"]["description"] = value[0].to_owned().into();
1132            }
1133            "whenCreated" => {
1134                let epoch = string_to_epoch(&value[0]);
1135                if epoch.is_positive() {
1136                    gpo_json["Properties"]["whencreated"] = epoch.into();
1137                }
1138            }
1139            "gPCFileSysPath" => {
1140                gpo_json["Properties"]["gpcpath"] = value[0].to_owned().into();
1141            }
1142            "IsDeleted" => {
1143                gpo_json["IsDeleted"] = true.into();
1144            }
1145            _ => {}
1146        }
1147    }
1148
1149    // For all, bins attributs
1150    for (key, value) in &result_bin {
1151        match key.as_str() {
1152            "objectGUID" => {
1153                // objectGUID raw to string
1154                let guid = decode_guid(&value[0]);
1155                gpo_json["ObjectIdentifier"] = guid.to_owned().into();
1156            }
1157            "nTSecurityDescriptor" => {
1158                // Needed with acl
1159                let entry_type = "gpo".to_string();
1160                // nTSecurityDescriptor raw to string
1161                let relations_ace = parse_ntsecuritydescriptor(
1162                    &mut gpo_json,
1163                    &value[0],
1164                    entry_type,
1165                    &result_attrs,
1166                    &result_bin,
1167                    &domain,
1168                );
1169                gpo_json["Aces"] = relations_ace.into();
1170            }
1171            _ => {}
1172        }
1173    }
1174
1175    // Push DN and SID in HashMap
1176    dn_sid.insert(
1177        gpo_json["Properties"]["distinguishedname"]
1178            .as_str()
1179            .unwrap()
1180            .to_string(),
1181        gpo_json["ObjectIdentifier"].as_str().unwrap().to_string(),
1182    );
1183    // Push DN and Type
1184    sid_type.insert(
1185        gpo_json["ObjectIdentifier"].as_str().unwrap().to_string(),
1186        "Gpo".to_string(),
1187    );
1188
1189    return gpo_json;
1190}
1191/*****************************************
1192******************************************
11937- Function to parse ForeignSecurityPrincipal
1194******************************************
1195*****************************************/
1196/// Function to parse and replace value in json template for ForeignSecurityPrincipal object.
1197pub fn parse_fsp(
1198    result: SearchEntry,
1199    domain: &String,
1200    dn_sid: &mut HashMap<String, String>,
1201    sid_type: &mut HashMap<String, String>,
1202) -> serde_json::value::Value {
1203
1204    let result_dn: String;
1205    result_dn = result.dn.to_uppercase();
1206
1207    let result_attrs: HashMap<String, Vec<String>>;
1208    result_attrs = result.attrs;
1209
1210    let _result_bin: HashMap<String, Vec<Vec<u8>>>;
1211    _result_bin = result.bin_attrs;
1212
1213    // Debug for current object
1214    debug!("Parse ForeignSecurityPrincipal: {}", result_dn);
1215    //for (key, value) in &result_attrs {
1216    //    trace!("  {:?}:{:?}", key, value);
1217    //}
1218    ////trace result bin
1219    //for (key, value) in &result_bin {
1220    //    trace!("  {:?}:{:?}", key, value);
1221    //}
1222
1223    // json template for one fsp
1224    let mut fsp_json = prepare_fsp_json_template();
1225    fsp_json["Properties"]["distinguishedname"] = result_dn.into();
1226
1227    #[allow(unused_assignments)]
1228    let mut sid: String = "".to_owned();
1229    // With a check
1230    for (key, value) in &result_attrs {
1231        match key.as_str() {
1232            "name" => {
1233                let name = format!("{}-{}",domain,&value[0]);
1234                fsp_json["Properties"]["name"] = name.to_uppercase().into();
1235
1236                // Type for group Member maker
1237                // based on https://docs.microsoft.com/fr-fr/troubleshoot/windows-server/identity/security-identifiers-in-windows
1238                let split = value[0].split("-");
1239                let vec = split.collect::<Vec<&str>>();
1240                let len = vec.len();
1241                let last = vec[len - 1].parse::<i32>().unwrap_or(0);
1242                if last >= 17 {
1243                    fsp_json["Properties"]["type"] = "User".into();
1244                } else {
1245                    fsp_json["Properties"]["type"] = "Group".into();
1246                }
1247            }
1248            "whenCreated" => {
1249                let epoch = string_to_epoch(&value[0]);
1250                if epoch.is_positive() {
1251                    fsp_json["Properties"]["whencreated"] = epoch.into();
1252                }
1253            }
1254            "objectSid" => {
1255                //objectSid to vec and raw to string
1256                let vec_sid = objectsid_to_vec8(&value[0]);
1257                sid = sid_maker(LdapSid::parse(&vec_sid).unwrap().1, domain);
1258                fsp_json["ObjectIdentifier"] = sid.to_owned().into();
1259
1260                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();
1261                for domain_sid in re.captures_iter(&sid) 
1262                {
1263                    fsp_json["Properties"]["domainsid"] = domain_sid[0].to_owned().to_string().into();
1264                }
1265            }
1266            "IsDeleted" => {
1267                fsp_json["IsDeleted"] = true.into();
1268            }
1269            _ => {}
1270        }
1271    }
1272
1273    // Push DN and SID in HashMap
1274    if fsp_json["ObjectIdentifier"].as_str().unwrap() != "SID" {
1275        dn_sid.insert(
1276            fsp_json["Properties"]["distinguishedname"]
1277                .as_str()
1278                .unwrap()
1279                .to_string(),
1280            fsp_json["ObjectIdentifier"].as_str().unwrap().to_string(),
1281        );
1282        // Push DN and Type
1283        sid_type.insert(
1284            fsp_json["ObjectIdentifier"].as_str().unwrap().to_string(),
1285            fsp_json["Properties"]["type"].as_str().unwrap().to_string(),
1286        );
1287    }
1288
1289    return fsp_json;
1290}
1291
1292
1293/*****************************************
1294******************************************
12958- Function to parse Container
1296******************************************
1297*****************************************/
1298/// Function to parse and replace value in json template for Container object.
1299pub fn parse_container(
1300    result: SearchEntry,
1301    domain: &String,
1302    dn_sid: &mut HashMap<String, String>,
1303    sid_type: &mut HashMap<String, String>,
1304) -> serde_json::value::Value {
1305
1306    let result_dn: String;
1307    result_dn = result.dn.to_uppercase();
1308
1309    let result_attrs: HashMap<String, Vec<String>>;
1310    result_attrs = result.attrs;
1311
1312    let result_bin: HashMap<String, Vec<Vec<u8>>>;
1313    result_bin = result.bin_attrs;
1314
1315    // Debug for current object
1316    debug!("Parse Container: {}", result_dn.to_uppercase());
1317    //for (key, value) in &result_attrs {
1318    //    trace!("  {:?}:{:?}", key, value);
1319    //}
1320    ////trace result bin
1321    //for (key, value) in &result_bin {
1322    //    trace!("  {:?}:{:?}", key, value);
1323    //}
1324
1325    // json template for one container
1326    let mut container_json = prepare_container_json_template();
1327    container_json["Properties"]["domain"] = domain.to_owned().to_uppercase().into();
1328    container_json["Properties"]["distinguishedname"] = result_dn.into();
1329
1330    // With a check
1331    for (key, value) in &result_attrs {
1332        match key.as_str() {
1333            "name" => {
1334                let name = &value[0];
1335                let email = format!("{}@{}",name.to_owned(),domain);
1336                container_json["Properties"]["name"] = email.to_uppercase().into();
1337            }
1338            _ => {}
1339        }
1340    }
1341    // For all, bins attributs
1342    for (key, value) in &result_bin {
1343        match key.as_str() {
1344            "objectGUID" => {
1345                let guid = decode_guid(&value[0]);
1346                container_json["ObjectIdentifier"] = guid.to_owned().into();
1347            }
1348            "nTSecurityDescriptor" => {
1349                // Needed with acl
1350                let entry_type = "container".to_string();
1351                // nTSecurityDescriptor raw to string
1352                let relations_ace = parse_ntsecuritydescriptor(
1353                    &mut container_json,
1354                    &value[0],
1355                    entry_type,
1356                    &result_attrs,
1357                    &result_bin,
1358                    &domain,
1359                );
1360                container_json["Aces"] = relations_ace.into();
1361            }
1362            "IsDeleted" => {
1363                container_json["IsDeleted"] = true.into();
1364            }
1365            _ => {}
1366        }
1367    }
1368
1369    // Push DN and SID in HashMap
1370    dn_sid.insert(
1371        container_json["Properties"]["distinguishedname"]
1372            .as_str()
1373            .unwrap()
1374            .to_string(),
1375        container_json["ObjectIdentifier"].as_str().unwrap().to_string(),
1376    );
1377    // Push DN and Type
1378    sid_type.insert(
1379        container_json["ObjectIdentifier"].as_str().unwrap().to_string(),
1380        "Container".to_string(),
1381    );
1382
1383    return container_json;
1384}
1385
1386/*****************************************
1387******************************************
13889- Function to parse trust domain values
1389******************************************
1390*****************************************/
1391/// Function to parse and replace value in json template for trust domain object.
1392pub fn parse_trust(result: SearchEntry, domain: &String) -> serde_json::value::Value  {
1393
1394    let result_dn: String;
1395    result_dn = result.dn.to_uppercase();
1396
1397    let result_attrs: HashMap<String, Vec<String>>;
1398    result_attrs = result.attrs;
1399
1400    let result_bin: HashMap<String, Vec<Vec<u8>>>;
1401    result_bin = result.bin_attrs;
1402
1403    let mut trust_json = prepare_trust_json_template();
1404
1405    // Debug for current object
1406    debug!("Parse TrustDomain: {}", result_dn);
1407    //for (key, value) in &result_attrs {
1408    //    trace!("  {:?}:{:?}", key, value);
1409    //}
1410    ////trace result bin
1411    //for (key, value) in &result_bin {
1412    //    trace!("  {:?}:{:?}", key, value);
1413    //}
1414
1415    // With a check
1416    for (key, value) in &result_attrs {
1417        match key.as_str() {
1418            "name" => {
1419                trust_json["TargetDomainName"] = value[0].to_uppercase().into();
1420            }
1421            "trustDirection" => {
1422                let trustdirection: u8 = value[0].parse::<u8>().unwrap_or(0);
1423                // <https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-adts/5026a939-44ba-47b2-99cf-386a9e674b04>
1424                match trustdirection { 
1425                    1 => { trust_json["TrustDirection"] = "Inbound".into(); }
1426                    2 => { trust_json["TrustDirection"] = "Outbound".into(); }
1427                    3 => { trust_json["TrustDirection"] = "Bidirectional".into(); } 
1428                    _ => { trust_json["TrustDirection"] = "Disable".into(); }
1429                }
1430            }
1431            "trustAttributes" => {
1432                let trustflag: u32 = value[0].parse::<u32>().unwrap_or(0);
1433                get_trust_flag(trustflag, &mut trust_json);
1434            }
1435            _ => {}
1436        }
1437    }
1438    // For all, bins attributs
1439    for (key, value) in &result_bin {
1440        match key.as_str() {
1441            "securityIdentifier" => {
1442                let sid = sid_maker(LdapSid::parse(&value[0]).unwrap().1, domain);
1443                trust_json["TargetDomainSid"] = sid.to_owned().into();
1444            }
1445            _ => {}
1446        }
1447    }
1448    //trace!("TRUST VALUE: {:?}",trust_json);
1449    return trust_json
1450}
1451
1452/*****************************************
1453******************************************
145410- Function to parse unknown values
1455******************************************
1456*****************************************/
1457/// Function to parse and replace value in json template for unknown object.
1458pub fn parse_unknown(result: SearchEntry, _domain: &String) -> serde_json::value::Value  {
1459
1460    let _result_dn = result.dn.to_uppercase();
1461
1462    let _result_attrs: HashMap<String, Vec<String>>;
1463    _result_attrs = result.attrs;
1464
1465    let _result_bin: HashMap<String, Vec<Vec<u8>>>;
1466    _result_bin = result.bin_attrs;
1467
1468    let unknown_json = json!({
1469        "unknown": null,
1470    });
1471
1472    // Debug for current object
1473    //debug!("Parse Unknown: {}", _result_dn);
1474    //for (key, value) in &_result_attrs {
1475    //    trace!("  {:?}:{:?}", key, value);
1476    //}
1477    ////trace result bin
1478    //for (key, value) in &_result_bin {
1479    //    trace!("  {:?}:{:?}", key, value);
1480    //}
1481
1482    return unknown_json
1483}