use hashbrown::HashMap;
use base64::prelude::*;
use crate::{
cache::{self, ColumnIndex, Record, Value, WithValue},
win32_types::SecurityDescriptor,
};
pub struct SdTable {
descriptors: HashMap<i64, Vec<u8>>,
}
impl SdTable {
pub fn new(sd_table: &cache::SdTable) -> crate::ntds::Result<Self> {
let sd_id_column = sd_table.sd_id_column();
let sd_value_column = sd_table.sd_value_column();
let descriptors: crate::ntds::Result<HashMap<i64, Vec<u8>>> = sd_table
.iter()
.map(|record| Self::descriptor_from_record(&record, sd_id_column, sd_value_column))
.collect();
Ok(Self {
descriptors: descriptors?,
})
}
fn descriptor_from_record(
record: &Record<'_, '_>,
sd_id_column: &ColumnIndex,
sd_value_column: &ColumnIndex,
) -> crate::ntds::Result<(i64, Vec<u8>)> {
Ok((
Self::sd_id_from_record(record, sd_id_column)?,
Self::sd_value_from_record(record, sd_value_column)?,
))
}
fn sd_id_from_record(
record: &Record<'_, '_>,
sd_id_column: &ColumnIndex,
) -> crate::ntds::Result<i64> {
record.with_value(*sd_id_column, |v| match v.unwrap() {
Value::I16(v) => Ok(i64::from(*v)),
Value::I32(v) => Ok(i64::from(*v)),
Value::I64(v) => Ok(*v),
Value::Currency(v) => Ok(*v),
v => unimplemented!("no support for {v} as sd_id"),
})
}
fn sd_value_from_record(
record: &Record<'_, '_>,
sd_value_column: &ColumnIndex,
) -> crate::ntds::Result<Vec<u8>> {
record.with_value(*sd_value_column, |v| match v.unwrap() {
Value::Binary(v) => Ok(v.as_ref().clone()),
v => unimplemented!("no support for {v} as sd_value"),
})
}
pub fn descriptor(
&self,
sd_id: &i64,
) -> Result<Option<SecurityDescriptor>, crate::ntds::Error> {
match self.descriptors.get(sd_id) {
Some(v) => match SecurityDescriptor::try_from(&v[..]) {
Ok(sd) => Ok(Some(sd)),
Err(why) => {
log::error!("failed descriptor was: {}", BASE64_STANDARD.encode(v));
log::error!("{why}");
Err(why)
}
},
None => Ok(None),
}
}
pub fn descriptors(
&self,
) -> impl Iterator<Item = (i64, Result<SecurityDescriptor, crate::ntds::Error>)> + '_ {
self.descriptors.iter().map(|(id, bin_sd)| {
let sd = match SecurityDescriptor::try_from(&bin_sd[..]) {
Ok(sd) => Ok(sd),
Err(why) => {
log::error!("failed descriptor was: {}", BASE64_STANDARD.encode(bin_sd));
log::error!("{why}");
Err(why)
}
};
(*id, sd)
})
}
pub fn len(&self) -> usize {
self.descriptors.len()
}
#[must_use]
pub fn is_empty(&self) -> bool {
self.len() == 0
}
}