win_sid_core/
lib.rs

1#![forbid(unsafe_code)]
2
3#[cfg(test)]
4mod tests;
5mod maybe_heap;
6
7use byteorder::{BigEndian, ByteOrder};
8use nom::{
9    branch::alt,
10    bytes::complete::{tag, take},
11    character::complete::{digit1, hex_digit1},
12    combinator::{map_res, recognize},
13    multi::{many0, many_m_n},
14    number::complete::le_u32,
15    Finish, IResult,
16};
17#[cfg(feature = "serde")]
18use serde::{de::Error, Deserialize, Deserializer, Serialize, Serializer};
19use std::{
20    fmt::{Debug, Display, Write}, hash::Hash, str::FromStr
21};
22use thiserror::Error;
23use const_for::const_for;
24use maybe_heap::MaybeHeap;
25
26fn use_parse_str<T>(parser_result: IResult<&str, T>) -> Result<T, SecurityIdentifierError> {
27    let (remainder, value) = parser_result.finish()?;
28    if !remainder.is_empty() {
29        Err(SecurityIdentifierError::UnexpectedContent(remainder.to_owned()))
30    } else {
31        Ok(value)
32    }
33}
34
35/// A type representing the first value after the SID version.
36/// 
37/// The value is a single 48 bit integer.  Almost all SIDs encoutered "in the wild" will be less than u32.
38/// 
39/// # Panics
40/// 
41/// Converting to u64 is infallible, however, converting to u32 may panic if the value exceeds 2^32.
42#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone, Hash)]
43pub struct IdentifierAuthority([u8; 6]);
44
45impl IdentifierAuthority {
46    fn parse_str(input: &str) -> IResult<&str, Self> {
47        let mut identifier_authority = [0u8; 6];
48        let (input, _) = tag("-")(input)?;
49        let (input, value) = alt((hex_u64, dec_u64))(input)?;
50        BigEndian::write_u48(&mut identifier_authority, value);
51        Ok((input, Self(identifier_authority)))
52    }
53}
54
55impl From<u32> for IdentifierAuthority {
56    fn from(value: u32) -> Self {
57        let mut identifier_authority = [0u8; 6];
58        BigEndian::write_u48(&mut identifier_authority, value as u64);
59        Self(identifier_authority)
60    }
61}
62
63impl From<IdentifierAuthority> for u64 {
64    fn from(value: IdentifierAuthority) -> Self {
65        BigEndian::read_u48(&value.0)
66    }
67}
68
69impl Display for IdentifierAuthority {
70    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
71        if self.0[0] == 0x00 && self.0[1] == 0x00 {
72            f.write_fmt(format_args!("{}", BigEndian::read_u32(&self.0[2..6])))?;
73        } else {
74            f.write_fmt(format_args!("{:#X}", BigEndian::read_u48(&self.0)))?;
75        }
76        Ok(())
77    }
78}
79
80impl FromStr for IdentifierAuthority {
81    type Err = SecurityIdentifierError;
82
83    fn from_str(input: &str) -> Result<Self, Self::Err> {
84        use_parse_str(Self::parse_str(input))
85    }
86}
87
88const COMMON_SIZE: usize = 6;
89
90/// Core type representing Windows security identifiers ("SID"s).  Type represents version one SIDs, which consist of a single 48 bit identifier authority, followed by up to 256 sub-authorities.
91#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone, Hash)]
92pub struct SecurityIdentifier {
93    identifier_authority: IdentifierAuthority,
94    sub_authority: MaybeHeap<COMMON_SIZE>,
95}
96
97impl SecurityIdentifier {
98    /// Constructs a new SID manually.
99    /// 
100    /// Version number is hard-coded to one, as no other version presently exists.
101    /// 
102    /// # Panics
103    /// 
104    /// Will panic if an attempt is made to construct a SID with more than 256 sub-authorities.
105    pub fn new(identifier_authority: impl Into<IdentifierAuthority>, sub_authority: &[u32]) -> Self {
106        if sub_authority.len() > 256 {
107            panic!("SIDs do not support more than 256 sub-authorities.  An attempt was made to construct a SID with {} sub-authorities", sub_authority.len())
108        }
109        Self {
110            identifier_authority: identifier_authority.into(),
111            sub_authority: sub_authority.to_vec().into(),
112        }
113    }
114
115    /// Constructs a new SID manually (const version)
116    /// 
117    /// Version number is hard-coded to one, as no other version presently exists.  See the sid macro for a friendlier adapter to this function.
118    /// 
119    /// # Panics
120    /// 
121    /// Will panic if an attempt is made to construct a SID with more than 6 sub-authorities.
122    pub const fn new_const<const N: usize>(identifier_authority: u64, sub_authority: [u32; N]) -> Self {
123        let mut stack_sub_authorities = [0u32; COMMON_SIZE];
124        assert!(N <= COMMON_SIZE);
125        const_for!(i in 0..COMMON_SIZE => {
126            if N > i {
127                stack_sub_authorities[i] = sub_authority[i];
128            }
129        });
130        Self {
131            identifier_authority: IdentifierAuthority([
132                (identifier_authority >> 40) as u8,
133                (identifier_authority >> 32) as u8,
134                (identifier_authority >> 24) as u8,
135                (identifier_authority >> 16) as u8,
136                (identifier_authority >> 8) as u8,
137                identifier_authority as u8
138            ]),
139            sub_authority: MaybeHeap::Stack(stack_sub_authorities, N),
140        }
141    }
142
143    /// Reads a SID from a slice of bytes.
144    /// 
145    /// SID must be in binary format - for text SIDs, first parse into a string.
146    pub fn from_bytes(input: &[u8]) -> Result<Self, SecurityIdentifierError> {
147        let (remainder, sid) = parse_sid_bytes(input).finish()?;
148        if !remainder.is_empty() {
149            Err(SecurityIdentifierError::UnexpectedContent(format!("{:?}", remainder)))
150        } else {
151            Ok(sid)
152        }
153    }
154
155    /// Writes a SID in binary format and returns a Vec containing the binary representation.
156    pub fn to_bytes(&self) -> Vec<u8> {
157        let mut result = Vec::with_capacity(8 + (self.sub_authority.as_slice().len() * 4));
158        result.push(1);
159        result.push(self.sub_authority.as_slice().len() as u8);
160        for byte in self.identifier_authority.0 {
161            result.push(byte)
162        }
163        for sub_authority in self.sub_authority.as_slice() {
164            for byte in sub_authority.to_le_bytes() {
165                result.push(byte);
166            }
167        }
168        result
169    }
170
171    /// Constructs an LDAP predicate that represents the objectSID attribute being equal to this SID.
172    pub fn to_ldap_predicate(&self) -> String {
173        let bytes = self.to_bytes();
174        // 12 for predicate fixed text, 3 for each byte encoded as hex and prefixed with \
175        let mut predicate = String::with_capacity(12 + (bytes.len() * 3));
176        let _ = write!(predicate, "(objectSID=");
177        for byte in bytes {
178            let _ = write!(predicate, "\\{:02x}", byte);
179        }
180        let _ = write!(predicate, ")");
181        predicate
182    }
183
184    /// Retrieves the last sub-authority, if there are any.  This is commonly referred to as the "resource identifier" or RID.
185    pub fn get_resource_identifier(&self) -> Option<&u32> {
186        self.sub_authority.as_slice().last()
187    }
188
189    /// Retrieves the mandatory identifier authority
190    pub fn get_identifier_authority(&self) -> &IdentifierAuthority {
191        &self.identifier_authority
192    }
193
194    /// Retrieves sub-authorities
195    pub fn get_identifier_sub_authority(&self) -> &[u32] {
196        self.sub_authority.as_slice()
197    }
198
199    fn parse_str(input: &str) -> IResult<&str, Self> {
200        let (input, _) = tag::<_, _, nom::error::Error<_>>("S-1")(input)?;
201
202        let (input, identifier_authority) = IdentifierAuthority::parse_str(input)?;
203        let (input, sub_authority) = many0(sid_segment)(input)?;
204
205        Ok((
206            input,
207            Self {
208                identifier_authority,
209                sub_authority : sub_authority.into(),
210            },
211        ))
212    }
213}
214
215impl Display for SecurityIdentifier {
216    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
217        f.write_fmt(format_args!("S-1-{}", self.identifier_authority))?;
218        for sub_authority in self.sub_authority.as_slice() {
219            f.write_fmt(format_args!("-{}", sub_authority))?;
220        }
221        Ok(())
222    }
223}
224
225impl FromStr for SecurityIdentifier {
226    type Err = SecurityIdentifierError;
227
228    fn from_str(input: &str) -> Result<Self, Self::Err> {
229        use_parse_str(Self::parse_str(input))
230    }
231}
232
233#[cfg(feature = "serde")]
234impl<'de> Deserialize<'de> for SecurityIdentifier {
235    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
236    where
237        D: Deserializer<'de>,
238    {
239        SecurityIdentifier::from_str(&String::deserialize(deserializer)?).map_err(|err| D::Error::custom(err.to_string()))
240    }
241}
242
243#[cfg(feature = "serde")]
244impl Serialize for SecurityIdentifier {
245    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
246    where
247        S: Serializer,
248    {
249        self.to_string().serialize(serializer)
250    }
251}
252
253fn dec_u64(input: &str) -> IResult<&str, u64> {
254    map_res(recognize(digit1), str::parse)(input)
255}
256
257fn hex_u64(input: &str) -> IResult<&str, u64> {
258    let (input, _) = tag("0x")(input)?;
259    map_res(recognize(hex_digit1), |x| u64::from_str_radix(x, 16))(input)
260}
261
262fn dec_u32(input: &str) -> IResult<&str, u32> {
263    map_res(recognize(digit1), str::parse)(input)
264}
265
266fn hex_u32(input: &str) -> IResult<&str, u32> {
267    let (input, _) = tag("0x")(input)?;
268    map_res(recognize(hex_digit1), |x| u32::from_str_radix(x, 16))(input)
269}
270
271fn sid_segment(input: &str) -> IResult<&str, u32> {
272    let (input, _) = tag("-")(input)?;
273    let (input, value) = alt((hex_u32, dec_u32))(input)?;
274    Ok((input, value))
275}
276
277fn parse_sid_bytes(input: &[u8]) -> IResult<&[u8], SecurityIdentifier> {
278    let (input, _) = tag([1])(input)?;
279
280    let (input, sub_authority_count) = nom::number::complete::u8(input)?;
281    let (input, identifier_authority) = take(6usize)(input)?;
282    let (input, sub_authority) = many_m_n(sub_authority_count as usize, sub_authority_count as usize, le_u32)(input)?;
283
284    Ok((
285        input,
286        SecurityIdentifier {
287            identifier_authority: IdentifierAuthority(identifier_authority.try_into().unwrap()),
288            sub_authority: sub_authority.into(),
289        },
290    ))
291}
292
293/// Represents all errors that may be encountered during either binary or string parsing of a SID.
294#[derive(Error, Debug)]
295pub enum SecurityIdentifierError {
296    /// Only version one SIDs are supported.  These are also the only SID version known to exist.
297    #[error("bad revision")]
298    BadRevision,
299
300    /// Generic parsing failure, such as premature ends.
301    #[error("parsing error: {0}")]
302    ParseError(String),
303
304    /// Additional or invalid content was found in the SID.
305    #[error("unexpected content: {0}")]
306    UnexpectedContent(String),
307}
308
309impl<E> From<nom::error::Error<E>> for SecurityIdentifierError
310where
311    E: Debug,
312{
313    fn from(value: nom::error::Error<E>) -> Self {
314        Self::ParseError(format!("{:?}: {:?}", value.code, value.input))
315    }
316}