sddl/sid_info/
mod.rs

1use std::fmt::{Debug, Display};
2use std::mem;
3use std::str::FromStr;
4
5use binrw::{BinRead, BinWrite};
6use dfir_windows_types::constants::*;
7use dfir_windows_types::*;
8use getset::Getters;
9
10mod sid_alias;
11pub use sid_alias::*;
12
13mod sid_name_use;
14
15use serde::ser::SerializeStruct;
16use serde::Serialize;
17
18use crate::*;
19
20#[derive(Eq, PartialEq, Getters, Clone, Hash)]
21#[getset(get = "pub")]
22pub struct SidInfo {
23    sid: Sid,
24    alias: Option<SidAlias>,
25    well_known_name: Option<&'static str>,
26}
27
28impl From<Sid> for SidInfo {
29    fn from(sid: Sid) -> Self {
30        let alias = Self::sddl_alias(sid.identifier_authority(), sid.sub_authority());
31        let well_known_name = alias.map(|a| a.long_name());
32        Self {
33            sid,
34            alias,
35            well_known_name,
36        }
37    }
38}
39
40impl Display for SidInfo {
41    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
42        write!(f, "{}", self.sid)
43    }
44}
45
46impl Serialize for SidInfo {
47    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
48    where
49        S: serde::Serializer,
50    {
51        let mut ser = serializer.serialize_struct("SID", 3)?;
52        ser.serialize_field("sid", &serde_json::Value::String(self.sid().to_string()))?;
53        ser.serialize_field("alias", &self.alias())?;
54        ser.serialize_field(
55            "well-known-name",
56            &self
57                .well_known_name()
58                .map(|a| a.into())
59                .unwrap_or(serde_json::Value::Null),
60        )?;
61        ser.end()
62    }
63}
64
65impl RawSize for SidInfo {
66    fn raw_size(&self) -> u16 {
67        self.sid().len().try_into().unwrap()
68    }
69}
70
71impl BinRead for SidInfo {
72    type Args<'a> = ();
73
74    fn read_options<R: std::io::Read + std::io::Seek>(
75        reader: &mut R,
76        endian: binrw::Endian,
77        args: Self::Args<'_>,
78    ) -> binrw::BinResult<Self> {
79        Ok(Sid::read_options(reader, endian, args)?.into())
80    }
81}
82
83impl BinWrite for SidInfo {
84    type Args<'a> = ();
85
86    fn write_options<W: std::io::Write + std::io::Seek>(
87        &self,
88        writer: &mut W,
89        endian: binrw::Endian,
90        args: Self::Args<'_>,
91    ) -> binrw::BinResult<()> {
92        self.sid().write_options(writer, endian, args)
93    }
94}
95
96impl SidInfo {
97    pub fn new(revision: u8, identifier_authority: IdentifierAuthority, sub_authority: &[u32]) -> Self {
98        let sid = Sid::new(revision, identifier_authority, sub_authority);
99        let alias = Self::sddl_alias(&identifier_authority, sub_authority);
100        let well_known_name = alias.map(|a| a.long_name());
101        Self {
102            sid,
103            alias,
104            well_known_name,
105        }
106    }
107
108    pub fn new_with_domain(rid: u32, domain: &[u32]) -> Self {
109        let mut d = vec![21];
110        d.extend_from_slice(domain);
111        d.push(rid);
112        Self::new(1, SECURITY_NT_AUTHORITY, &d[..])
113    }
114
115    pub fn new_builtin(rid: u32) -> Self {
116        Self::new(1, SECURITY_NT_AUTHORITY, &[32, rid])
117    }
118
119    #[allow(clippy::len_without_is_empty)]
120    pub fn len(&self) -> usize {
121        mem::size_of::<u8>()
122            + mem::size_of::<u8>()
123            + mem::size_of::<IdentifierAuthority>()
124            + (self.sid().sub_authority().len() * mem::size_of::<u32>())
125    }
126
127    pub fn try_from_alias(alias: &str, domain_rid: Option<&[u32]>) -> Result<Self, crate::Error> {
128        match SidAlias::from_str(alias)? {
129            SidAlias::AA => Ok(Sid::new_builtin(579).into()),
130            SidAlias::AC => Ok(APPLICATION_PACKAGE_AUTHORITY.new_sid(1, &[2, 1]).into()),
131            SidAlias::AN => Ok(SECURITY_NT_AUTHORITY.new_sid(1, &[7]).into()),
132            SidAlias::AO => Ok(Sid::new_builtin(548).into()),
133            SidAlias::AP => Ok(domain_rid.new_domain_sid(525)?.into()),
134            SidAlias::AS => Ok(AUTHENTICATION_AUTHORITY.new_sid(1, &[1]).into()),
135            SidAlias::AU => Ok(SECURITY_NT_AUTHORITY.new_sid(1, &[11]).into()),
136            SidAlias::BA => Ok(Sid::new_builtin(544).into()),
137            SidAlias::BG => Ok(Sid::new_builtin(546).into()),
138            SidAlias::BO => Ok(Sid::new_builtin(551).into()),
139            SidAlias::BU => Ok(Sid::new_builtin(545).into()),
140            SidAlias::CA => Ok(domain_rid.new_domain_sid(517)?.into()),
141            SidAlias::CD => Ok(Sid::new_builtin(574).into()),
142            SidAlias::CG => Ok(SECURITY_CREATOR_SID_AUTHORITY.new_sid(1, &[1]).into()),
143            SidAlias::CN => Ok(domain_rid.new_domain_sid(522)?.into()),
144            SidAlias::CO => Ok(SECURITY_CREATOR_SID_AUTHORITY.new_sid(1, &[0]).into()),
145            SidAlias::CY => Ok(Sid::new_builtin(569).into()),
146            SidAlias::DA => Ok(domain_rid.new_domain_sid(512)?.into()),
147            SidAlias::DC => Ok(domain_rid.new_domain_sid(515)?.into()),
148            SidAlias::DD => Ok(domain_rid.new_domain_sid(516)?.into()),
149            SidAlias::DG => Ok(domain_rid.new_domain_sid(514)?.into()),
150            SidAlias::DU => Ok(domain_rid.new_domain_sid(513)?.into()),
151            SidAlias::EA => Ok(domain_rid.new_domain_sid(519)?.into()),
152            SidAlias::ED => Ok(SECURITY_NT_AUTHORITY.new_sid(1, &[9]).into()),
153            SidAlias::EK => Ok(domain_rid.new_domain_sid(527)?.into()),
154            SidAlias::ER => Ok(Sid::new_builtin(573).into()),
155            SidAlias::ES => Ok(Sid::new_builtin(576).into()),
156            SidAlias::HA => Ok(Sid::new_builtin(578).into()),
157            SidAlias::HI => Ok(MANDATORY_LABEL_AUTHORITY.new_sid(1, &[12288]).into()),
158            SidAlias::IS => Ok(Sid::new_builtin(568).into()),
159            SidAlias::IU => Ok(SECURITY_NT_AUTHORITY.new_sid(1, &[4]).into()),
160            SidAlias::KA => Ok(domain_rid.new_domain_sid(526)?.into()),
161            SidAlias::LA => Ok(domain_rid.new_domain_sid(500)?.into()),
162            SidAlias::LG => Ok(domain_rid.new_domain_sid(501)?.into()),
163            SidAlias::LS => Ok(SECURITY_NT_AUTHORITY.new_sid(1, &[19]).into()),
164            SidAlias::LU => Ok(Sid::new_builtin(559).into()),
165            SidAlias::LW => Ok(MANDATORY_LABEL_AUTHORITY.new_sid(1, &[4096]).into()),
166            SidAlias::ME => Ok(MANDATORY_LABEL_AUTHORITY.new_sid(1, &[8192]).into()),
167            SidAlias::MP => Ok(MANDATORY_LABEL_AUTHORITY.new_sid(1, &[8448]).into()),
168            SidAlias::MS => Ok(Sid::new_builtin(577).into()),
169            SidAlias::MU => Ok(Sid::new_builtin(558).into()),
170            SidAlias::NO => Ok(Sid::new_builtin(556).into()),
171            SidAlias::NS => Ok(SECURITY_NT_AUTHORITY.new_sid(1, &[20]).into()),
172            SidAlias::NU => Ok(SECURITY_NT_AUTHORITY.new_sid(1, &[2]).into()),
173            SidAlias::OW => Ok(SECURITY_CREATOR_SID_AUTHORITY.new_sid(1, &[4]).into()),
174            SidAlias::PA => Ok(domain_rid.new_domain_sid(520)?.into()),
175            SidAlias::PO => Ok(Sid::new_builtin(550).into()),
176            SidAlias::PS => Ok(SECURITY_NT_AUTHORITY.new_sid(1, &[10]).into()),
177            SidAlias::PU => Ok(Sid::new_builtin(547).into()),
178            SidAlias::RA => Ok(Sid::new_builtin(575).into()),
179            SidAlias::RC => Ok(SECURITY_NT_AUTHORITY.new_sid(1, &[12]).into()),
180            SidAlias::RD => Ok(Sid::new_builtin(555).into()),
181            SidAlias::RE => Ok(Sid::new_builtin(552).into()),
182            SidAlias::RM => Ok(Sid::new_builtin(580).into()),
183            SidAlias::RO => Ok(domain_rid.new_domain_sid(498)?.into()),
184            SidAlias::RS => Ok(domain_rid.new_domain_sid(553)?.into()),
185            SidAlias::RU => Ok(Sid::new_builtin(554).into()),
186            SidAlias::SA => Ok(domain_rid.new_domain_sid(518)?.into()),
187            SidAlias::SI => Ok(MANDATORY_LABEL_AUTHORITY.new_sid(1, &[16384]).into()),
188            SidAlias::SO => Ok(Sid::new_builtin(549).into()),
189            SidAlias::SS => Ok(AUTHENTICATION_AUTHORITY.new_sid(1, &[2]).into()),
190            SidAlias::SU => Ok(SECURITY_NT_AUTHORITY.new_sid(1, &[6]).into()),
191            SidAlias::SY => Ok(SECURITY_NT_AUTHORITY.new_sid(1, &[18]).into()),
192            SidAlias::UD => Ok(SECURITY_NT_AUTHORITY.new_sid(1, &[84, 0, 0, 0, 0, 0]).into()),
193            SidAlias::WD => Ok(SECURITY_WORLD_SID_AUTHORITY.new_sid(1, &[0]).into()),
194            SidAlias::WR => Ok(SECURITY_NT_AUTHORITY.new_sid(1, &[33]).into()),
195            SidAlias::HO => Ok(Sid::new_builtin(584).into()),
196            SidAlias::SH => Ok(Sid::new_builtin(585).into()),
197        }
198    }
199
200    pub fn sddl_alias(
201        identifier_authority: &IdentifierAuthority,
202        sub_authority: &[u32],
203    ) -> Option<SidAlias> {
204        match *identifier_authority {
205            SECURITY_WORLD_SID_AUTHORITY if sub_authority == [0] => Some(SDDL_EVERYONE),
206
207            // S-1-3-*
208            SECURITY_CREATOR_SID_AUTHORITY => match sub_authority {
209                [0] => Some(SDDL_CREATOR_OWNER),
210                [1] => Some(SDDL_CREATOR_GROUP),
211                [4] => Some(SDDL_OWNER_RIGHTS),
212                _ => None,
213            },
214
215            // S-1-5-*
216            SECURITY_NT_AUTHORITY => match sub_authority {
217                [7] => Some(SDDL_ANONYMOUS),
218                [11] => Some(SDDL_AUTHENTICATED_USERS),
219                [9] => Some(SDDL_ENTERPRISE_DOMAIN_CONTROLLERS),
220                [4] => Some(SDDL_INTERACTIVE),
221                [19] => Some(SDDL_LOCAL_SERVICE),
222                [20] => Some(SDDL_NETWORK_SERVICE),
223                [2] => Some(SDDL_NETWORK),
224                [10] => Some(SDDL_PERSONAL_SELF),
225                [12] => Some(SDDL_RESTRICTED_CODE),
226                [6] => Some(SDDL_SERVICE),
227                [18] => Some(SDDL_LOCAL_SYSTEM),
228                [33] => Some(SDDL_WRITE_RESTRICTED_CODE),
229                [84, 0, 0, 0, 0, 0] => Some(SDDL_USER_MODE_DRIVERS),
230                _ => {
231                    // map S-1-5-21-* to sddl_domain_alias()
232                    // map S-1-5-32-* to sddl_builtin_alias()
233                    sub_authority.first().and_then(|s0| match s0 {
234                        21 => Self::sddl_domain_alias(sub_authority),
235                        32 => Self::sddl_builtin_alias(sub_authority),
236                        _ => None,
237                    })
238                }
239            },
240
241            // S-1-15-*
242            APPLICATION_PACKAGE_AUTHORITY if sub_authority == [2, 1] => Some(SDDL_ALL_APP_PACKAGES),
243
244            MANDATORY_LABEL_AUTHORITY => match sub_authority {
245                [12288] => Some(SDDL_ML_HIGH),
246                [4096] => Some(SDDL_ML_LOW),
247                [8192] => Some(SDDL_ML_MEDIUM),
248                [8448] => Some(SDDL_ML_MEDIUM_PLUS),
249                [16384] => Some(SDDL_ML_SYSTEM),
250                _ => None,
251            },
252
253            // S-1-18-*
254            AUTHENTICATION_AUTHORITY => match sub_authority {
255                [1] => Some(SDDL_AUTHORITY_ASSERTED),
256                [2] => Some(SDDL_SERVICE_ASSERTED),
257                _ => None,
258            },
259            _ => None,
260        }
261    }
262
263    fn sddl_domain_alias(sub_authority: &[u32]) -> Option<SidAlias> {
264        assert_eq!(*sub_authority.first().unwrap(), 21);
265        if let Some(last) = sub_authority.last() {
266            match last {
267                525 => Some(SDDL_PROTECTED_USERS),
268                517 => Some(SDDL_CERT_SERV_ADMINISTRATORS),
269                522 => Some(SDDL_CLONEABLE_CONTROLLERS),
270                512 => Some(SDDL_DOMAIN_ADMINISTRATORS),
271                515 => Some(SDDL_DOMAIN_COMPUTERS),
272                516 => Some(SDDL_DOMAIN_DOMAIN_CONTROLLERS),
273                514 => Some(SDDL_DOMAIN_GUESTS),
274                513 => Some(SDDL_DOMAIN_USERS),
275                519 => Some(SDDL_ENTERPRISE_ADMINS),
276                527 => Some(SDDL_ENTERPRISE_KEY_ADMINS),
277                526 => Some(SDDL_KEY_ADMINS),
278                500 => Some(SDDL_LOCAL_ADMIN),
279                501 => Some(SDDL_LOCAL_GUEST),
280                520 => Some(SDDL_GROUP_POLICY_ADMINS),
281                498 => Some(SDDL_ENTERPRISE_RO_DCs),
282                553 => Some(SDDL_RAS_SERVERS),
283                518 => Some(SDDL_SCHEMA_ADMINISTRATORS),
284                _ => None,
285            }
286        } else {
287            None
288        }
289    }
290
291    fn sddl_builtin_alias(sub_authority: &[u32]) -> Option<SidAlias> {
292        assert_eq!(sub_authority.len(), 2);
293        assert_eq!(*sub_authority.first().unwrap(), 32);
294
295        if let Some(last) = sub_authority.last() {
296            match last {
297                579 => Some(SDDL_ACCESS_CONTROL_ASSISTANCE_OPS),
298                548 => Some(SDDL_ACCOUNT_OPERATORS),
299                544 => Some(SDDL_BUILTIN_ADMINISTRATORS),
300                546 => Some(SDDL_BUILTIN_GUESTS),
301                551 => Some(SDDL_BACKUP_OPERATORS),
302                545 => Some(SDDL_BUILTIN_USERS),
303                574 => Some(SDDL_CERTSVC_DCOM_ACCESS),
304                569 => Some(SDDL_CRYPTO_OPERATORS),
305                573 => Some(SDDL_EVENT_LOG_READERS),
306                576 => Some(SDDL_RDS_ENDPOINT_SERVERS),
307                578 => Some(SDDL_HYPER_V_ADMINS),
308                568 => Some(SDDL_IIS_USERS),
309                559 => Some(SDDL_PERFLOG_USERS),
310                577 => Some(SDDL_RDS_MANAGEMENT_SERVERS),
311                558 => Some(SDDL_PERFMON_USERS),
312                556 => Some(SDDL_NETWORK_CONFIGURATION_OPS),
313                550 => Some(SDDL_PRINTER_OPERATORS),
314                547 => Some(SDDL_POWER_USERS),
315                575 => Some(SDDL_RDS_REMOTE_ACCESS_SERVERS),
316                555 => Some(SDDL_REMOTE_DESKTOP),
317                552 => Some(SDDL_REPLICATOR),
318                580 => Some(SDDL_REMOTE_MANAGEMENT_USERS),
319                554 => Some(SDDL_ALIAS_PREW2KCOMPACC),
320                549 => Some(SDDL_SERVER_OPERATORS),
321                584 => Some(SDDL_USER_MODE_HARDWARE_OPERATORS),
322                585 => Some(SDDL_OPENSSH_USERS),
323                _ => None,
324            }
325        } else {
326            None
327        }
328    }
329}
330
331impl Debug for SidInfo {
332    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
333        write!(f, "{self}")
334    }
335}
336
337impl TryFrom<&str> for SidInfo {
338    type Error = crate::Error;
339
340    fn try_from(value: &str) -> Result<Self, Self::Error> {
341        match Sid::try_from(value) {
342            Ok(sid) => Ok(sid.into()),
343            Err(dfir_windows_types::Error::IllegalSidFormat(a, b)) => {
344                Err(crate::Error::IllegalSidFormat(a, b))
345            }
346            _ => panic!("unexpected error message"),
347        }
348    }
349}
350
351#[cfg(test)]
352mod tests {
353    use crate::*;
354    #[test]
355    fn test_all_aliases() {
356        let aliases = [
357            "AA", "AC", "AN", "AO", "AP", "AS", "AU", "BA", "BG", "BO", "BU", "CA", "CD", "CG",
358            "CN", "CO", "CY", "DA", "DC", "DD", "DG", "DU", "EA", "ED", "EK", "ER", "ES", "HA",
359            "HI", "IS", "IU", "KA", "LA", "LG", "LS", "LU", "LW", "ME", "MP", "MS", "MU", "NO",
360            "NS", "NU", "OW", "PA", "PO", "PS", "PU", "RA", "RC", "RD", "RE", "RM", "RO", "RS",
361            "RU", "SA", "SI", "SO", "SS", "SU", "SY", "UD", "WD", "WR",
362        ];
363        let domain = [2623811015, 3361044348, 30300820];
364        for alias in aliases {
365            let sid = SidInfo::try_from_alias(alias, Some(&domain)).unwrap();
366            assert_eq!(
367                sid.alias()
368                    .unwrap_or_else(|| panic!("missing alias for '{alias}'"))
369                    .short_name(),
370                alias
371            );
372        }
373    }
374}