ntdsextract2 1.4.33

Display contents of Active Directory database files (ntds.dit)
use std::fmt::Display;

use getset::Getters;
use libntdsextract2::{cache::RecordId, CDatabase};

#[derive(Debug, Getters)]
#[getset(get="pub")]
pub struct MembershipTreeEntry {
    account_name: String,
    distinguished_name: String
}

impl MembershipTreeEntry {
    pub fn try_from(record_id: &RecordId, database: &CDatabase<'_, '_>) -> Option<Self> {
        let pointer = database
            .data_table()
            .data_table()
            .metadata()
            .ptr_from_id(record_id)
            .expect("invalid record id");
        match database.entry(record_id.into()) {
            Ok(Some(record)) => {
                let account_name = match record.att_sam_account_name_opt() {
                    Ok(Some(name)) => name,
                    Ok(None) => {
                        record.att_object_name2().expect("Object has no RDN").to_string()
                    }
                    Err(why) => {
                        log::error!(
                            "Error while reading samAccountName for {}: {why}",
                            record.ds_record_id().unwrap()
                        );
                        return None;
                    }
                };

                let distinguished_name = match database.data_table().object_tree().dn_of(pointer) {
                    Some(dn) => dn,
                    None => {
                        log::error!(
                            "Record {} has no distinguished name",
                            record.ds_record_id().unwrap()
                        );
                        return None;
                    }
                };

                Some(Self {
                    account_name,
                    distinguished_name
                })
            }
            Ok(None) => panic!("illegal record pointer: {pointer:?}"),
            Err(why) => {
                log::error!("Error while reading a record: {why}");
                None
            }
        }
    }
}

impl Display for MembershipTreeEntry {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        write!(
            f,
            "{account_name} ({distinguished_name})",
            account_name = self.account_name,
            distinguished_name = self.distinguished_name
        )
    }
}