Skip to main content

windows_permissions/structures/
trustee.rs

1use crate::constants::TrusteeForm;
2use crate::utilities;
3use crate::wrappers;
4use crate::Sid;
5use std::ffi::OsStr;
6use std::fmt;
7use std::marker::PhantomData;
8use std::ptr::NonNull;
9use winapi::ctypes::c_void;
10use winapi::um::accctrl::TRUSTEE_W;
11
12/// An entity that can be added to an ACL.
13///
14/// Trustees can identify their subject (usually an account or a group) using a
15/// string or a `Sid`.
16#[repr(C)]
17pub struct Trustee<'s> {
18    inner: TRUSTEE_W,
19    _phantom: PhantomData<TrusteeSubject<'s>>,
20}
21
22/// The contents of a Trustee.
23#[derive(Debug)]
24pub enum TrusteeSubject<'s> {
25    /// This trustee holds a zero-terminated WTF-16-encoded name. This can be
26    /// converted into an [`OsString`](`std::ffi::OsString`) using
27    /// [`utilities::os_from_buf`].
28    Name(&'s [u16]),
29
30    /// This trustee holds a reference to the Sid it was created with.
31    Sid(&'s Sid),
32
33    /// An opaque pointer to objects and SID.
34    ObjectsAndSid(*const c_void),
35
36    /// An opaque pointer to objects and name.
37    ObjectsAndName(*const c_void),
38
39    /// `Bad` means that `trusteeForm` is explicitly set to `TRUSTEE_BAD_FORM`
40    Bad,
41}
42
43impl<'s> Trustee<'s> {
44    /// Get a pointer to the underlying buffer
45    pub fn as_ptr(&self) -> *const TRUSTEE_W {
46        &self.inner
47    }
48
49    /// Get a mutable pointer to the underlying buffer
50    pub fn as_mut_ptr(&mut self) -> *mut TRUSTEE_W {
51        &mut self.inner
52    }
53
54    /// Allocate and zero-initialize space for a Trustee
55    ///
56    /// # Safety
57    ///
58    /// The Trustee is zero-initialized, and should only be used in contexts
59    /// where that is acceptable.
60    pub unsafe fn allocate() -> Self {
61        Self {
62            inner: std::mem::zeroed(),
63            _phantom: PhantomData,
64        }
65    }
66
67    /// Get the `TrusteeSubject` of a `Trustee`
68    ///
69    /// # Panics
70    ///
71    /// Panics if the `trusteeForm` in the underlying object is an unrecognized
72    /// value. To get the value, use `wrappers::GetTrusteeForm` directly.
73    ///
74    /// Also panics if the pointer value is null.
75    pub fn get_subject(&self) -> TrusteeSubject<'s> {
76        let form = wrappers::GetTrusteeForm(&self)
77            .unwrap_or_else(|f| panic!("Trustee had unrecognized form: {:x}", f));
78
79        let ptr = self.inner.ptstrName as *mut _;
80
81        match form {
82            TrusteeForm::TRUSTEE_IS_SID => {
83                let ptr =
84                    NonNull::new(ptr).expect("Null SID pointer on Trustee with TRUSTEE_IS_SID");
85
86                unsafe { TrusteeSubject::Sid(&*ptr.as_ptr()) }
87            }
88            TrusteeForm::TRUSTEE_IS_NAME => {
89                let ptr =
90                    NonNull::new(ptr).expect("Null name pointer on Trustee with TRUSTEE_IS_NAME");
91
92                unsafe {
93                    let nul_pos = utilities::search_buffer(&0x00, ptr.as_ptr() as *const u16);
94                    TrusteeSubject::Name(std::slice::from_raw_parts(
95                        ptr.as_ptr() as *const u16,
96                        nul_pos + 1,
97                    ))
98                }
99            }
100            TrusteeForm::TRUSTEE_IS_OBJECTS_AND_SID => {
101                TrusteeSubject::ObjectsAndSid(ptr as *const _)
102            }
103            TrusteeForm::TRUSTEE_IS_OBJECTS_AND_NAME => {
104                TrusteeSubject::ObjectsAndName(ptr as *const _)
105            }
106            TrusteeForm::TRUSTEE_BAD_FORM => TrusteeSubject::Bad,
107        }
108    }
109}
110
111impl<'s> From<&'s Sid> for Trustee<'s> {
112    fn from(sid: &'s Sid) -> Self {
113        wrappers::BuildTrusteeWithSid(sid)
114    }
115}
116
117impl From<&OsStr> for Trustee<'static> {
118    fn from(name: &OsStr) -> Self {
119        wrappers::BuildTrusteeWithNameOsStr(name)
120    }
121}
122
123impl<'s> fmt::Debug for Trustee<'s> {
124    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
125        fmt.debug_map().finish()
126    }
127}
128
129#[cfg(test)]
130mod tests {
131    use super::*;
132
133    const TRUSTEE_NAMES: &[&'static str] = &["test_name", r"domain\username", "a_unicode_char: 💩"];
134
135    #[test]
136    fn create_and_retrieve_sid_trustee() {
137        use std::ops::Deref;
138
139        for (sid, _, _) in Sid::test_sids() {
140            let trustee: Trustee = sid.as_ref().into();
141
142            match trustee.get_subject() {
143                TrusteeSubject::Sid(s) => assert_eq!(s, sid.deref()),
144                _ => panic!("Expected to get back a TrusteeSubject::Sid"),
145            }
146        }
147    }
148
149    #[test]
150    fn create_and_retrieve_name_trustee() {
151        for name in TRUSTEE_NAMES {
152            let trustee: Trustee = OsStr::new(name).into();
153            let buffer = utilities::buf_from_os(OsStr::new(name));
154
155            match trustee.get_subject() {
156                TrusteeSubject::Name(n) => assert_eq!(n, buffer.as_slice()),
157                _ => panic!("Expected to get back a TrusteeSubject::Name"),
158            }
159
160            assert_eq!(wrappers::GetTrusteeName(&trustee), **name);
161        }
162    }
163}