use std::path::{Path, PathBuf}; use crate::define_parser::parse_defines; const OPENSSH_TAG: &str = "V_9_9_P2"; /// Default algorithms for ssh. #[derive(Debug, Default, Clone, PartialEq, Eq)] pub struct MyPrefs { pub ca_signature_algorithms: Vec, pub ciphers: Vec, pub host_key_algorithms: Vec, pub kex_algorithms: Vec, pub mac: Vec, pub pubkey_accepted_algorithms: Vec, } pub fn get_my_prefs() -> anyhow::Result { let out_dir = std::env::var_os("OUT_DIR") .map(|s| PathBuf::from(s).join("openssh")) .ok_or_else(|| anyhow::anyhow!("OUT_DIR not set"))?; let build_dir = out_dir.join("build"); let inner_dir = build_dir.join("src"); std::fs::remove_dir_all(&build_dir).ok(); std::fs::create_dir_all(&inner_dir).ok(); clone_openssh(&inner_dir)?; let my_proposal_path = inner_dir.join("myproposal.h"); let reader = std::io::BufReader::new(std::fs::File::open(my_proposal_path)?); let defines = parse_defines(reader)?; let ca_signature_algorithms = defines .get("SSH_ALLOWED_CA_SIGALGS") .map(|s| s.split_whitespace().map(|s| format!(r#""{s}""#)).collect()) .unwrap_or_default(); let ciphers = defines .get("KEX_CLIENT_ENCRYPT") .map(|s| s.split_whitespace().map(|s| format!(r#""{s}""#)).collect()) .unwrap_or_default(); let host_key_algorithms = defines .get("KEX_DEFAULT_PK_ALG") .map(|s| s.split_whitespace().map(|s| format!(r#""{s}""#)).collect()) .unwrap_or_default(); let kex_algorithms = defines .get("KEX_CLIENT") .map(|s| s.split_whitespace().map(|s| format!(r#""{s}""#)).collect()) .unwrap_or_default(); let mac = defines .get("KEX_CLIENT_MAC") .map(|s| s.split_whitespace().map(|s| format!(r#""{s}""#)).collect()) .unwrap_or_default(); let pubkey_accepted_algorithms = defines .get("KEX_DEFAULT_PK_ALG") .map(|s| s.split_whitespace().map(|s| format!(r#""{s}""#)).collect()) .unwrap_or_default(); Ok(MyPrefs { ca_signature_algorithms, ciphers, host_key_algorithms, kex_algorithms, mac, pubkey_accepted_algorithms, }) } fn clone_openssh(path: &Path) -> anyhow::Result<()> { let repo_url = "https://github.com/openssh/openssh-portable.git"; let repo = git2::Repository::clone(repo_url, path)?; let obj = repo.revparse_single(OPENSSH_TAG)?; let commit = obj.peel_to_commit()?; repo.checkout_tree(&obj, None)?; repo.set_head_detached(commit.id())?; Ok(()) }