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 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 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 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 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 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}