1use std::{error, fmt, str::FromStr};
2
3use serde::{
4 Deserialize, Deserializer, Serialize, Serializer,
5 de::{self, SeqAccess, Visitor},
6 ser::SerializeSeq,
7};
8
9const REVISION: u8 = SidRevision::One as u8;
10const MIN_SUB_AUTHORITIES: usize = 1;
11const MAX_SUB_AUTHORITIES: usize = 15;
12const IDENTIFIER_AUTHORITY_MAX: u64 = (1 << 48) - 1;
13
14#[derive(Debug, Clone, PartialEq, Eq, Hash)]
19pub struct Sid {
20 identifier_authority: SidIdentifierAuthority,
21 sub_authorities: Box<[u32]>,
22}
23
24impl Sid {
25 pub fn new(
30 identifier_authority: impl Into<SidIdentifierAuthority>,
31 sub_authorities: impl IntoIterator<Item = u32>,
32 ) -> Result<Self, SidError> {
33 let identifier_authority = identifier_authority.into();
34 let identifier_authority_value = u64::from(identifier_authority);
35 if identifier_authority_value > IDENTIFIER_AUTHORITY_MAX {
36 return Err(SidError::IdentifierAuthority);
37 }
38 let sub_authorities = sub_authorities.into_iter().collect::<Box<[_]>>();
39 if !(MIN_SUB_AUTHORITIES..=MAX_SUB_AUTHORITIES).contains(&sub_authorities.len()) {
40 return Err(SidError::SubAuthorityCount(sub_authorities.len()));
41 }
42 Ok(Self {
43 identifier_authority,
44 sub_authorities,
45 })
46 }
47
48 pub const fn revision(&self) -> SidRevision {
50 SidRevision::One
51 }
52
53 pub const fn identifier_authority(&self) -> SidIdentifierAuthority {
55 self.identifier_authority
56 }
57
58 pub fn sub_authorities(&self) -> &[u32] {
60 &self.sub_authorities
61 }
62
63 pub fn from_bytes(bytes: &[u8]) -> Result<Self, SidError> {
65 if bytes.len() < 8 {
66 return Err(SidError::PacketLength);
67 }
68 if bytes[0] != REVISION {
69 return Err(SidError::Revision(bytes[0]));
70 }
71 let count = usize::from(bytes[1]);
72 if !(MIN_SUB_AUTHORITIES..=MAX_SUB_AUTHORITIES).contains(&count) {
73 return Err(SidError::SubAuthorityCount(count));
74 }
75 let expected = 8 + count * 4;
76 if bytes.len() != expected {
77 return Err(SidError::PacketLength);
78 }
79
80 let mut identifier_authority_bytes = [0; 8];
81 identifier_authority_bytes[2..].copy_from_slice(&bytes[2..8]);
82 let identifier_authority = u64::from_be_bytes(identifier_authority_bytes);
83 let sub_authorities = bytes[8..]
84 .as_chunks::<4>()
85 .0
86 .iter()
87 .copied()
88 .map(u32::from_le_bytes);
89 Self::new(identifier_authority, sub_authorities)
90 }
91
92 pub fn to_bytes(&self) -> Vec<u8> {
94 let mut bytes = Vec::with_capacity(8 + self.sub_authorities.len() * 4);
95 bytes.push(REVISION);
96 bytes.push(u8::try_from(self.sub_authorities.len()).unwrap());
97 bytes.extend_from_slice(&u64::from(self.identifier_authority).to_be_bytes()[2..]);
98 for sub_authority in &self.sub_authorities {
99 bytes.extend_from_slice(&sub_authority.to_le_bytes());
100 }
101 bytes
102 }
103
104 fn identifier_authority_bytes(&self) -> [u8; 6] {
105 u64::from(self.identifier_authority).to_be_bytes()[2..]
106 .try_into()
107 .unwrap()
108 }
109}
110
111impl TryFrom<&[u8]> for Sid {
112 type Error = SidError;
113
114 fn try_from(value: &[u8]) -> Result<Self, Self::Error> {
115 Self::from_bytes(value)
116 }
117}
118
119impl fmt::Display for Sid {
120 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
121 write!(f, "S-{REVISION}-")?;
122 let identifier_authority = u64::from(self.identifier_authority);
123 if identifier_authority < (1 << 32) {
124 write!(f, "{identifier_authority}")?;
125 } else {
126 write!(f, "0x{identifier_authority:012X}")?;
127 }
128 for sub_authority in &self.sub_authorities {
129 write!(f, "-{sub_authority}")?;
130 }
131 Ok(())
132 }
133}
134
135#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
137#[repr(u8)]
138pub enum SidRevision {
139 One = 1,
141}
142
143impl Serialize for SidRevision {
144 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
145 where
146 S: Serializer,
147 {
148 serializer.serialize_u8(*self as u8)
149 }
150}
151
152impl<'de> Deserialize<'de> for SidRevision {
153 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
154 where
155 D: Deserializer<'de>,
156 {
157 match u8::deserialize(deserializer)? {
158 REVISION => Ok(Self::One),
159 revision => Err(de::Error::custom(SidError::Revision(revision))),
160 }
161 }
162}
163
164#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
166#[non_exhaustive]
167pub enum SidIdentifierAuthority {
168 Null,
170 World,
172 Local,
174 Creator,
176 NonUnique,
178 Nt,
180 ResourceManager,
182 AppPackage,
184 MandatoryLabel,
186 ScopedPolicy,
188 Authentication,
190 ProcessTrust,
192 Unknown(u64),
194}
195
196impl From<u64> for SidIdentifierAuthority {
197 fn from(value: u64) -> Self {
198 match value {
199 0 => Self::Null,
200 1 => Self::World,
201 2 => Self::Local,
202 3 => Self::Creator,
203 4 => Self::NonUnique,
204 5 => Self::Nt,
205 9 => Self::ResourceManager,
206 15 => Self::AppPackage,
207 16 => Self::MandatoryLabel,
208 17 => Self::ScopedPolicy,
209 18 => Self::Authentication,
210 19 => Self::ProcessTrust,
211 value => Self::Unknown(value),
212 }
213 }
214}
215
216impl From<SidIdentifierAuthority> for u64 {
217 fn from(authority: SidIdentifierAuthority) -> Self {
218 match authority {
219 SidIdentifierAuthority::Null => 0,
220 SidIdentifierAuthority::World => 1,
221 SidIdentifierAuthority::Local => 2,
222 SidIdentifierAuthority::Creator => 3,
223 SidIdentifierAuthority::NonUnique => 4,
224 SidIdentifierAuthority::Nt => 5,
225 SidIdentifierAuthority::ResourceManager => 9,
226 SidIdentifierAuthority::AppPackage => 15,
227 SidIdentifierAuthority::MandatoryLabel => 16,
228 SidIdentifierAuthority::ScopedPolicy => 17,
229 SidIdentifierAuthority::Authentication => 18,
230 SidIdentifierAuthority::ProcessTrust => 19,
231 SidIdentifierAuthority::Unknown(value) => value,
232 }
233 }
234}
235
236impl Serialize for SidIdentifierAuthority {
237 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
238 where
239 S: Serializer,
240 {
241 serializer.serialize_u64((*self).into())
242 }
243}
244
245impl<'de> Deserialize<'de> for SidIdentifierAuthority {
246 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
247 where
248 D: Deserializer<'de>,
249 {
250 Ok(u64::deserialize(deserializer)?.into())
251 }
252}
253
254#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
267#[non_exhaustive]
268pub enum WellKnownSid {
269 Null,
271 Everyone,
273 Local,
275 ConsoleLogon,
277 CreatorOwner,
279 CreatorGroup,
281 OwnerRights,
283 Dialup,
285 Network,
287 Batch,
289 Interactive,
291 Service,
293 Anonymous,
295 PrincipalSelf,
297 AuthenticatedUsers,
299 RestrictedCode,
301 RemoteInteractiveLogon,
303 ThisOrganization,
305 LocalSystem,
307 LocalService,
309 NetworkService,
311 LocalAccount,
313 LocalAccountAdministrator,
315 BuiltinAdministrators,
317 BuiltinUsers,
319 BuiltinGuests,
321 BuiltinPowerUsers,
323 BuiltinBackupOperators,
325 BuiltinRemoteDesktopUsers,
327 BuiltinRemoteManagementUsers,
329 AllApplicationPackages,
331 AllRestrictedApplicationPackages,
333 UntrustedLabel,
335 LowLabel,
337 MediumLabel,
339 MediumPlusLabel,
341 HighLabel,
343 SystemLabel,
345}
346
347impl WellKnownSid {
348 const fn parts(self) -> (SidIdentifierAuthority, &'static [u32]) {
350 use SidIdentifierAuthority::{AppPackage, Creator, Local, MandatoryLabel, Nt, Null, World};
351 match self {
352 Self::Null => (Null, &[0]),
353 Self::Everyone => (World, &[0]),
354 Self::Local => (Local, &[0]),
355 Self::ConsoleLogon => (Local, &[1]),
356 Self::CreatorOwner => (Creator, &[0]),
357 Self::CreatorGroup => (Creator, &[1]),
358 Self::OwnerRights => (Creator, &[4]),
359 Self::Dialup => (Nt, &[1]),
360 Self::Network => (Nt, &[2]),
361 Self::Batch => (Nt, &[3]),
362 Self::Interactive => (Nt, &[4]),
363 Self::Service => (Nt, &[6]),
364 Self::Anonymous => (Nt, &[7]),
365 Self::PrincipalSelf => (Nt, &[10]),
366 Self::AuthenticatedUsers => (Nt, &[11]),
367 Self::RestrictedCode => (Nt, &[12]),
368 Self::RemoteInteractiveLogon => (Nt, &[14]),
369 Self::ThisOrganization => (Nt, &[15]),
370 Self::LocalSystem => (Nt, &[18]),
371 Self::LocalService => (Nt, &[19]),
372 Self::NetworkService => (Nt, &[20]),
373 Self::LocalAccount => (Nt, &[113]),
374 Self::LocalAccountAdministrator => (Nt, &[114]),
375 Self::BuiltinAdministrators => (Nt, &[32, 544]),
376 Self::BuiltinUsers => (Nt, &[32, 545]),
377 Self::BuiltinGuests => (Nt, &[32, 546]),
378 Self::BuiltinPowerUsers => (Nt, &[32, 547]),
379 Self::BuiltinBackupOperators => (Nt, &[32, 551]),
380 Self::BuiltinRemoteDesktopUsers => (Nt, &[32, 555]),
381 Self::BuiltinRemoteManagementUsers => (Nt, &[32, 580]),
382 Self::AllApplicationPackages => (AppPackage, &[2, 1]),
383 Self::AllRestrictedApplicationPackages => (AppPackage, &[2, 2]),
384 Self::UntrustedLabel => (MandatoryLabel, &[0]),
385 Self::LowLabel => (MandatoryLabel, &[4096]),
386 Self::MediumLabel => (MandatoryLabel, &[8192]),
387 Self::MediumPlusLabel => (MandatoryLabel, &[8448]),
388 Self::HighLabel => (MandatoryLabel, &[12288]),
389 Self::SystemLabel => (MandatoryLabel, &[16384]),
390 }
391 }
392}
393
394impl From<WellKnownSid> for Sid {
395 fn from(value: WellKnownSid) -> Self {
396 let (identifier_authority, sub_authorities) = value.parts();
397 Self {
398 identifier_authority,
399 sub_authorities: sub_authorities.into(),
400 }
401 }
402}
403
404impl FromStr for Sid {
405 type Err = SidError;
406
407 fn from_str(value: &str) -> Result<Self, Self::Err> {
408 let mut parts = value.split('-');
409 if parts.next() != Some("S") || parts.next() != Some("1") {
410 return Err(SidError::StringSyntax);
411 }
412 let authority = parts.next().ok_or(SidError::StringSyntax)?;
413 let identifier_authority = if let Some(hex) = authority.strip_prefix("0x") {
414 if hex.len() != 12 || !hex.bytes().all(|byte| byte.is_ascii_hexdigit()) {
415 return Err(SidError::StringSyntax);
416 }
417 let authority = u64::from_str_radix(hex, 16).map_err(|_| SidError::StringSyntax)?;
418 if authority < (1 << 32) {
419 return Err(SidError::StringSyntax);
420 }
421 authority
422 } else {
423 if authority.is_empty()
424 || (authority.len() > 1 && authority.starts_with('0'))
425 || !authority.bytes().all(|byte| byte.is_ascii_digit())
426 {
427 return Err(SidError::StringSyntax);
428 }
429 let authority = authority
430 .parse::<u64>()
431 .map_err(|_| SidError::IdentifierAuthority)?;
432 if authority >= (1 << 32) {
433 return Err(SidError::StringSyntax);
434 }
435 authority
436 };
437
438 let sub_authorities = parts
439 .map(|part| {
440 if part.is_empty()
441 || (part.len() > 1 && part.starts_with('0'))
442 || !part.bytes().all(|byte| byte.is_ascii_digit())
443 {
444 return Err(SidError::StringSyntax);
445 }
446 part.parse::<u32>().map_err(|_| SidError::StringSyntax)
447 })
448 .collect::<Result<Vec<_>, _>>()?;
449 Self::new(identifier_authority, sub_authorities)
450 }
451}
452
453impl Serialize for Sid {
454 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
455 where
456 S: Serializer,
457 {
458 let mut seq = serializer.serialize_seq(Some(3 + self.sub_authorities.len()))?;
459 seq.serialize_element(&REVISION)?;
460 seq.serialize_element(&u8::try_from(self.sub_authorities.len()).unwrap())?;
461 seq.serialize_element(&self.identifier_authority_bytes())?;
462 for sub_authority in &self.sub_authorities {
463 seq.serialize_element(sub_authority)?;
464 }
465 seq.end()
466 }
467}
468
469impl<'de> Deserialize<'de> for Sid {
470 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
471 where
472 D: Deserializer<'de>,
473 {
474 struct SidVisitor;
475
476 impl<'de> Visitor<'de> for SidVisitor {
477 type Value = Sid;
478
479 fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
480 formatter.write_str("a structurally encoded Windows SID")
481 }
482
483 fn visit_seq<A>(self, mut seq: A) -> Result<Self::Value, A::Error>
484 where
485 A: SeqAccess<'de>,
486 {
487 let revision: u8 = seq
488 .next_element()?
489 .ok_or_else(|| de::Error::invalid_length(0, &self))?;
490 if revision != REVISION {
491 return Err(de::Error::custom(SidError::Revision(revision)));
492 }
493 let count: u8 = seq
494 .next_element()?
495 .ok_or_else(|| de::Error::invalid_length(1, &self))?;
496 let count = usize::from(count);
497 if !(MIN_SUB_AUTHORITIES..=MAX_SUB_AUTHORITIES).contains(&count) {
498 return Err(de::Error::custom(SidError::SubAuthorityCount(count)));
499 }
500 let authority: [u8; 6] = seq
501 .next_element()?
502 .ok_or_else(|| de::Error::invalid_length(2, &self))?;
503 let mut authority_bytes = [0; 8];
504 authority_bytes[2..].copy_from_slice(&authority);
505 let authority = u64::from_be_bytes(authority_bytes);
506 let mut sub_authorities = Vec::with_capacity(count);
507 for index in 0..count {
508 sub_authorities.push(
509 seq.next_element()?
510 .ok_or_else(|| de::Error::invalid_length(3 + index, &self))?,
511 );
512 }
513 if seq.next_element::<de::IgnoredAny>()?.is_some() {
514 return Err(de::Error::invalid_length(4 + count, &self));
515 }
516 Sid::new(authority, sub_authorities).map_err(de::Error::custom)
517 }
518 }
519
520 deserializer.deserialize_seq(SidVisitor)
521 }
522}
523
524#[derive(Debug, Clone, PartialEq, Eq)]
526pub enum SidError {
527 Revision(u8),
529 SubAuthorityCount(usize),
531 IdentifierAuthority,
533 PacketLength,
535 StringSyntax,
537}
538
539impl fmt::Display for SidError {
540 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
541 match self {
542 Self::Revision(revision) => write!(f, "unsupported SID revision {revision}"),
543 Self::SubAuthorityCount(count) => {
544 write!(
545 f,
546 "SID must contain between 1 and 15 sub-authorities, got {count}"
547 )
548 }
549 Self::IdentifierAuthority => f.write_str("SID identifier authority exceeds 48 bits"),
550 Self::PacketLength => f.write_str("SID packet length does not match its structure"),
551 Self::StringSyntax => f.write_str("invalid canonical SID string"),
552 }
553 }
554}
555
556impl error::Error for SidError {}
557
558#[cfg(test)]
559mod tests {
560 use super::*;
561
562 #[test]
563 fn string_and_packet_round_trip() {
564 let sid: Sid = "S-1-5-21-287454020-2864434397".parse().unwrap();
565 let bytes = [
566 1, 3, 0, 0, 0, 0, 0, 5, 21, 0, 0, 0, 0x44, 0x33, 0x22, 0x11, 0xDD, 0xCC, 0xBB, 0xAA,
567 ];
568 assert_eq!(sid.to_bytes(), bytes);
569 assert_eq!(Sid::from_bytes(&bytes).unwrap(), sid);
570 assert_eq!(sid.to_string(), "S-1-5-21-287454020-2864434397");
571 assert_eq!(Sid::new(5, [32, 544]).unwrap().to_string(), "S-1-5-32-544");
572 }
573
574 #[test]
575 fn well_known_sids_have_their_canonical_values() {
576 const ALL: &[WellKnownSid] = &[
579 WellKnownSid::Null,
580 WellKnownSid::Everyone,
581 WellKnownSid::Local,
582 WellKnownSid::ConsoleLogon,
583 WellKnownSid::CreatorOwner,
584 WellKnownSid::CreatorGroup,
585 WellKnownSid::OwnerRights,
586 WellKnownSid::Dialup,
587 WellKnownSid::Network,
588 WellKnownSid::Batch,
589 WellKnownSid::Interactive,
590 WellKnownSid::Service,
591 WellKnownSid::Anonymous,
592 WellKnownSid::PrincipalSelf,
593 WellKnownSid::AuthenticatedUsers,
594 WellKnownSid::RestrictedCode,
595 WellKnownSid::RemoteInteractiveLogon,
596 WellKnownSid::ThisOrganization,
597 WellKnownSid::LocalSystem,
598 WellKnownSid::LocalService,
599 WellKnownSid::NetworkService,
600 WellKnownSid::LocalAccount,
601 WellKnownSid::LocalAccountAdministrator,
602 WellKnownSid::BuiltinAdministrators,
603 WellKnownSid::BuiltinUsers,
604 WellKnownSid::BuiltinGuests,
605 WellKnownSid::BuiltinPowerUsers,
606 WellKnownSid::BuiltinBackupOperators,
607 WellKnownSid::BuiltinRemoteDesktopUsers,
608 WellKnownSid::BuiltinRemoteManagementUsers,
609 WellKnownSid::AllApplicationPackages,
610 WellKnownSid::AllRestrictedApplicationPackages,
611 WellKnownSid::UntrustedLabel,
612 WellKnownSid::LowLabel,
613 WellKnownSid::MediumLabel,
614 WellKnownSid::MediumPlusLabel,
615 WellKnownSid::HighLabel,
616 WellKnownSid::SystemLabel,
617 ];
618
619 fn canonical(sid: WellKnownSid) -> &'static str {
620 match sid {
621 WellKnownSid::Null => "S-1-0-0",
622 WellKnownSid::Everyone => "S-1-1-0",
623 WellKnownSid::Local => "S-1-2-0",
624 WellKnownSid::ConsoleLogon => "S-1-2-1",
625 WellKnownSid::CreatorOwner => "S-1-3-0",
626 WellKnownSid::CreatorGroup => "S-1-3-1",
627 WellKnownSid::OwnerRights => "S-1-3-4",
628 WellKnownSid::Dialup => "S-1-5-1",
629 WellKnownSid::Network => "S-1-5-2",
630 WellKnownSid::Batch => "S-1-5-3",
631 WellKnownSid::Interactive => "S-1-5-4",
632 WellKnownSid::Service => "S-1-5-6",
633 WellKnownSid::Anonymous => "S-1-5-7",
634 WellKnownSid::PrincipalSelf => "S-1-5-10",
635 WellKnownSid::AuthenticatedUsers => "S-1-5-11",
636 WellKnownSid::RestrictedCode => "S-1-5-12",
637 WellKnownSid::RemoteInteractiveLogon => "S-1-5-14",
638 WellKnownSid::ThisOrganization => "S-1-5-15",
639 WellKnownSid::LocalSystem => "S-1-5-18",
640 WellKnownSid::LocalService => "S-1-5-19",
641 WellKnownSid::NetworkService => "S-1-5-20",
642 WellKnownSid::LocalAccount => "S-1-5-113",
643 WellKnownSid::LocalAccountAdministrator => "S-1-5-114",
644 WellKnownSid::BuiltinAdministrators => "S-1-5-32-544",
645 WellKnownSid::BuiltinUsers => "S-1-5-32-545",
646 WellKnownSid::BuiltinGuests => "S-1-5-32-546",
647 WellKnownSid::BuiltinPowerUsers => "S-1-5-32-547",
648 WellKnownSid::BuiltinBackupOperators => "S-1-5-32-551",
649 WellKnownSid::BuiltinRemoteDesktopUsers => "S-1-5-32-555",
650 WellKnownSid::BuiltinRemoteManagementUsers => "S-1-5-32-580",
651 WellKnownSid::AllApplicationPackages => "S-1-15-2-1",
652 WellKnownSid::AllRestrictedApplicationPackages => "S-1-15-2-2",
653 WellKnownSid::UntrustedLabel => "S-1-16-0",
654 WellKnownSid::LowLabel => "S-1-16-4096",
655 WellKnownSid::MediumLabel => "S-1-16-8192",
656 WellKnownSid::MediumPlusLabel => "S-1-16-8448",
657 WellKnownSid::HighLabel => "S-1-16-12288",
658 WellKnownSid::SystemLabel => "S-1-16-16384",
659 }
660 }
661
662 for well_known in ALL {
663 let expected = canonical(*well_known);
664 let sid = Sid::from(*well_known);
665 assert_eq!(sid.to_string(), expected, "{well_known:?}");
666 assert_eq!(expected.parse::<Sid>().unwrap(), sid, "{well_known:?}");
668 }
669 }
670
671 #[test]
672 fn high_identifier_authority_uses_hexadecimal() {
673 let sid: Sid = "S-1-0x010203040506-7".parse().unwrap();
674 assert_eq!(
675 sid.identifier_authority(),
676 SidIdentifierAuthority::Unknown(0x0102_0304_0506)
677 );
678 assert_eq!(sid.to_string(), "S-1-0x010203040506-7");
679 assert_eq!(&sid.to_bytes()[2..8], &[1, 2, 3, 4, 5, 6]);
680 }
681
682 #[test]
683 fn rejects_noncanonical_or_malformed_values() {
684 assert!("S-1-5".parse::<Sid>().is_err());
685 assert!("S-1-05-1".parse::<Sid>().is_err());
686 assert!("S-1-5-01".parse::<Sid>().is_err());
687 assert!("S-1-0x000000000005-1".parse::<Sid>().is_err());
688 assert!(Sid::from_bytes(&[2, 1, 0, 0, 0, 0, 0, 5, 0, 0, 0, 0]).is_err());
689 assert!(Sid::from_bytes(&[1, 1, 0, 0, 0, 0, 0, 5]).is_err());
690 }
691
692 #[test]
693 fn serde_is_structural() {
694 let sid: Sid = "S-1-5-32-544".parse().unwrap();
695 let encoded = postcard::to_stdvec(&sid).unwrap();
696 let expected =
697 postcard::to_stdvec(&(1u8, 2u8, [0u8, 0, 0, 0, 0, 5], 32u32, 544u32)).unwrap();
698 assert_eq!(encoded, [vec![5], expected].concat());
699 assert_eq!(postcard::from_bytes::<Sid>(&encoded).unwrap(), sid);
700 }
701
702 #[test]
703 fn revisions_and_authorities_use_native_values() {
704 assert_eq!(
705 Sid::new(SidIdentifierAuthority::Nt, [32])
706 .unwrap()
707 .revision(),
708 SidRevision::One
709 );
710 assert_eq!(SidIdentifierAuthority::from(5), SidIdentifierAuthority::Nt);
711 assert_eq!(
712 SidIdentifierAuthority::from(42),
713 SidIdentifierAuthority::Unknown(42)
714 );
715 assert_eq!(postcard::to_stdvec(&SidRevision::One).unwrap(), vec![1]);
716 assert!(postcard::from_bytes::<SidRevision>(&[2]).is_err());
717 assert_eq!(
718 postcard::to_stdvec(&SidIdentifierAuthority::Nt).unwrap(),
719 postcard::to_stdvec(&5u64).unwrap()
720 );
721 }
722}