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