1use std::str::FromStr;
4
5use binrw::prelude::*;
6
7use crate::binrw_util::prelude::*;
8
9#[binrw::binrw]
23#[derive(Debug, PartialEq, Eq, Clone)]
24#[brw(little)]
25pub struct SID {
26 #[bw(calc = 1)]
27 #[br(assert(revision == 1))]
28 revision: u8,
29 #[bw(try_calc = sub_authority.len().try_into())]
30 sub_authority_count: u8,
31 #[brw(big)] #[br(parse_with = read_u48)]
33 #[bw(write_with = write_u48)]
34 pub identifier_authority: u64,
35 #[br(count = sub_authority_count)]
36 pub sub_authority: Vec<u32>,
37}
38impl SID {
39 pub const MIN_SIZE: usize = std::mem::size_of::<u8>() + std::mem::size_of::<u8>() + 6; const PREFIX: &'static str = "S-1-";
46
47 pub const S_ADMINISTRATORS: &'static str = "S-1-5-32-544";
49 pub const S_LOCAL_SYSTEM: &'static str = "S-1-5-18";
51 pub const S_EVERYONE: &'static str = "S-1-1-0";
53}
54
55impl FromStr for SID {
56 type Err = &'static str;
57
58 fn from_str(s: &str) -> Result<Self, Self::Err> {
59 if !s.starts_with(Self::PREFIX) {
61 return Err("SID must start with S-1-");
62 }
63 let mut s = s[Self::PREFIX.len()..].split('-');
64 let identifier_authority = match s.next() {
66 Some("0x") => {
67 let p = u64::from_str_radix(
69 s.next().ok_or("Identifier authority format is incorrect")?,
70 16,
71 )
72 .map_err(|_| "Identifier authority format is incorrect")?;
73 if p >> 32 == 0 {
74 p
75 } else {
76 return Err("Identifier authority format is incorrect");
77 }
78 }
79 Some(x) => x
80 .parse()
81 .map_err(|_| "Identifier authority format is incorrect")?,
82 None => return Err("SID format is incorrect - missing authority"),
83 };
84 let sub_authority = s
86 .map(|x| x.parse().map_err(|_| "Sub-authority format is incorrect"))
87 .collect::<Result<_, _>>()?;
88 Ok(SID {
89 identifier_authority,
90 sub_authority,
91 })
92 }
93}
94
95impl std::fmt::Display for SID {
96 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
97 write!(f, "S-1-")?;
99 if self.identifier_authority >> 32 == 0 {
100 write!(f, "{}", self.identifier_authority)?;
101 } else {
102 write!(f, "0x{:x}", self.identifier_authority)?;
103 }
104 for sub_authority in &self.sub_authority {
105 write!(f, "-{sub_authority}")?;
106 }
107 Ok(())
108 }
109}
110
111#[cfg(test)]
112mod tests {
113 use super::*;
114 use smb_tests::*;
115
116 const SID_STRING: &str = "S-1-5-21-782712087-4182988437-2163400469-1002";
117
118 #[test]
119 fn test_sid_to_from_string() {
120 let sid_value: SID = SID {
121 identifier_authority: 5,
122 sub_authority: vec![21, 782712087, 4182988437, 2163400469, 1002],
123 };
124 assert_eq!(SID_STRING.parse::<SID>().unwrap(), sid_value);
125 assert_eq!(sid_value.to_string(), SID_STRING);
126
127 let invalid_sids = ["", "S-1", "S-1-", "S-1-2-", "S-1-4f4"];
128 for sid in invalid_sids {
129 assert!(sid.parse::<SID>().is_err())
130 }
131 }
132
133 test_binrw! {
134 SID: SID_STRING.parse::<SID>().unwrap()
135 => "010500000000000515000000173da72e955653f915dff280ea030000"
136 }
137}