Skip to main content

windows_permissions/structures/
sd.rs

1use crate::constants::SecurityInformation;
2use crate::{wrappers, Acl, LocalBox, Sid};
3use std::ffi::OsString;
4use std::fmt;
5use std::io;
6use std::str::FromStr;
7
8/// A Windows security descriptor.
9///
10/// This can only be accessed through a pointer, never constructed directly.
11///
12/// See [MSDN](https://docs.microsoft.com/en-us/windows/win32/api/winnt/ns-winnt-security_descriptor)
13/// for details.
14#[repr(C)]
15pub struct SecurityDescriptor {
16    _opaque: [u8; 0],
17}
18
19impl Drop for SecurityDescriptor {
20    fn drop(&mut self) {
21        unreachable!("SecurityDescriptor should only be borrowed, not owned")
22    }
23}
24
25impl SecurityDescriptor {
26    /// Get the Security Descriptor Definition Language (SDDL) string
27    /// corresponding to this `SecurityDescriptor`
28    ///
29    /// This function attempts to get the entire SDDL string using
30    /// `SecurityInformation::all()`. To get a portion of the SDDL, use
31    /// `wrappers::ConvertSecurityDescriptorToStringSecurityDescriptor`
32    /// directly.
33    pub fn as_sddl(&self) -> io::Result<OsString> {
34        wrappers::ConvertSecurityDescriptorToStringSecurityDescriptor(
35            self,
36            SecurityInformation::all(),
37        )
38    }
39
40    /// Get the owner SID if it exists
41    ///
42    /// ```
43    /// use windows_permissions::{LocalBox, SecurityDescriptor, Sid};
44    ///
45    /// let sd1: LocalBox<SecurityDescriptor> = "O:S-1-5-10-20".parse().unwrap();
46    /// let sd2: LocalBox<SecurityDescriptor> = "G:S-1-5-10-20".parse().unwrap();
47    ///
48    /// assert_eq!(sd1.owner().unwrap(),
49    ///     &*Sid::new([0, 0, 0, 0, 0, 5], &[10, 20]).unwrap());
50    /// assert_eq!(sd2.owner(), None);
51    /// ```
52    pub fn owner(&self) -> Option<&Sid> {
53        wrappers::GetSecurityDescriptorOwner(self)
54            .expect("Valid SecurityDescriptor failed to get owner")
55    }
56
57    /// Get the group SID if it exists
58    ///
59    /// ```
60    /// use windows_permissions::{LocalBox, SecurityDescriptor, Sid};
61    ///
62    /// let sd1: LocalBox<SecurityDescriptor> = "G:S-1-5-10-20".parse().unwrap();
63    /// let sd2: LocalBox<SecurityDescriptor> = "O:S-1-5-10-20".parse().unwrap();
64    ///
65    /// assert_eq!(sd1.group().unwrap(),
66    ///     &*Sid::new([0, 0, 0, 0, 0, 5], &[10, 20]).unwrap());
67    /// assert_eq!(sd2.group(), None);
68    /// ```
69    pub fn group(&self) -> Option<&Sid> {
70        wrappers::GetSecurityDescriptorGroup(self)
71            .expect("Valid SecurityDescriptor failed to get group")
72    }
73
74    /// Get the DACL if it exists
75    pub fn dacl(&self) -> Option<&Acl> {
76        wrappers::GetSecurityDescriptorDacl(self)
77            .expect("Valid SecurityDescriptor failed to get dacl")
78    }
79
80    /// Get the SACL if it exists
81    pub fn sacl(&self) -> Option<&Acl> {
82        wrappers::GetSecurityDescriptorSacl(self)
83            .expect("Valid SecurityDescriptor failed to get sacl")
84    }
85}
86
87impl fmt::Debug for SecurityDescriptor {
88    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
89        fmt.debug_map()
90            .entry(&"owner", &self.owner())
91            .entry(&"group", &self.group())
92            .entry(&"sddl", &self.as_sddl().unwrap())
93            .finish()
94    }
95}
96
97impl FromStr for LocalBox<SecurityDescriptor> {
98    type Err = io::Error;
99
100    fn from_str(s: &str) -> Result<Self, Self::Err> {
101        wrappers::ConvertStringSecurityDescriptorToSecurityDescriptor(s)
102    }
103}
104
105#[cfg(test)]
106mod test {
107    use super::*;
108    use crate::LocalBox;
109    use std::ffi::OsStr;
110    use std::ops::Deref;
111
112    static SDDL_TEST_CASES: &[(&str, &str, &str)] = &[
113        ("", "", ""),
114        ("O:AOG:SY", "AO", "SY"),
115        ("O:SU", "SU", ""),
116        ("G:SI", "", "SI"),
117        ("O:AOG:SYD:S:", "AO", "SY"),
118    ];
119
120    fn assert_option_eq(lhs: Option<&Sid>, rhs: Option<&LocalBox<Sid>>) {
121        match (lhs, rhs) {
122            (None, None) => (),
123            (Some(_), None) => panic!("Assertion failed: {:?} == {:?}", lhs, rhs),
124            (None, Some(_)) => panic!("Assertion failed: {:?} == {:?}", lhs, rhs),
125            (Some(l), Some(r)) => assert_eq!(l, r.deref()),
126        }
127    }
128
129    fn sddl_test_cases(
130    ) -> impl Iterator<Item = (String, Option<LocalBox<Sid>>, Option<LocalBox<Sid>>)> {
131        let parse_if_there = |s: &str| {
132            if s.is_empty() {
133                None
134            } else {
135                Some(s.parse().unwrap())
136            }
137        };
138
139        SDDL_TEST_CASES.iter().map(move |(sddl, own, grp)| {
140            (sddl.to_string(), parse_if_there(own), parse_if_there(grp))
141        })
142    }
143
144    #[test]
145    fn sddl_get_sids() -> io::Result<()> {
146        for (sddl, owner, group) in sddl_test_cases() {
147            let sd: LocalBox<SecurityDescriptor> = sddl.parse()?;
148
149            assert_option_eq(sd.owner(), owner.as_ref());
150            assert_option_eq(sd.group(), group.as_ref());
151        }
152
153        Ok(())
154    }
155
156    #[test]
157    fn sddl_round_trip() -> io::Result<()> {
158        for (sddl, _, _) in sddl_test_cases() {
159            let sd: LocalBox<SecurityDescriptor> = sddl.parse()?;
160            let sddl2 = sd.as_sddl()?;
161
162            assert_eq!(OsStr::new(&sddl), &sddl2);
163        }
164
165        Ok(())
166    }
167
168    #[test]
169    fn sddl_missing_acls() -> io::Result<()> {
170        let sd: LocalBox<SecurityDescriptor> = "O:LAG:AO".parse()?;
171        assert!(sd.dacl().is_none());
172        assert!(sd.sacl().is_none());
173
174        let sd: LocalBox<SecurityDescriptor> = "O:LAG:AOD:".parse()?;
175        assert!(sd.dacl().is_some());
176        assert!(sd.sacl().is_none());
177
178        let sd: LocalBox<SecurityDescriptor> = "O:LAG:AOS:".parse()?;
179        assert!(sd.dacl().is_none());
180        assert!(sd.sacl().is_some());
181
182        let sd: LocalBox<SecurityDescriptor> = "O:LAG:AOD:S:".parse()?;
183        assert!(sd.dacl().is_some());
184        assert!(sd.sacl().is_some());
185
186        Ok(())
187    }
188}