#![forbid(unsafe_code)]
#[cfg(test)]
mod tests;
mod maybe_heap;
use byteorder::{BigEndian, ByteOrder};
use nom::{
branch::alt,
bytes::complete::{tag, take},
character::complete::{digit1, hex_digit1},
combinator::{map_res, recognize},
multi::{many0, many_m_n},
number::complete::le_u32,
Finish, IResult,
};
#[cfg(feature = "serde")]
use serde::{de::Error, Deserialize, Deserializer, Serialize, Serializer};
use std::{
fmt::{Debug, Display, Write}, hash::Hash, str::FromStr
};
use thiserror::Error;
use const_for::const_for;
use maybe_heap::MaybeHeap;
fn use_parse_str<T>(parser_result: IResult<&str, T>) -> Result<T, SecurityIdentifierError> {
let (remainder, value) = parser_result.finish()?;
if !remainder.is_empty() {
Err(SecurityIdentifierError::UnexpectedContent(remainder.to_owned()))
} else {
Ok(value)
}
}
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone, Hash)]
pub struct IdentifierAuthority([u8; 6]);
impl IdentifierAuthority {
fn parse_str(input: &str) -> IResult<&str, Self> {
let mut identifier_authority = [0u8; 6];
let (input, _) = tag("-")(input)?;
let (input, value) = alt((hex_u64, dec_u64))(input)?;
BigEndian::write_u48(&mut identifier_authority, value);
Ok((input, Self(identifier_authority)))
}
}
impl From<u32> for IdentifierAuthority {
fn from(value: u32) -> Self {
let mut identifier_authority = [0u8; 6];
BigEndian::write_u48(&mut identifier_authority, value as u64);
Self(identifier_authority)
}
}
impl From<IdentifierAuthority> for u64 {
fn from(value: IdentifierAuthority) -> Self {
BigEndian::read_u48(&value.0)
}
}
impl Display for IdentifierAuthority {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
if self.0[0] == 0x00 && self.0[1] == 0x00 {
f.write_fmt(format_args!("{}", BigEndian::read_u32(&self.0[2..6])))?;
} else {
f.write_fmt(format_args!("{:#X}", BigEndian::read_u48(&self.0)))?;
}
Ok(())
}
}
impl FromStr for IdentifierAuthority {
type Err = SecurityIdentifierError;
fn from_str(input: &str) -> Result<Self, Self::Err> {
use_parse_str(Self::parse_str(input))
}
}
const COMMON_SIZE: usize = 6;
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone, Hash)]
pub struct SecurityIdentifier {
identifier_authority: IdentifierAuthority,
sub_authority: MaybeHeap<COMMON_SIZE>,
}
impl SecurityIdentifier {
pub fn new(identifier_authority: impl Into<IdentifierAuthority>, sub_authority: &[u32]) -> Self {
if sub_authority.len() > 256 {
panic!("SIDs do not support more than 256 sub-authorities. An attempt was made to construct a SID with {} sub-authorities", sub_authority.len())
}
Self {
identifier_authority: identifier_authority.into(),
sub_authority: sub_authority.to_vec().into(),
}
}
pub const fn new_const<const N: usize>(identifier_authority: u64, sub_authority: [u32; N]) -> Self {
let mut stack_sub_authorities = [0u32; COMMON_SIZE];
assert!(N <= COMMON_SIZE);
const_for!(i in 0..COMMON_SIZE => {
if N > i {
stack_sub_authorities[i] = sub_authority[i];
}
});
Self {
identifier_authority: IdentifierAuthority([
(identifier_authority >> 40) as u8,
(identifier_authority >> 32) as u8,
(identifier_authority >> 24) as u8,
(identifier_authority >> 16) as u8,
(identifier_authority >> 8) as u8,
identifier_authority as u8
]),
sub_authority: MaybeHeap::Stack(stack_sub_authorities, N),
}
}
pub fn from_bytes(input: &[u8]) -> Result<Self, SecurityIdentifierError> {
let (remainder, sid) = parse_sid_bytes(input).finish()?;
if !remainder.is_empty() {
Err(SecurityIdentifierError::UnexpectedContent(format!("{:?}", remainder)))
} else {
Ok(sid)
}
}
pub fn to_bytes(&self) -> Vec<u8> {
let mut result = Vec::with_capacity(8 + (self.sub_authority.as_slice().len() * 4));
result.push(1);
result.push(self.sub_authority.as_slice().len() as u8);
for byte in self.identifier_authority.0 {
result.push(byte)
}
for sub_authority in self.sub_authority.as_slice() {
for byte in sub_authority.to_le_bytes() {
result.push(byte);
}
}
result
}
pub fn to_ldap_predicate(&self) -> String {
let bytes = self.to_bytes();
let mut predicate = String::with_capacity(12 + (bytes.len() * 3));
let _ = write!(predicate, "(objectSID=");
for byte in bytes {
let _ = write!(predicate, "\\{:02x}", byte);
}
let _ = write!(predicate, ")");
predicate
}
pub fn get_resource_identifier(&self) -> Option<&u32> {
self.sub_authority.as_slice().last()
}
pub fn get_identifier_authority(&self) -> &IdentifierAuthority {
&self.identifier_authority
}
pub fn get_identifier_sub_authority(&self) -> &[u32] {
self.sub_authority.as_slice()
}
fn parse_str(input: &str) -> IResult<&str, Self> {
let (input, _) = tag::<_, _, nom::error::Error<_>>("S-1")(input)?;
let (input, identifier_authority) = IdentifierAuthority::parse_str(input)?;
let (input, sub_authority) = many0(sid_segment)(input)?;
Ok((
input,
Self {
identifier_authority,
sub_authority : sub_authority.into(),
},
))
}
}
impl Display for SecurityIdentifier {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.write_fmt(format_args!("S-1-{}", self.identifier_authority))?;
for sub_authority in self.sub_authority.as_slice() {
f.write_fmt(format_args!("-{}", sub_authority))?;
}
Ok(())
}
}
impl FromStr for SecurityIdentifier {
type Err = SecurityIdentifierError;
fn from_str(input: &str) -> Result<Self, Self::Err> {
use_parse_str(Self::parse_str(input))
}
}
#[cfg(feature = "serde")]
impl<'de> Deserialize<'de> for SecurityIdentifier {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
SecurityIdentifier::from_str(&String::deserialize(deserializer)?).map_err(|err| D::Error::custom(err.to_string()))
}
}
#[cfg(feature = "serde")]
impl Serialize for SecurityIdentifier {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
self.to_string().serialize(serializer)
}
}
fn dec_u64(input: &str) -> IResult<&str, u64> {
map_res(recognize(digit1), str::parse)(input)
}
fn hex_u64(input: &str) -> IResult<&str, u64> {
let (input, _) = tag("0x")(input)?;
map_res(recognize(hex_digit1), |x| u64::from_str_radix(x, 16))(input)
}
fn dec_u32(input: &str) -> IResult<&str, u32> {
map_res(recognize(digit1), str::parse)(input)
}
fn hex_u32(input: &str) -> IResult<&str, u32> {
let (input, _) = tag("0x")(input)?;
map_res(recognize(hex_digit1), |x| u32::from_str_radix(x, 16))(input)
}
fn sid_segment(input: &str) -> IResult<&str, u32> {
let (input, _) = tag("-")(input)?;
let (input, value) = alt((hex_u32, dec_u32))(input)?;
Ok((input, value))
}
fn parse_sid_bytes(input: &[u8]) -> IResult<&[u8], SecurityIdentifier> {
let (input, _) = tag([1])(input)?;
let (input, sub_authority_count) = nom::number::complete::u8(input)?;
let (input, identifier_authority) = take(6usize)(input)?;
let (input, sub_authority) = many_m_n(sub_authority_count as usize, sub_authority_count as usize, le_u32)(input)?;
Ok((
input,
SecurityIdentifier {
identifier_authority: IdentifierAuthority(identifier_authority.try_into().unwrap()),
sub_authority: sub_authority.into(),
},
))
}
#[derive(Error, Debug)]
pub enum SecurityIdentifierError {
#[error("bad revision")]
BadRevision,
#[error("parsing error: {0}")]
ParseError(String),
#[error("unexpected content: {0}")]
UnexpectedContent(String),
}
impl<E> From<nom::error::Error<E>> for SecurityIdentifierError
where
E: Debug,
{
fn from(value: nom::error::Error<E>) -> Self {
Self::ParseError(format!("{:?}: {:?}", value.code, value.input))
}
}