Skip to main content

ldap_parser/
filter_parser.rs

1use crate::error::*;
2use crate::filter::*;
3use crate::ldap::*;
4use crate::parser::*;
5use asn1_rs::nom;
6use asn1_rs::OptTaggedImplicit;
7use asn1_rs::{
8    Any, Class, FromBer, OptTaggedParser, ParseResult, Sequence, Set, Tag, TaggedParser,
9};
10use nom::combinator::{complete, map};
11use nom::multi::{many0, many1};
12use nom::Err;
13// use nom::dbg_dmp;
14use std::borrow::Cow;
15
16// AttributeDescription ::= LDAPString
17//                         -- Constrained to <attributedescription>
18//                         -- [RFC4512]
19#[inline]
20fn parse_ldap_attribute_description(i: &[u8]) -> Result<'_, LdapString<'_>> {
21    LdapString::from_ber(i)
22}
23
24// AttributeValue ::= OCTET STRING
25// #[inline]
26// fn parse_ldap_attribute_value(i: &[u8]) -> Result<&[u8]> {
27//     parse_ldap_octet_string_as_slice(i)
28// }
29
30// AttributeValueAssertion ::= SEQUENCE {
31//      attributeDesc   AttributeDescription,
32//      assertionValue  AssertionValue }
33fn parse_ldap_attribute_value_assertion_content(
34    content: &[u8],
35) -> Result<'_, AttributeValueAssertion<'_>> {
36    let (content, attribute_desc) = parse_ldap_attribute_description(content)?;
37    let (content, assertion_value) = parse_ldap_assertion_value(content)?;
38    let assertion = AttributeValueAssertion {
39        attribute_desc,
40        assertion_value: assertion_value.into(),
41    };
42    Ok((content, assertion))
43}
44
45impl<'a> FromBer<'a, LdapError> for AttributeValueAssertion<'a> {
46    fn from_ber(bytes: &'a [u8]) -> ParseResult<'a, Self, LdapError> {
47        Sequence::from_ber_and_then(bytes, parse_ldap_attribute_value_assertion_content)
48    }
49}
50
51// AssertionValue ::= OCTET STRING
52#[inline]
53fn parse_ldap_assertion_value(i: &[u8]) -> Result<'_, &[u8]> {
54    parse_ldap_octet_string_as_slice(i)
55}
56
57// AttributeValue ::= OCTET STRING
58#[inline]
59fn parse_ldap_attribute_value(i: &[u8]) -> Result<'_, AttributeValue<'_>> {
60    map(parse_ldap_octet_string_as_slice, |v| {
61        AttributeValue(Cow::Borrowed(v))
62    })(i)
63}
64
65// PartialAttribute ::= SEQUENCE {
66//      type       AttributeDescription,
67//      vals       SET OF value AttributeValue }
68impl<'a> FromBer<'a, LdapError> for PartialAttribute<'a> {
69    fn from_ber(bytes: &'a [u8]) -> ParseResult<'a, Self, LdapError> {
70        Sequence::from_ber_and_then(bytes, |i| {
71            let (i, attr_type) = LdapString::from_ber(i)?;
72            let (i, attr_vals) = Set::from_ber_and_then(i, |inner| {
73                many0(complete(
74                    // dbg_dmp(|d| parse_ldap_attribute_value(d), "parse_partial_attribute")
75                    parse_ldap_attribute_value,
76                ))(inner)
77            })?;
78            let partial_attr = PartialAttribute {
79                attr_type,
80                attr_vals,
81            };
82            Ok((i, partial_attr))
83        })
84    }
85}
86
87// Attribute ::= PartialAttribute(WITH COMPONENTS {
88//      ...,
89//      vals (SIZE(1..MAX))})
90impl<'a> FromBer<'a, LdapError> for Attribute<'a> {
91    fn from_ber(bytes: &'a [u8]) -> ParseResult<'a, Self, LdapError> {
92        Sequence::from_ber_and_then(bytes, |i| {
93            let (i, attr_type) = LdapString::from_ber(i)?;
94            let (i, attr_vals) = Set::from_ber_and_then(i, |inner| {
95                many1(complete(
96                    // dbg_dmp(|d| parse_ldap_attribute_value(d), "parse_partial_attribute")
97                    parse_ldap_attribute_value,
98                ))(inner)
99            })?;
100            let attr = Attribute {
101                attr_type,
102                attr_vals,
103            };
104            Ok((i, attr))
105        })
106    }
107}
108
109// MatchingRuleId ::= LDAPString
110
111/// Attempt to parse a `Filter` object and return the result, or an error
112///
113/// This function is recursive, and has a maximum limit (see `MAX_FILTER_DEPTH` constant)
114// Filter ::= CHOICE {
115//     and             [0] SET SIZE (1..MAX) OF filter Filter,
116//     or              [1] SET SIZE (1..MAX) OF filter Filter,
117//     not             [2] Filter,
118//     equalityMatch   [3] AttributeValueAssertion,
119//     substrings      [4] SubstringFilter,
120//     greaterOrEqual  [5] AttributeValueAssertion,
121//     lessOrEqual     [6] AttributeValueAssertion,
122//     present         [7] AttributeDescription,
123//     approxMatch     [8] AttributeValueAssertion,
124//     extensibleMatch [9] MatchingRuleAssertion,
125//     ...  }
126impl<'a> FromBer<'a, LdapError> for Filter<'a> {
127    #[inline]
128    fn from_ber(bytes: &'a [u8]) -> ParseResult<'a, Self, LdapError> {
129        filter_from_ber(MAX_FILTER_DEPTH)(bytes)
130    }
131}
132
133/// Helper function to build a combinator to parse a `Filter` parser, with depth limit argument
134#[inline]
135const fn filter_from_ber<'i>(
136    limit: usize,
137) -> impl FnMut(&'i [u8]) -> ParseResult<'i, Filter<'i>, LdapError> {
138    move |bytes: &'i [u8]| Filter::from_ber_recursive(bytes, limit)
139}
140
141impl<'a> Filter<'a> {
142    /// Parse a `Filter`, but with recursion limit.
143    ///
144    /// If `limit` reaches zero, returns an error `LdapError::FilterMaxDepth`.
145    fn from_ber_recursive(bytes: &'a [u8], limit: usize) -> ParseResult<'a, Self, LdapError> {
146        if limit == 0 {
147            return Err(Err::Error(LdapError::FilterMaxDepth));
148        }
149        // new limit
150        let limit = limit - 1;
151
152        // read next element as ANY and look tag value
153        let (rem, any) = Any::from_ber(bytes).map_err(Err::convert)?;
154        // eprintln!("parse_ldap_filter: [{}] {:?}", header.tag.0, header);
155        // tag is context-specific IMPLICIT
156        any.class()
157            .assert_eq(Class::ContextSpecific)
158            .map_err(|e| Err::Error(e.into()))?;
159        let content = any.data;
160        let (_, filter) = match any.tag().0 {
161            0 => {
162                let (rem, sub_filters) = many1(complete(filter_from_ber(limit)))(content)?;
163                Ok((rem, Filter::And(sub_filters)))
164            }
165            1 => {
166                let (rem, sub_filters) = many1(complete(filter_from_ber(limit)))(content)?;
167                Ok((rem, Filter::Or(sub_filters)))
168            }
169            2 => map(filter_from_ber(limit), |f| Filter::Not(Box::new(f)))(content),
170            3 => map(
171                parse_ldap_attribute_value_assertion_content,
172                Filter::EqualityMatch,
173            )(content),
174            4 => map(parse_ldap_substrings_filter_content, Filter::Substrings)(content),
175            5 => map(
176                parse_ldap_attribute_value_assertion_content,
177                Filter::GreaterOrEqual,
178            )(content),
179            6 => map(
180                parse_ldap_attribute_value_assertion_content,
181                Filter::LessOrEqual,
182            )(content),
183            7 => {
184                let s =
185                    std::str::from_utf8(content).or(Err(Err::Error(LdapError::InvalidString)))?;
186                let s = LdapString(Cow::Borrowed(s));
187                Ok(([].as_ref(), Filter::Present(s)))
188            }
189            8 => map(
190                parse_ldap_attribute_value_assertion_content,
191                Filter::ApproxMatch,
192            )(content),
193            9 => map(
194                parse_ldap_matching_rule_assertion_content,
195                Filter::ExtensibleMatch,
196            )(content),
197            _ => {
198                // print_hex_dump(i, 32);
199                // panic!("Filter id {} not yet implemented", header.tag.0);
200                Err(Err::Error(LdapError::InvalidFilterType))
201            }
202        }?;
203        // use the remaining bytes from the outer object
204        Ok((rem, filter))
205    }
206}
207
208// SubstringFilter ::= SEQUENCE {
209//      type           AttributeDescription,
210//      substrings     SEQUENCE SIZE (1..MAX) OF substring CHOICE {
211//           initial [0] AssertionValue,  -- can occur at most once
212//           any     [1] AssertionValue,
213//           final   [2] AssertionValue } -- can occur at most once
214//      }
215fn parse_ldap_substrings_filter_content(i: &[u8]) -> Result<'_, SubstringFilter<'_>> {
216    let (i, filter_type) = parse_ldap_attribute_description(i)?;
217    let (i, substrings) =
218        Sequence::from_ber_and_then(i, |inner| many1(complete(parse_ldap_substring))(inner))?;
219    let filter = SubstringFilter {
220        filter_type,
221        substrings,
222    };
223    Ok((i, filter))
224}
225
226fn parse_ldap_substring(bytes: &[u8]) -> Result<'_, Substring<'_>> {
227    let (rem, any) = Any::from_ber(bytes).map_err(Err::convert)?;
228    // in any case, this is an AssertionValue (== OCTET STRING)
229    let b = AssertionValue(Cow::Borrowed(any.data));
230    match any.tag().0 {
231        0 => Ok((rem, Substring::Initial(b))),
232        1 => Ok((rem, Substring::Any(b))),
233        2 => Ok((rem, Substring::Final(b))),
234        _ => Err(Err::Error(LdapError::InvalidSubstring)),
235    }
236}
237
238// MatchingRuleAssertion ::= SEQUENCE {
239//     matchingRule    [1] MatchingRuleId OPTIONAL,
240//     type            [2] AttributeDescription OPTIONAL,
241//     matchValue      [3] AssertionValue,
242//     dnAttributes    [4] BOOLEAN DEFAULT FALSE }
243fn parse_ldap_matching_rule_assertion_content(i: &[u8]) -> Result<'_, MatchingRuleAssertion<'_>> {
244    // MatchingRuleId ::= LDAPString
245    let (i, matching_rule) =
246        OptTaggedParser::new(Class::ContextSpecific, Tag(1)).parse_ber(i, |_, content| {
247            let s = std::str::from_utf8(content).or(Err(Err::Error(LdapError::InvalidString)))?;
248            let s = LdapString(Cow::Borrowed(s));
249            Ok((&b""[..], s))
250        })?;
251    let (i, rule_type) =
252        OptTaggedParser::new(Class::ContextSpecific, Tag(2)).parse_ber(i, |_, content| {
253            let s = std::str::from_utf8(content).or(Err(Err::Error(LdapError::InvalidString)))?;
254            let s = AttributeDescription(Cow::Borrowed(s));
255            Ok((&b""[..], s))
256        })?;
257    let (i, assertion_value) =
258        TaggedParser::from_ber_and_then(Class::ContextSpecific, 3, i, |content| {
259            let s = AssertionValue(Cow::Borrowed(content));
260            Ok((&b""[..], s))
261        })?;
262    let (i, dn_attributes) =
263        OptTaggedImplicit::<bool, asn1_rs::Error, 4>::from_ber(i).map_err(Err::convert)?;
264    let dn_attributes = dn_attributes.map(|t| t.into_inner());
265    let assertion = MatchingRuleAssertion {
266        matching_rule,
267        rule_type,
268        assertion_value,
269        dn_attributes,
270    };
271    Ok((i, assertion))
272}