use crate::error::*;
use crate::filter::*;
use crate::ldap::*;
use crate::parser::*;
use asn1_rs::nom;
use asn1_rs::OptTaggedImplicit;
use asn1_rs::{
Any, Class, FromBer, OptTaggedParser, ParseResult, Sequence, Set, Tag, TaggedParser,
};
use nom::combinator::{complete, map};
use nom::multi::{many0, many1};
use nom::Err;
use std::borrow::Cow;
#[inline]
fn parse_ldap_attribute_description(i: &[u8]) -> Result<LdapString> {
LdapString::from_ber(i)
}
fn parse_ldap_attribute_value_assertion_content(content: &[u8]) -> Result<AttributeValueAssertion> {
let (content, attribute_desc) = parse_ldap_attribute_description(content)?;
let (content, assertion_value) = parse_ldap_assertion_value(content)?;
let assertion = AttributeValueAssertion {
attribute_desc,
assertion_value,
};
Ok((content, assertion))
}
impl<'a> FromBer<'a, LdapError> for AttributeValueAssertion<'a> {
fn from_ber(bytes: &'a [u8]) -> ParseResult<Self, LdapError> {
Sequence::from_ber_and_then(bytes, parse_ldap_attribute_value_assertion_content)
}
}
#[inline]
fn parse_ldap_assertion_value(i: &[u8]) -> Result<&[u8]> {
parse_ldap_octet_string_as_slice(i)
}
#[inline]
fn parse_ldap_attribute_value(i: &[u8]) -> Result<AttributeValue> {
map(parse_ldap_octet_string_as_slice, |v| {
AttributeValue(Cow::Borrowed(v))
})(i)
}
impl<'a> FromBer<'a, LdapError> for PartialAttribute<'a> {
fn from_ber(bytes: &'a [u8]) -> ParseResult<Self, LdapError> {
Sequence::from_ber_and_then(bytes, |i| {
let (i, attr_type) = LdapString::from_ber(i)?;
let (i, attr_vals) = Set::from_ber_and_then(i, |inner| {
many0(complete(
parse_ldap_attribute_value,
))(inner)
})?;
let partial_attr = PartialAttribute {
attr_type,
attr_vals,
};
Ok((i, partial_attr))
})
}
}
impl<'a> FromBer<'a, LdapError> for Attribute<'a> {
fn from_ber(bytes: &'a [u8]) -> ParseResult<Self, LdapError> {
Sequence::from_ber_and_then(bytes, |i| {
let (i, attr_type) = LdapString::from_ber(i)?;
let (i, attr_vals) = Set::from_ber_and_then(i, |inner| {
many1(complete(
parse_ldap_attribute_value,
))(inner)
})?;
let attr = Attribute {
attr_type,
attr_vals,
};
Ok((i, attr))
})
}
}
impl<'a> FromBer<'a, LdapError> for Filter<'a> {
fn from_ber(bytes: &'a [u8]) -> ParseResult<Self, LdapError> {
let (rem, any) = Any::from_ber(bytes).map_err(Err::convert)?;
any.class()
.assert_eq(Class::ContextSpecific)
.map_err(|e| Err::Error(e.into()))?;
let content = any.data;
let (_, filter) = match any.tag().0 {
0 => {
let (rem, sub_filters) = many1(complete(Filter::from_ber))(content)?;
Ok((rem, Filter::And(sub_filters)))
}
1 => {
let (rem, sub_filters) = many1(complete(Filter::from_ber))(content)?;
Ok((rem, Filter::Or(sub_filters)))
}
2 => map(Filter::from_ber, |f| Filter::Not(Box::new(f)))(content),
3 => map(
parse_ldap_attribute_value_assertion_content,
Filter::EqualityMatch,
)(content),
4 => map(parse_ldap_substrings_filter_content, Filter::Substrings)(content),
5 => map(
parse_ldap_attribute_value_assertion_content,
Filter::GreaterOrEqual,
)(content),
6 => map(
parse_ldap_attribute_value_assertion_content,
Filter::LessOrEqual,
)(content),
7 => {
let s =
std::str::from_utf8(content).or(Err(Err::Error(LdapError::InvalidString)))?;
let s = LdapString(Cow::Borrowed(s));
Ok(([].as_ref(), Filter::Present(s)))
}
8 => map(
parse_ldap_attribute_value_assertion_content,
Filter::ApproxMatch,
)(content),
9 => map(
parse_ldap_matching_rule_assertion_content,
Filter::ExtensibleMatch,
)(content),
_ => {
Err(Err::Error(LdapError::InvalidFilterType))
}
}?;
Ok((rem, filter))
}
}
fn parse_ldap_substrings_filter_content(i: &[u8]) -> Result<SubstringFilter> {
let (i, filter_type) = parse_ldap_attribute_description(i)?;
let (i, substrings) =
Sequence::from_ber_and_then(i, |inner| many1(complete(parse_ldap_substring))(inner))?;
let filter = SubstringFilter {
filter_type,
substrings,
};
Ok((i, filter))
}
fn parse_ldap_substring(bytes: &[u8]) -> Result<Substring> {
let (rem, any) = Any::from_ber(bytes).map_err(Err::convert)?;
let b = AssertionValue(Cow::Borrowed(any.data));
match any.tag().0 {
0 => Ok((rem, Substring::Initial(b))),
1 => Ok((rem, Substring::Any(b))),
2 => Ok((rem, Substring::Final(b))),
_ => Err(Err::Error(LdapError::InvalidSubstring)),
}
}
fn parse_ldap_matching_rule_assertion_content(i: &[u8]) -> Result<MatchingRuleAssertion> {
let (i, matching_rule) =
OptTaggedParser::new(Class::ContextSpecific, Tag(1)).parse_ber(i, |_, content| {
let s = std::str::from_utf8(content).or(Err(Err::Error(LdapError::InvalidString)))?;
let s = LdapString(Cow::Borrowed(s));
Ok((&b""[..], s))
})?;
let (i, rule_type) =
OptTaggedParser::new(Class::ContextSpecific, Tag(2)).parse_ber(i, |_, content| {
let s = std::str::from_utf8(content).or(Err(Err::Error(LdapError::InvalidString)))?;
let s = AttributeDescription(Cow::Borrowed(s));
Ok((&b""[..], s))
})?;
let (i, assertion_value) =
TaggedParser::from_ber_and_then(Class::ContextSpecific, 3, i, |content| {
let s = AssertionValue(Cow::Borrowed(content));
Ok((&b""[..], s))
})?;
let (i, dn_attributes) =
OptTaggedImplicit::<bool, asn1_rs::Error, 4>::from_ber(i).map_err(Err::convert)?;
let dn_attributes = dn_attributes.map(|t| t.into_inner());
let assertion = MatchingRuleAssertion {
matching_rule,
rule_type,
assertion_value,
dn_attributes,
};
Ok((i, assertion))
}