use libntdsextract2::{ntds::TransitiveClosure, win32_types::Rdn, CDatabase, EntryId, Resolve};
use crate::walk::{
acl_line::AclLine, attribute_line_set::AttributeLineSet,
membership_tree_entry::MembershipTreeEntry,
};
pub struct EntryAttributes {
pub sam_account_name: Option<String>,
pub object_name: Rdn,
pub attributes: Vec<AttributeLineSet>,
pub sacls: Vec<AclLine>,
pub dacls: Vec<AclLine>,
pub owner: Option<String>,
pub group: Option<String>,
pub member_of: Option<TransitiveClosure<MembershipTreeEntry>>,
pub members: Option<TransitiveClosure<MembershipTreeEntry>>,
}
impl EntryAttributes {
pub fn new<'info, 'db>(database: &CDatabase<'info, 'db>, entry_id: EntryId) -> Self {
let attributes: Vec<_>;
let mut sacls = Vec::new();
let mut dacls = Vec::new();
let mut owner = None;
let mut group = None;
let member_of;
let members;
if let Ok(Some(entry)) = database.entry(entry_id) {
let sam_account_name = entry.att_sam_account_name_opt().unwrap();
let object_name = entry.att_object_name2().expect("missing object name");
attributes = entry
.all_attributes()
.iter()
.map(|(i, a)| AttributeLineSet::from(database, i, a))
.collect();
match entry.security_descriptor(database.sd_table().as_ref().unwrap()) {
Ok(sd) => {
if let Some(sd) = sd.as_ref() {
if let Some(user_sid) = sd.as_ref().owner() {
match database.resolve(user_sid.sid()) {
Some(entry) => {
owner = Some(
entry
.sam_account_name()
.as_ref()
.map(|s| &s[..])
.unwrap_or_else(|| entry.rdn().as_str())
.to_string(),
);
}
None => {
log::error!("Did not find an entry for SID {}", user_sid.sid());
owner = Some(user_sid.sid().to_string());
}
}
}
if let Some(group_sid) = sd.as_ref().group() {
match database.resolve(group_sid.sid()) {
Some(entry) => {
group = Some(
entry
.sam_account_name()
.as_ref()
.map(|s| &s[..])
.unwrap_or_else(|| entry.rdn().as_str())
.to_string(),
);
}
None => {
log::error!("Did not find an entry for SID {}", group_sid.sid());
group = Some(group_sid.sid().to_string());
}
}
}
if let Some(acl) = sd.as_ref().sacl().as_ref() {
sacls = acl
.ace_list()
.iter()
.enumerate()
.map(|(index, ace)| AclLine::from(database, index, ace))
.collect();
}
if let Some(acl) = sd.as_ref().dacl().as_ref() {
dacls = acl
.ace_list()
.iter()
.enumerate()
.map(|(index, ace)| AclLine::from(database, index, ace))
.collect();
}
}
}
Err(why) => {
log::error!("unable to access security descriptor of {entry_id:?}: {why}");
}
}
member_of = database
.link_table()
.transitive_member_of(&entry.ds_record_id().unwrap())
.filter_map(|record_id| MembershipTreeEntry::try_from(&record_id, database));
members = database
.link_table()
.transitive_members(&entry.ds_record_id().unwrap())
.filter_map(|record_id| MembershipTreeEntry::try_from(&record_id, database));
Self {
sam_account_name,
object_name,
attributes,
sacls,
dacls,
owner,
group,
member_of,
members,
}
} else {
panic!("found no database entry for id {entry_id:?}");
}
}
}