use std::collections::HashMap; use std::str::FromStr; use cvrf_xmlparser::{Severity, CUSA}; use lazy_static::lazy_static; use rpm_rs::rpm::{get_installed_packages, Package}; use rpm_rs::rpmio::rpmvercmp; use updateinfo_xmlparser::{RpmInfo, UpdateInfoDb}; use crate::analyzer::db::{CveDb, PackgeDb, SaDb}; use crate::cli::Cli; lazy_static! { pub static ref update_pkgs: PackgeDb = { let mut updatedb = UpdateInfoDb::new(); updatedb.load_xml("test/updateinfo.xml").unwrap(); let mut pkgdb = PackgeDb::new(); pkgdb.load_from_updateinfodb(&updatedb); pkgdb }; pub static ref sadb: SaDb = { let mut _sadb = SaDb::new(); _sadb.load_from_file("test/cvrf_sainfos.json").unwrap(); _sadb }; pub static ref cvedb: CveDb = sadb.get_cvedb(); } pub mod db; pub fn cuvat_run(cli: &Cli) -> crate::Result<()> { // 只报告 cve 相关 if cli.cves { return list_cves(cli); } // 只报告 sa 相关 if cli.sas { return list_sas(cli); } // 生成报告 if cli.report { return repoter(cli); } // 默认报告格式 summary(cli) } fn list_cves(cli: &Cli) -> crate::Result<()> { Ok(()) } fn list_sas(cli: &Cli) -> crate::Result<()> { Ok(()) } fn repoter(cli: &Cli) -> crate::Result<()> { Ok(()) } fn summary(cli: &Cli) -> crate::Result<()> { let avaliable = get_avaliable()?; let severity = Severity::from_str(&cli.severity)?; let mut res = vec![0; 5]; for (cusa, rpms) in &avaliable { // 过滤 if cusa.severity() < &severity { continue; } let pos: usize = cusa.severity().into(); res[pos] += 1; } let msg = format!(" 漏洞扫描结果如下: 致命漏洞: {:3} 个 高危漏洞: {:3} 个 中危漏洞: {:3} 个 低危漏洞: {:3} 个 ", res[4], res[3], res[2], res[1]); println!("{}", msg); Ok(()) } // 获取当前可用的更新,所有安全检查均基于此 fn get_avaliable() -> crate::Result>> { let mut avaliable: HashMap> = HashMap::new(); // 当前系统所有已安装的 rpm 包 let installed = get_installed_packages(); // installed 已被消费掉 // latest_installed 是所有最新版本软件包的 Vec let latest_installed: Vec = installed .into_iter() .map(|(_, pkgs)| { let mut latest = pkgs[0].clone(); for pkg in pkgs.into_iter() { latest = rpmdb_package_vercmp(latest, pkg); } latest }) .collect(); // 获取 sa 更新列表 for pkg in latest_installed { let name = pkg.name(); if let Some(updates) = update_pkgs.db().get(name) { for update in updates { // 因 updateinfo 里包含所有架构,故于此做个判断 // 是否考虑架构信息在不同的版本有所不同? if update.arch() != pkg.arch().unwrap() { continue; } // epoch 判断 match (update.epoch(), pkg.epoch()) { (Some(_), None) => { _add_to_avaliable(&mut avaliable, update.sa(), update.clone()); } (None, Some(_)) => continue, _ => {} } // evr 对比 if rpmvercmp(&update.evr(), &pkg.evr()) > 0 { _add_to_avaliable(&mut avaliable, update.sa(), update.clone()); } } } } Ok(avaliable) } fn _add_to_avaliable(avaliable: &mut HashMap>, sa: &str, rpm: RpmInfo) { let sainfo = sadb.db().get(sa).unwrap(); if let Some(rpms) = avaliable.get_mut(sainfo) { rpms.push(rpm); } else { let rpms = vec![rpm]; avaliable.insert(sainfo.clone(), rpms); } } // 对比两个 rpm Package 的版本,返回最新的一个 fn rpmdb_package_vercmp(pa: Package, pb: Package) -> Package { // 首先进行 epoch 的比较 match (pa.epoch(), pb.epoch()) { (Some(_), None) => return pa, (None, Some(_)) => return pb, _ => {} // 继续往下对比 } if rpmvercmp(&pa.evr(), &pb.evr()) > 0 { return pa; } else { return pb; } }