1use std::{collections::HashMap, error::Error};
2
3use indicatif::ProgressBar;
4use ldap3::SearchEntry;
5
6use crate::{
7 args::Options, banner::progress_bar, enums::{get_type, Type, PARSER_MOD_RE1, PARSER_MOD_RE2}, json::{
8 checker::check_all_result,
9 },
10 objects::{
11 aiaca::AIACA, certtemplate::CertTemplate, common::parse_unknown, computer::Computer, container::Container, domain::Domain, enterpriseca::EnterpriseCA, fsp::Fsp, gpo::Gpo, group::Group, inssuancepolicie::IssuancePolicie, ntauthstore::NtAuthStore, ou::Ou, rootca::RootCA, trust::Trust, user::User
12 },
13 storage::{EntrySource}
14};
15
16#[derive(Default)]
17pub struct ADResults {
18 pub users: Vec<User>,
19 pub groups: Vec<Group>,
20 pub computers: Vec<Computer>,
21 pub ous: Vec<Ou>,
22 pub domains: Vec<Domain>,
23 pub gpos: Vec<Gpo>,
24 pub fsps: Vec<Fsp>,
25 pub containers: Vec<Container>,
26 pub trusts: Vec<Trust>,
27 pub ntauthstores: Vec<NtAuthStore>,
28 pub aiacas: Vec<AIACA>,
29 pub rootcas: Vec<RootCA>,
30 pub enterprisecas: Vec<EnterpriseCA>,
31 pub certtemplates: Vec<CertTemplate>,
32 pub issuancepolicies: Vec<IssuancePolicie>,
33
34 pub mappings: DomainMappings,
35}
36
37#[derive(Default)]
38pub struct DomainMappings {
39 pub dn_sid: HashMap<String, String>,
41 pub sid_type: HashMap<String, String>,
43 pub fqdn_sid: HashMap<String, String>,
45 pub fqdn_ip: HashMap<String, String>,
47}
48
49impl ADResults {
50 pub fn new() -> Self {
51 Self::default()
52 }
53}
54
55pub async fn prepare_results_from_source<S: EntrySource>(
56 source: S,
57 options: &Options,
58 total_objects: Option<usize>,
59) -> Result<ADResults, Box<dyn std::error::Error>> {
60 let mut ad_results = parse_result_type_from_source(options, source, total_objects)?;
61
62 check_all_result(
64 options,
65 &mut ad_results.users,
66 &mut ad_results.groups,
67 &mut ad_results.computers,
68 &mut ad_results.ous,
69 &mut ad_results.domains,
70 &mut ad_results.gpos,
71 &mut ad_results.fsps,
72 &mut ad_results.containers,
73 &mut ad_results.trusts,
74 &mut ad_results.ntauthstores,
75 &mut ad_results.aiacas,
76 &mut ad_results.rootcas,
77 &mut ad_results.enterprisecas,
78 &mut ad_results.certtemplates,
79 &mut ad_results.issuancepolicies,
80 &ad_results.mappings.dn_sid,
81 &ad_results.mappings.sid_type,
82 &ad_results.mappings.fqdn_sid,
83 &ad_results.mappings.fqdn_ip,
84 )?;
85
86 Ok(ad_results)
87}
88
89pub fn parse_result_type_from_source(
92 common_args: &Options,
93 source: impl EntrySource,
94 total_objects: Option<usize>,
95) -> Result<ADResults, Box<dyn Error>> {
96 let mut results = ADResults::default();
97 let domain = &common_args.domain;
99
100 let pb = ProgressBar::new(1);
102 let mut count = 0;
103 let total = total_objects;
104 let mut domain_sid: String = "DOMAIN_SID".to_owned();
105
106 log::info!("Starting the LDAP objects parsing...");
107
108 let dn_sid = &mut results.mappings.dn_sid;
109 let sid_type = &mut results.mappings.sid_type;
110 let fqdn_sid = &mut results.mappings.fqdn_sid;
111 let fqdn_ip = &mut results.mappings.fqdn_ip;
112
113 for entry in source.into_entry_iter() {
114 let entry: SearchEntry = entry?.into();
115 let atype = get_type(&entry).unwrap_or(Type::Unknown);
117 match atype {
118 Type::User => {
119 let mut user: User = User::new();
120 user.parse(entry, domain, dn_sid, sid_type, &domain_sid)?;
121 results.users.push(user);
122 }
123 Type::Group => {
124 let mut group = Group::new();
125 group.parse(entry, domain, dn_sid, sid_type, &domain_sid)?;
126 results.groups.push(group);
127 }
128 Type::Computer => {
129 let mut computer = Computer::new();
130 computer.parse(
131 entry,
132 domain,
133 dn_sid,
134 sid_type,
135 fqdn_sid,
136 fqdn_ip,
137 &domain_sid,
138 )?;
139 results.computers.push(computer);
140 }
141 Type::Ou => {
142 let mut ou = Ou::new();
143 ou.parse(entry, domain, dn_sid, sid_type, &domain_sid)?;
144 results.ous.push(ou);
145 }
146 Type::Domain => {
147 let mut domain_object = Domain::new();
148 let domain_sid_from_domain =
149 domain_object.parse(entry, domain, dn_sid, sid_type)?;
150 domain_sid = domain_sid_from_domain;
151 results.domains.push(domain_object);
152 }
153 Type::Gpo => {
154 let mut gpo = Gpo::new();
155 gpo.parse(entry, domain, dn_sid, sid_type, &domain_sid)?;
156 results.gpos.push(gpo);
157 }
158 Type::ForeignSecurityPrincipal => {
159 let mut security_principal = Fsp::new();
160 security_principal.parse(entry, domain, dn_sid, sid_type)?;
161 results.fsps.push(security_principal);
162 }
163 Type::Container => {
164 if PARSER_MOD_RE1.is_match(&entry.dn.to_uppercase())
165 || PARSER_MOD_RE2.is_match(&entry.dn.to_uppercase())
166 {
167 continue;
169 }
170
171 let mut container = Container::new();
173 container.parse(entry, domain, dn_sid, sid_type, &domain_sid)?;
174 results.containers.push(container);
175 }
176 Type::Trust => {
177 let mut trust = Trust::new();
178 trust.parse(entry, domain)?;
179 results.trusts.push(trust);
180 }
181 Type::NtAutStore => {
182 let mut nt_auth_store = NtAuthStore::new();
183 nt_auth_store.parse(entry, domain, dn_sid, sid_type, &domain_sid)?;
184 results.ntauthstores.push(nt_auth_store);
185 }
186 Type::AIACA => {
187 let mut aiaca = AIACA::new();
188 aiaca.parse(entry, domain, dn_sid, sid_type, &domain_sid)?;
189 results.aiacas.push(aiaca);
190 }
191 Type::RootCA => {
192 let mut root_ca = RootCA::new();
193 root_ca.parse(entry, domain, dn_sid, sid_type, &domain_sid)?;
194 results.rootcas.push(root_ca);
195 }
196 Type::EnterpriseCA => {
197 let mut enterprise_ca = EnterpriseCA::new();
198 enterprise_ca.parse(entry, domain, dn_sid, sid_type, &domain_sid)?;
199 results.enterprisecas.push(enterprise_ca);
200 }
201 Type::CertTemplate => {
202 let mut cert_template = CertTemplate::new();
203 cert_template.parse(entry, domain, dn_sid, sid_type, &domain_sid)?;
204 results.certtemplates.push(cert_template);
205 }
206 Type::IssuancePolicie => {
207 let mut issuance_policie = IssuancePolicie::new();
208 issuance_policie.parse(entry, domain, dn_sid, sid_type, &domain_sid)?;
209 results.issuancepolicies.push(issuance_policie);
210 }
211 Type::Unknown => {
212 let _unknown = parse_unknown(entry, domain);
213 }
214 }
215 if let Some(total) = total {
218 count += 1;
219 let pourcentage = 100 * count / total;
220 progress_bar(
221 pb.to_owned(),
222 "Parsing LDAP objects".to_string(),
223 pourcentage.try_into()?,
224 "%".to_string(),
225 );
226 }
227 }
228
229 pb.finish_and_clear();
230 log::info!("Parsing LDAP objects finished!");
231 Ok(results)
232}
233