1use crate::error::*;
6use crate::filter::*;
7use crate::ldap::*;
8use asn1_rs::nom;
9use asn1_rs::{
10 Class, Enumerated, FromBer, Header, Implicit, OptTaggedParser, ParseResult, Sequence, Tag,
11 TaggedParser, TaggedValue,
12};
13use nom::bytes::streaming::take;
14use nom::combinator::{complete, map, opt, verify};
15use nom::multi::{many0, many1};
16use nom::Err;
17use std::borrow::Cow;
18
19impl<'a> FromBer<'a, LdapError> for MessageID {
24 fn from_ber(bytes: &'a [u8]) -> ParseResult<'a, Self, LdapError> {
25 map(u32::from_ber, MessageID)(bytes).map_err(Err::convert)
26 }
27}
28
29impl<'a> FromBer<'a, LdapError> for LdapString<'a> {
32 fn from_ber(bytes: &'a [u8]) -> ParseResult<'a, Self, LdapError> {
33 let (i, b) = parse_ldap_octet_string_as_slice(bytes)?;
34 let s = std::str::from_utf8(b).or(Err(Err::Error(LdapError::InvalidString)))?;
36 Ok((i, LdapString(Cow::Borrowed(s))))
37 }
38}
39
40#[inline]
41pub(crate) fn parse_ldap_octet_string_as_slice(i: &[u8]) -> Result<&[u8]> {
42 <&[u8]>::from_ber(i).map_err(Err::convert)
43}
44
45#[inline]
46fn parse_ldap_int_as_u32(i: &[u8]) -> Result<u32> {
47 <u32>::from_ber(i).map_err(Err::convert)
48}
49
50#[inline]
51fn parse_ldap_enum_as_u32(i: &[u8]) -> Result<u32> {
52 let (i, obj) = Enumerated::from_ber(i).map_err(Err::convert)?;
53 Ok((i, obj.0))
54}
55
56impl<'a> FromBer<'a, LdapError> for LdapDN<'a> {
59 fn from_ber(bytes: &'a [u8]) -> ParseResult<'a, Self, LdapError> {
60 let (i, b) = <&[u8]>::from_ber(bytes).map_err(Err::convert)?;
62 let s = std::str::from_utf8(b).or(Err(Err::Error(LdapError::InvalidDN)))?;
64 Ok((i, LdapDN(Cow::Borrowed(s))))
65 }
66}
67
68impl<'a> FromBer<'a, LdapError> for RelativeLdapDN<'a> {
71 fn from_ber(bytes: &'a [u8]) -> ParseResult<'a, Self, LdapError> {
72 let (i, b) = <&[u8]>::from_ber(bytes).map_err(Err::convert)?;
74 let s = std::str::from_utf8(b).or(Err(Err::Error(LdapError::InvalidDN)))?;
76 Ok((i, RelativeLdapDN(Cow::Borrowed(s))))
77 }
78}
79
80impl<'a> FromBer<'a, LdapError> for LdapOID<'a> {
83 fn from_ber(bytes: &'a [u8]) -> ParseResult<'a, Self, LdapError> {
84 let (i, b) = <&[u8]>::from_ber(bytes).map_err(Err::convert)?;
86 let s = std::str::from_utf8(b).or(Err(Err::Error(LdapError::InvalidDN)))?;
88 Ok((i, LdapOID(Cow::Borrowed(s))))
89 }
90}
91
92#[inline]
95fn parse_ldap_uri(i: &[u8]) -> Result<LdapString> {
96 LdapString::from_ber(i)
97}
98
99fn parse_ldap_result_content(i: &[u8]) -> Result<LdapResult> {
165 let (i, result_code) = map(parse_ldap_enum_as_u32, ResultCode)(i)?;
166 let (i, matched_dn) = LdapDN::from_ber(i)?;
167 let (i, diagnostic_message) = LdapString::from_ber(i)?;
168 let result = LdapResult {
170 result_code,
171 matched_dn,
172 diagnostic_message,
173 };
174 Ok((i, result))
175}
176
177impl<'a> FromBer<'a, LdapError> for LdapMessage<'a> {
231 fn from_ber(bytes: &'a [u8]) -> ParseResult<'a, Self, LdapError> {
232 Sequence::from_ber_and_then(bytes, |i| {
233 let (i, message_id) = MessageID::from_ber(i)?;
234 let (_, header) = Header::from_ber(i).map_err(Err::convert)?;
236 let (i, protocol_op) = match header.tag().0 {
237 0 => map(BindRequest::from_ber, ProtocolOp::BindRequest)(i),
238 1 => map(BindResponse::from_ber, ProtocolOp::BindResponse)(i),
239 2 => parse_ldap_unbind_request(i),
240 3 => map(SearchRequest::from_ber, ProtocolOp::SearchRequest)(i),
241 4 => map(SearchResultEntry::from_ber, ProtocolOp::SearchResultEntry)(i),
242 5 => map(parse_ldap_search_result_done, ProtocolOp::SearchResultDone)(i),
243 6 => map(ModifyRequest::from_ber, ProtocolOp::ModifyRequest)(i),
244 7 => map(parse_ldap_modify_response, ProtocolOp::ModifyResponse)(i),
245 8 => map(AddRequest::from_ber, ProtocolOp::AddRequest)(i),
246 9 => map(parse_ldap_add_response, ProtocolOp::AddResponse)(i),
247 10 => map(parse_ldap_del_request, ProtocolOp::DelRequest)(i),
248 11 => map(parse_ldap_del_response, ProtocolOp::DelResponse)(i),
249 12 => map(ModDnRequest::from_ber, ProtocolOp::ModDnRequest)(i),
250 13 => map(parse_ldap_moddn_response, ProtocolOp::ModDnResponse)(i),
251 14 => map(CompareRequest::from_ber, ProtocolOp::CompareRequest)(i),
252 15 => map(parse_ldap_compare_response, ProtocolOp::CompareResponse)(i),
253 16 => map(parse_ldap_abandon_request, ProtocolOp::AbandonRequest)(i),
254 19 => map(
255 parse_ldap_search_result_ref,
256 ProtocolOp::SearchResultReference,
257 )(i),
258 23 => map(ExtendedRequest::from_ber, ProtocolOp::ExtendedRequest)(i),
259 24 => map(ExtendedResponse::from_ber, ProtocolOp::ExtendedResponse)(i),
260 25 => map(
261 IntermediateResponse::from_ber,
262 ProtocolOp::IntermediateResponse,
263 )(i),
264 _ => {
265 Err(Err::Error(LdapError::InvalidMessageType))
268 }
269 }?;
270 let (i, controls) = OptTaggedParser::new(Class::ContextSpecific, Tag(0))
271 .parse_ber(i, |_, i| many0(complete(Control::from_ber))(i))?;
272 let msg = LdapMessage {
273 message_id,
274 protocol_op,
275 controls,
276 };
277 Ok((i, msg))
278 })
279 }
280}
281
282#[deprecated(
283 since = "0.3.0",
284 note = "Parsing functions are deprecated. Users should instead use the FromBer trait"
285)]
286#[inline]
287pub fn parse_ldap_message(i: &[u8]) -> Result<LdapMessage> {
288 LdapMessage::from_ber(i)
289}
290
291pub fn parse_ldap_messages(i: &[u8]) -> Result<Vec<LdapMessage>> {
294 many1(complete(LdapMessage::from_ber))(i)
297}
298
299impl<'a> FromBer<'a, LdapError> for BindRequest<'a> {
304 fn from_ber(bytes: &'a [u8]) -> ParseResult<'a, Self, LdapError> {
305 TaggedParser::from_ber_and_then(Class::Application, 0, bytes, |i| {
306 let (i, version) = verify(u8::from_ber, |&n| n < 128)(i).map_err(Err::convert)?;
308 let (i, name) = LdapDN::from_ber(i)?;
309 let (i, authentication) = AuthenticationChoice::from_ber(i)?;
310 let req = BindRequest {
311 version,
312 name,
313 authentication,
314 };
315 Ok((i, req))
316 })
318 }
319}
320
321impl<'a> FromBer<'a, LdapError> for BindResponse<'a> {
325 fn from_ber(bytes: &'a [u8]) -> ParseResult<'a, Self, LdapError> {
326 TaggedParser::from_ber_and_then(Class::Application, 1, bytes, |i| {
327 let (i, result) = parse_ldap_result_content(i)?;
328 let (i, server_sasl_creds) = OptTaggedParser::new(Class::ContextSpecific, Tag(7))
329 .parse_ber(i, |_, data| Ok((&b""[..], Cow::Borrowed(data))))?;
330
331 let req = BindResponse {
335 result,
336 server_sasl_creds,
337 };
338 Ok((i, req))
339 })
340 }
341}
342
343fn parse_ldap_unbind_request(bytes: &[u8]) -> Result<ProtocolOp> {
345 TaggedParser::from_ber_and_then(Class::Application, 2, bytes, |i| {
346 if !i.is_empty() {
348 let (_, _) = <()>::from_ber(i).map_err(Err::convert)?;
349 }
350 Ok((i, ProtocolOp::UnbindRequest))
351 })
352}
353
354impl<'a> FromBer<'a, LdapError> for SearchRequest<'a> {
372 fn from_ber(bytes: &'a [u8]) -> ParseResult<'a, Self, LdapError> {
373 TaggedParser::from_ber_and_then(Class::Application, 3, bytes, |i| {
374 let (i, base_object) = LdapDN::from_ber(i)?;
375 let (i, scope) = map(parse_ldap_enum_as_u32, SearchScope)(i)?;
376 let (i, deref_aliases) = map(parse_ldap_enum_as_u32, DerefAliases)(i)?;
377 let (i, size_limit) = parse_ldap_int_as_u32(i)?;
378 let (i, time_limit) = parse_ldap_int_as_u32(i)?;
379 let (i, types_only) = <bool>::from_ber(i).map_err(Err::convert)?;
380 let (i, filter) = Filter::from_ber(i)?;
381 let (i, attributes) = parse_attribute_selection(i)?;
382 let req = SearchRequest {
383 base_object,
384 scope,
385 deref_aliases,
386 size_limit,
387 time_limit,
388 types_only,
389 filter,
390 attributes,
391 };
392 Ok((i, req))
393 })
394 }
395}
396
397impl<'a> FromBer<'a, LdapError> for SearchResultEntry<'a> {
401 fn from_ber(bytes: &'a [u8]) -> ParseResult<'a, Self, LdapError> {
402 TaggedParser::from_ber_and_then(Class::Application, 4, bytes, |i| {
403 let (i, object_name) = LdapDN::from_ber(i)?;
404 let (i, attributes) = parse_partial_attribute_list(i)?;
405 let res = SearchResultEntry {
406 object_name,
407 attributes,
408 };
409 Ok((i, res))
410 })
411 }
412}
413
414fn parse_ldap_search_result_done(bytes: &[u8]) -> Result<LdapResult> {
416 TaggedParser::from_ber_and_then(Class::Application, 5, bytes, parse_ldap_result_content)
417}
418
419impl<'a> FromBer<'a, LdapError> for ModifyRequest<'a> {
429 fn from_ber(bytes: &'a [u8]) -> ParseResult<'a, Self, LdapError> {
430 TaggedParser::from_ber_and_then(Class::Application, 6, bytes, |i| {
431 let (i, object) = LdapDN::from_ber(i)?;
432 let (i, changes) = Sequence::from_ber_and_then(i, many1(complete(Change::from_ber)))?;
433 let res = ModifyRequest { object, changes };
434 Ok((i, res))
435 })
436 }
437}
438
439fn parse_ldap_modify_response(bytes: &[u8]) -> Result<ModifyResponse> {
441 TaggedParser::from_ber_and_then(Class::Application, 7, bytes, |i| {
442 let (i, result) = parse_ldap_result_content(i)?;
443 let res = ModifyResponse { result };
444 Ok((i, res))
445 })
446}
447
448impl<'a> FromBer<'a, LdapError> for AddRequest<'a> {
452 fn from_ber(bytes: &'a [u8]) -> ParseResult<'a, Self, LdapError> {
453 TaggedParser::from_ber_and_then(Class::Application, 8, bytes, |i| {
454 let (i, entry) = LdapDN::from_ber(i)?;
455 let (i, attributes) = parse_attribute_list(i)?;
456 let res = AddRequest { entry, attributes };
457 Ok((i, res))
458 })
459 }
460}
461
462fn parse_ldap_add_response(bytes: &[u8]) -> Result<LdapResult> {
464 TaggedParser::from_ber_and_then(Class::Application, 9, bytes, parse_ldap_result_content)
465}
466
467fn parse_ldap_del_request(bytes: &[u8]) -> Result<LdapDN> {
469 TaggedParser::from_ber_and_then(Class::Application, 10, bytes, |i| {
470 let s = std::str::from_utf8(i).or(Err(Err::Error(LdapError::InvalidDN)))?;
471 let oid = LdapDN(Cow::Borrowed(s));
472 Ok((&b""[..], oid))
473 })
474}
475
476fn parse_ldap_del_response(bytes: &[u8]) -> Result<LdapResult> {
478 TaggedParser::from_ber_and_then(Class::Application, 11, bytes, parse_ldap_result_content)
479}
480
481impl<'a> FromBer<'a, LdapError> for ModDnRequest<'a> {
487 fn from_ber(bytes: &'a [u8]) -> ParseResult<'a, Self, LdapError> {
488 TaggedParser::from_ber_and_then(Class::Application, 12, bytes, |i| {
489 let (i, entry) = LdapDN::from_ber(i)?;
490 let (i, newrdn) = RelativeLdapDN::from_ber(i)?;
491 let (i, deleteoldrdn) = <bool>::from_ber(i).map_err(Err::convert)?;
492 let (i, newsuperior) =
493 OptTaggedParser::new(Class::ContextSpecific, Tag(0)).parse_ber(i, |_, i| {
494 let s = std::str::from_utf8(i).or(Err(Err::Error(LdapError::InvalidDN)))?;
495 let oid = LdapDN(Cow::Borrowed(s));
496 Ok((&b""[..], oid))
497 })?;
498 let res = ModDnRequest {
499 entry,
500 newrdn,
501 deleteoldrdn,
502 newsuperior,
503 };
504 Ok((i, res))
505 })
506 }
507}
508
509fn parse_ldap_moddn_response(bytes: &[u8]) -> Result<LdapResult> {
511 TaggedParser::from_ber_and_then(Class::Application, 13, bytes, parse_ldap_result_content)
512}
513
514impl<'a> FromBer<'a, LdapError> for CompareRequest<'a> {
518 fn from_ber(bytes: &'a [u8]) -> ParseResult<'a, Self, LdapError> {
519 TaggedParser::from_ber_and_then(Class::Application, 14, bytes, |i| {
520 let (i, entry) = LdapDN::from_ber(i)?;
521 let (i, ava) = AttributeValueAssertion::from_ber(i)?;
522 let res = CompareRequest { entry, ava };
523 Ok((i, res))
524 })
525 }
526}
527
528fn parse_ldap_compare_response(bytes: &[u8]) -> Result<LdapResult> {
530 TaggedParser::from_ber_and_then(Class::Application, 15, bytes, parse_ldap_result_content)
531}
532
533fn parse_ldap_abandon_request(bytes: &[u8]) -> Result<MessageID> {
535 let (rem, id) = TaggedValue::<u32, _, Implicit, { Class::APPLICATION }, 16>::from_ber(bytes)
536 .map_err(Err::convert)?;
537 Ok((rem, MessageID(id.into_inner())))
538}
539
540fn parse_ldap_search_result_ref(bytes: &[u8]) -> Result<Vec<LdapString>> {
543 TaggedParser::from_ber_and_then(
544 Class::Application,
545 19,
546 bytes,
547 many1(complete(parse_ldap_uri)),
548 )
549}
550
551impl<'a> FromBer<'a, LdapError> for ExtendedRequest<'a> {
555 fn from_ber(bytes: &'a [u8]) -> ParseResult<'a, Self, LdapError> {
556 TaggedParser::from_ber_and_then(Class::Application, 23, bytes, |i| {
557 let (i, request_name) =
558 TaggedParser::from_ber_and_then(Class::ContextSpecific, 0, i, |i| {
559 let s = std::str::from_utf8(i).or(Err(Err::Error(LdapError::InvalidDN)))?;
560 let oid = LdapOID(Cow::Borrowed(s));
561 Ok((&b""[..], oid))
562 })?;
563 let (i, request_value) = OptTaggedParser::new(Class::ContextSpecific, Tag(1))
564 .parse_ber(i, |_, data| Ok((&b""[..], Cow::Borrowed(data))))?;
565 let req = ExtendedRequest {
566 request_name,
567 request_value,
568 };
569 Ok((i, req))
570 })
571 }
572}
573
574impl<'a> FromBer<'a, LdapError> for ExtendedResponse<'a> {
579 fn from_ber(bytes: &'a [u8]) -> ParseResult<'a, Self, LdapError> {
580 TaggedParser::from_ber_and_then(Class::Application, 24, bytes, |i| {
581 let (i, result) = parse_ldap_result_content(i)?;
582 let (i, response_name) = OptTaggedParser::new(Class::ContextSpecific, Tag(10))
583 .parse_ber(i, |_, i| {
584 let s = std::str::from_utf8(i).or(Err(Err::Error(LdapError::InvalidDN)))?;
585 let oid = LdapOID(Cow::Borrowed(s));
586 Ok((&b""[..], oid))
587 })?;
588 let (i, response_value) = OptTaggedParser::new(Class::ContextSpecific, Tag(11))
589 .parse_ber(i, |_, data| Ok((&b""[..], Cow::Borrowed(data))))?;
590 let resp = ExtendedResponse {
591 result,
592 response_name,
593 response_value,
594 };
595 Ok((i, resp))
596 })
597 }
598}
599
600impl<'a> FromBer<'a, LdapError> for IntermediateResponse<'a> {
604 fn from_ber(bytes: &'a [u8]) -> ParseResult<'a, Self, LdapError> {
605 TaggedParser::from_ber_and_then(Class::Application, 25, bytes, |i| {
606 let (i, response_name) = OptTaggedParser::new(Class::ContextSpecific, Tag(0))
607 .parse_ber(i, |_, i| {
608 let s = std::str::from_utf8(i).or(Err(Err::Error(LdapError::InvalidDN)))?;
609 let oid = LdapOID(Cow::Borrowed(s));
610 Ok((&b""[..], oid))
611 })?;
612 let (i, response_value) = OptTaggedParser::new(Class::ContextSpecific, Tag(1))
613 .parse_ber(i, |_, data| Ok((&b""[..], Cow::Borrowed(data))))?;
614 let resp = IntermediateResponse {
615 response_name,
616 response_value,
617 };
618 Ok((i, resp))
619 })
620 }
621}
622
623impl<'a> FromBer<'a, LdapError> for AuthenticationChoice<'a> {
629 fn from_ber(bytes: &'a [u8]) -> ParseResult<'a, Self, LdapError> {
630 let (rem, header) = Header::from_ber(bytes).map_err(Err::convert)?;
631 match header.tag().0 {
632 0 => {
633 let sz = header
635 .length()
636 .definite()
637 .map_err(|e| Err::Error(LdapError::Ber(e)))?;
638 let (i, b) = take(sz)(rem)?;
639 Ok((i, AuthenticationChoice::Simple(Cow::Borrowed(b))))
654 }
655 3 => map(parse_sasl_credentials, AuthenticationChoice::Sasl)(rem),
656 _ => Err(Err::Error(LdapError::InvalidAuthenticationType)),
657 }
658 }
659}
660
661fn parse_sasl_credentials(i: &[u8]) -> Result<SaslCredentials> {
665 let (i, mechanism) = LdapString::from_ber(i)?;
666 let (i, credentials) = opt(complete(map(
667 parse_ldap_octet_string_as_slice,
668 Cow::Borrowed,
669 )))(i)?;
670 let credentials = SaslCredentials {
671 mechanism,
672 credentials,
673 };
674 Ok((i, credentials))
675}
676
677fn parse_attribute_selection(bytes: &[u8]) -> Result<Vec<LdapString>> {
681 Sequence::from_ber_and_then(bytes, many0(complete(LdapString::from_ber)))
682}
683
684fn parse_partial_attribute_list(bytes: &[u8]) -> Result<Vec<PartialAttribute>> {
686 Sequence::from_ber_and_then(bytes, many0(complete(PartialAttribute::from_ber)))
687}
688
689fn parse_attribute_list(bytes: &[u8]) -> Result<Vec<Attribute>> {
691 Sequence::from_ber_and_then(bytes, many0(complete(Attribute::from_ber)))
692}
693
694impl<'a> FromBer<'a, LdapError> for Change<'a> {
702 fn from_ber(bytes: &'a [u8]) -> ParseResult<'a, Self, LdapError> {
703 Sequence::from_ber_and_then(bytes, |i| {
704 let (i, operation) = map(parse_ldap_enum_as_u32, Operation)(i)?;
705 let (i, modification) = PartialAttribute::from_ber(i)?;
706 let change = Change {
707 operation,
708 modification,
709 };
710 Ok((i, change))
711 })
712 }
713}
714
715impl<'a> FromBer<'a, LdapError> for Control<'a> {
720 fn from_ber(bytes: &'a [u8]) -> ParseResult<'a, Self, LdapError> {
721 Sequence::from_ber_and_then(bytes, |i| {
722 let (i, control_type) = LdapOID::from_ber(i)?;
723 let (i, maybe_critical) = <Option<bool>>::from_ber(i).map_err(Err::convert)?;
724 let criticality = maybe_critical.unwrap_or(false);
726 let (i, control_value) = opt(complete(map(
727 parse_ldap_octet_string_as_slice,
728 Cow::Borrowed,
729 )))(i)?;
730 let control = Control {
731 control_type,
732 criticality,
733 control_value,
734 };
735 Ok((i, control))
736 })
737 }
738}
739
740#[cfg(test)]
754mod tests {
755 use super::*;
756 use asn1_rs::oid;
757 use hex_literal::hex;
758
759 #[test]
760 fn test_parse_bind_request() {
761 const DATA: &[u8] = include_bytes!("../assets/bind_request.bin");
762
763 let (rem, req) = BindRequest::from_ber(DATA).expect("parsing failed");
764 assert!(rem.is_empty());
768 assert_eq!(&req.name.0, "xxxxxxxxxxx@xx.xxx.xxxxx.net");
769 assert_eq!(
770 req.authentication,
771 AuthenticationChoice::Simple(Cow::Borrowed(b"passwor8d1"))
772 );
773 }
774
775 #[test]
776 fn test_parse_bind_request_sasl() {
777 const DATA: &[u8] = include_bytes!("../assets/bind_request_sasl.bin");
778
779 let (rem, req) = BindRequest::from_ber(DATA).expect("parsing failed");
780 assert!(rem.is_empty());
784 assert_eq!(&req.name.0, "");
785 if let AuthenticationChoice::Sasl(sasl_credentials) = &req.authentication {
786 assert_eq!(&sasl_credentials.mechanism.0, "GSS-SPNEGO");
787 } else {
788 panic!("wrong authentication type");
789 }
790 }
791
792 #[test]
793 fn test_parse_bind_response_minimal() {
794 const DATA: &[u8] = &hex!("61 84 00 00 00 07 0a 01 00 04 00 04 00");
795 let (rem, resp) = BindResponse::from_ber(DATA).expect("parsing failed");
796 assert!(rem.is_empty());
800 assert_eq!(resp.result.result_code, ResultCode::Success);
801 }
802
803 #[test]
804 fn test_parse_bind_response_sasl() {
805 const DATA: &[u8] = include_bytes!("../assets/bind_response_sasl.bin");
806 let (rem, resp) = BindResponse::from_ber(DATA).expect("parsing failed");
807 assert!(rem.is_empty());
811 assert_eq!(resp.result.result_code, ResultCode::Success);
812 assert!(resp.server_sasl_creds.is_some());
813 }
814
815 #[test]
816 fn test_parse_unbind_request() {
817 const DATA: &[u8] = &hex!("42 00");
818
819 let (rem, req) = parse_ldap_unbind_request(DATA).expect("parsing failed");
820 assert!(rem.is_empty());
824 assert_eq!(req, ProtocolOp::UnbindRequest);
825 }
826
827 #[test]
828 fn test_parse_search_request() {
829 const DATA: &[u8] = include_bytes!("../assets/search_request.bin");
830 let (rem, resp) = SearchRequest::from_ber(DATA).expect("parsing failed");
831 assert!(rem.is_empty());
835 assert_eq!(&resp.base_object.0, "DC=xx,DC=xxx,DC=xxxxx,DC=net");
836 assert_eq!(resp.scope, SearchScope::WholeSubtree);
837 assert_eq!(resp.attributes.len(), 1);
838 }
839
840 #[test]
841 fn test_parse_search_result_entry() {
842 const DATA: &[u8] = include_bytes!("../assets/search_result_entry.bin");
843 let (rem, resp) = SearchResultEntry::from_ber(DATA).expect("parsing failed");
844 assert!(rem.is_empty());
848 assert_eq!(resp.attributes.len(), 1);
849 }
850
851 #[test]
852 fn test_parse_search_result_done() {
853 const DATA: &[u8] = include_bytes!("../assets/search_result_done.bin");
854 let (rem, resp) = parse_ldap_search_result_done(DATA).expect("parsing failed");
855 assert!(rem.is_empty());
859 assert_eq!(resp.result_code, ResultCode::Success);
860 }
861
862 #[test]
863 fn test_parse_search_result_ref() {
864 const DATA: &[u8] = include_bytes!("../assets/search_result_ref.bin");
865 let (rem, v) = parse_ldap_search_result_ref(DATA).expect("parsing failed");
866 assert!(rem.is_empty());
870 assert_eq!(v.len(), 1);
871 assert_eq!(
872 &v[0].0,
873 "ldap://DomainDnsZones.rccad.net/DC=DomainDnsZones,DC=rccad,DC=net"
874 );
875 }
876
877 #[test]
878 fn test_parse_extended_req() {
879 const DATA: &[u8] = include_bytes!("../assets/extended-req.bin");
880 let (rem, req) = ExtendedRequest::from_ber(DATA).expect("parsing failed");
881 assert!(rem.is_empty());
885 assert_eq!(
886 req.request_name.0,
887 oid!(1.3.6 .1 .4 .1 .1466 .20037).to_string()
888 );
889 assert!(req.request_value.is_none());
890 }
891
892 #[test]
893 fn test_parse_extended_response() {
894 const DATA: &[u8] = &hex!("78 07 0a 01 00 04 00 04 00");
895 let (rem, resp) = ExtendedResponse::from_ber(DATA).expect("parsing failed");
896 assert!(rem.is_empty());
900 assert_eq!(resp.result.result_code, ResultCode::Success);
901 }
902
903 #[test]
904 fn test_parse_modify_request() {
905 const DATA: &[u8] = include_bytes!("../assets/modify-request.bin");
906 let (rem, req) = ModifyRequest::from_ber(DATA).expect("parsing failed");
907 assert!(rem.is_empty());
911 assert_eq!(&req.object.0, "cn=username1,ou=users,dc=xxx,dc=internet");
912 assert_eq!(req.changes.len(), 1);
913 assert_eq!(req.changes[0].modification.attr_type.0, "description");
914 }
915
916 #[test]
917 fn test_parse_modify_response() {
918 const DATA: &[u8] = include_bytes!("../assets/modify-response.bin");
919 let (rem, resp) = parse_ldap_modify_response(DATA).expect("parsing failed");
920 assert!(rem.is_empty());
924 assert_eq!(resp.result.result_code, ResultCode::Success);
925 }
926
927 #[test]
928 fn test_parse_add_request() {
929 const DATA: &[u8] = include_bytes!("../assets/add-request.bin");
930 let (rem, req) = AddRequest::from_ber(DATA).expect("parsing failed");
931 assert!(rem.is_empty());
935 assert_eq!(&req.entry.0, "cn=username1,ou=users,dc=xxx,dc=internet");
936 assert_eq!(req.attributes.len(), 4);
937 }
938
939 #[test]
940 fn test_parse_add_response() {
941 const DATA: &[u8] = include_bytes!("../assets/add-response.bin");
942 let (rem, resp) = parse_ldap_add_response(DATA).expect("parsing failed");
943 assert!(rem.is_empty());
947 assert_eq!(resp.result_code, ResultCode::Success);
948 }
949
950 #[test]
951 fn test_parse_del_request() {
952 const DATA: &[u8] = include_bytes!("../assets/del-request.bin");
953 let (rem, req) = parse_ldap_del_request(DATA).expect("parsing failed");
954 assert!(rem.is_empty());
958 assert_eq!(&req.0, "cn=username2,ou=users2,dc=xxx,dc=internet");
959 }
960
961 #[test]
962 fn test_parse_del_response() {
963 const DATA: &[u8] = include_bytes!("../assets/del-response.bin");
964 let (rem, resp) = parse_ldap_del_response(DATA).expect("parsing failed");
965 assert!(rem.is_empty());
969 assert_eq!(resp.result_code, ResultCode::Success);
970 }
971
972 #[test]
973 fn test_parse_moddn_request() {
974 const DATA: &[u8] = include_bytes!("../assets/moddn-request.bin");
975 let (rem, req) = ModDnRequest::from_ber(DATA).expect("parsing failed");
976 assert!(rem.is_empty());
980 assert_eq!(&req.entry.0, "cn=username1,ou=users,dc=xxx,dc=internet");
981 assert_eq!(&req.newrdn.0, "cn=username2");
982 assert!(req.deleteoldrdn);
983 assert_eq!(&req.newsuperior.unwrap().0, "ou=users,dc=xxx,dc=internet");
984 }
985
986 #[test]
987 fn test_parse_moddn_response() {
988 const DATA: &[u8] = include_bytes!("../assets/moddn-response.bin");
989 let (rem, resp) = parse_ldap_moddn_response(DATA).expect("parsing failed");
990 assert!(rem.is_empty());
994 assert_eq!(resp.result_code, ResultCode::Success);
995 }
996
997 #[test]
998 fn test_parse_compare_request() {
999 const DATA: &[u8] = include_bytes!("../assets/compare-request.bin");
1000 let (rem, req) = CompareRequest::from_ber(DATA).expect("parsing failed");
1001 assert!(rem.is_empty());
1005 assert_eq!(&req.entry.0, "cn=username2,ou=users2,dc=xxx,dc=internet");
1006 assert_eq!(&req.ava.attribute_desc.0, "cn");
1007 }
1008
1009 #[test]
1010 fn test_parse_compare_response() {
1011 const DATA: &[u8] = include_bytes!("../assets/compare-response.bin");
1012 let (rem, resp) = parse_ldap_compare_response(DATA).expect("parsing failed");
1013 assert!(rem.is_empty());
1017 assert_eq!(resp.result_code, ResultCode::CompareTrue);
1018 }
1019
1020 #[test]
1021 fn test_parse_abandon_request() {
1022 const DATA: &[u8] = &[0x30, 0x06, 0x02, 0x01, 0x06, 0x50, 0x01, 0x05];
1023
1024 let (rem, msg) = LdapMessage::from_ber(DATA).expect("parsing failed");
1025 assert!(rem.is_empty());
1026 assert_eq!(msg.message_id, MessageID(6));
1027 assert!(matches!(
1028 msg.protocol_op,
1029 ProtocolOp::AbandonRequest(MessageID(5))
1030 ))
1031 }
1032}