use crate::error::*;
use crate::filter::*;
use crate::filter_parser::*;
use crate::ldap::*;
use der_parser::ber::*;
use nom::bytes::streaming::take;
use nom::combinator::{complete, map, map_res, opt, verify};
use nom::multi::{many0, many1};
use nom::{Err, Needed};
use std::borrow::Cow;
fn parse_message_id(i: &[u8]) -> Result<MessageID> {
map(parse_ber_u32, MessageID)(i).map_err(Err::convert)
}
pub(crate) fn parse_ldap_string(i: &[u8]) -> Result<LdapString> {
let (i, b) = parse_ldap_octet_string_as_slice(i)?;
let s = std::str::from_utf8(b).or(Err(Err::Error(LdapError::InvalidString)))?;
Ok((i, LdapString(Cow::Borrowed(s))))
}
#[inline]
fn parse_ldap_octet_string(i: &[u8]) -> Result<BerObject> {
parse_ber_octetstring(i).map_err(Err::convert)
}
#[inline]
pub(crate) fn parse_ldap_octet_string_as_slice(i: &[u8]) -> Result<&[u8]> {
map_res(parse_ldap_octet_string, |o| o.as_slice())(i)
}
#[inline]
fn parse_ldap_int_as_u32(i: &[u8]) -> Result<u32> {
let (i, res) = parse_ber_u32(i).map_err(Err::convert)?;
Ok((i, res))
}
#[inline]
fn parse_ldap_enum_as_u32(i: &[u8]) -> Result<u32> {
let (i, obj) = parse_ber_enum(i).map_err(Err::convert)?;
let scope = obj.as_u32().map_err(|e| Err::Error(LdapError::Ber(e)))?;
Ok((i, scope))
}
fn parse_ldap_dn(i: &[u8]) -> Result<LdapDN> {
let (i, obj) = parse_ber_octetstring(i).map_err(Err::convert)?;
let b = obj.as_slice().or(Err(Err::Error(LdapError::InvalidDN)))?;
let s = std::str::from_utf8(b).or(Err(Err::Error(LdapError::InvalidDN)))?;
Ok((i, LdapDN(Cow::Borrowed(s))))
}
fn parse_relative_ldap_dn(i: &[u8]) -> Result<RelativeLdapDN> {
let (i, obj) = parse_ber_octetstring(i).map_err(Err::convert)?;
let b = obj.as_slice().or(Err(Err::Error(LdapError::InvalidDN)))?;
let s = std::str::from_utf8(b).or(Err(Err::Error(LdapError::InvalidDN)))?;
Ok((i, RelativeLdapDN(Cow::Borrowed(s))))
}
fn parse_ldap_oid(i: &[u8]) -> Result<LdapOID> {
let (i, obj) = parse_ber_octetstring(i).map_err(Err::convert)?;
let b = obj.as_slice().or(Err(Err::Error(LdapError::InvalidDN)))?;
let s = std::str::from_utf8(b).or(Err(Err::Error(LdapError::InvalidDN)))?;
Ok((i, LdapOID(Cow::Borrowed(s))))
}
#[inline]
fn parse_ldap_uri(i: &[u8]) -> Result<LdapString> {
parse_ldap_string(i)
}
fn parse_ldap_result_content(i: &[u8]) -> Result<LdapResult> {
let (i, result_code) = map(parse_ldap_enum_as_u32, ResultCode)(i)?;
let (i, matched_dn) = parse_ldap_dn(i)?;
let (i, diagnostic_message) = parse_ldap_string(i)?;
let result = LdapResult {
result_code,
matched_dn,
diagnostic_message,
};
Ok((i, result))
}
pub fn parse_ldap_message(i: &[u8]) -> Result<LdapMessage> {
parse_ber_sequence_defined_g(|i, _| {
let (i, message_id) = parse_message_id(i)?;
let (_, header) = ber_read_element_header(i).map_err(Err::convert)?;
let (i, protocol_op) = match header.tag.0 {
0 => map(parse_ldap_bind_request, ProtocolOp::BindRequest)(i),
1 => map(parse_ldap_bind_response, ProtocolOp::BindResponse)(i),
2 => parse_ldap_unbind_request(i),
3 => map(parse_ldap_search_request, ProtocolOp::SearchRequest)(i),
4 => map(
parse_ldap_search_result_entry,
ProtocolOp::SearchResultEntry,
)(i),
5 => map(parse_ldap_search_result_done, ProtocolOp::SearchResultDone)(i),
6 => map(parse_ldap_modify_request, ProtocolOp::ModifyRequest)(i),
7 => map(parse_ldap_modify_response, ProtocolOp::ModifyResponse)(i),
8 => map(parse_ldap_add_request, ProtocolOp::AddRequest)(i),
9 => map(parse_ldap_add_response, ProtocolOp::AddResponse)(i),
10 => map(parse_ldap_del_request, ProtocolOp::DelRequest)(i),
11 => map(parse_ldap_del_response, ProtocolOp::DelResponse)(i),
12 => map(parse_ldap_moddn_request, ProtocolOp::ModDnRequest)(i),
13 => map(parse_ldap_moddn_response, ProtocolOp::ModDnResponse)(i),
14 => map(parse_ldap_compare_request, ProtocolOp::CompareRequest)(i),
15 => map(parse_ldap_compare_response, ProtocolOp::CompareResponse)(i),
16 => map(parse_ldap_abandon_request, ProtocolOp::AbandonRequest)(i),
19 => map(
parse_ldap_search_result_ref,
ProtocolOp::SearchResultReference,
)(i),
23 => map(parse_ldap_extended_request, ProtocolOp::ExtendedRequest)(i),
24 => map(parse_ldap_extended_response, ProtocolOp::ExtendedResponse)(i),
25 => map(
parse_ldap_intermediate_response,
ProtocolOp::IntermediateResponse,
)(i),
_ => {
Err(Err::Error(LdapError::InvalidMessageType))
}
}?;
let (i, controls) = opt(complete(parse_ber_tagged_implicit_g(
0,
|i, _hdr, _depth| many0(complete(parse_ldap_control))(i),
)))(i)?;
let msg = LdapMessage {
message_id,
protocol_op,
controls,
};
Ok((i, msg))
})(i)
}
pub fn parse_ldap_messages(i: &[u8]) -> Result<Vec<LdapMessage>> {
many1(complete(parse_ldap_message))(i)
}
fn parse_ldap_bind_request(i: &[u8]) -> Result<BindRequest> {
parse_ber_tagged_implicit_g(0, |content, _hdr, _depth| {
let i = content;
let (i, version) = verify(parse_ber_u32, |&n| n < 128)(i).map_err(Err::convert)?;
let version = version as u8;
let (i, name) = parse_ldap_dn(i)?;
let (i, authentication) = parse_authentication_choice(i)?;
let req = BindRequest {
version,
name,
authentication,
};
Ok((i, req))
})(i)
}
fn parse_ldap_bind_response(i: &[u8]) -> Result<BindResponse> {
parse_ber_tagged_implicit_g(1, |content, _hdr, _depth| {
let i = content;
let (i, result) = parse_ldap_result_content(i)?;
let (i, server_sasl_creds) =
opt(complete(parse_ber_tagged_implicit_g(7, |content, _, _| {
Ok((&b""[..], Cow::Borrowed(content)))
})))(i)?;
let req = BindResponse {
result,
server_sasl_creds,
};
Ok((i, req))
})(i)
}
fn parse_ldap_unbind_request(i: &[u8]) -> Result<ProtocolOp> {
parse_ber_tagged_implicit_g(2, |content, _hdr, _depth| {
let i = content;
if !i.is_empty() {
let (_, _) = parse_ber_null(i).map_err(Err::convert)?;
}
Ok((i, ProtocolOp::UnbindRequest))
})(i)
}
fn parse_ldap_search_request(i: &[u8]) -> Result<SearchRequest> {
parse_ber_tagged_implicit_g(3, |content, _hdr, _depth| {
let i = content;
let (i, base_object) = parse_ldap_dn(i)?;
let (i, scope) = map(parse_ldap_enum_as_u32, SearchScope)(i)?;
let (i, deref_aliases) = map(parse_ldap_enum_as_u32, DerefAliases)(i)?;
let (i, size_limit) = parse_ldap_int_as_u32(i)?;
let (i, time_limit) = parse_ldap_int_as_u32(i)?;
let (i, types_only) = map_res(parse_ber_bool, |o| o.as_bool())(i).map_err(Err::convert)?;
let (i, filter) = parse_ldap_filter(i)?;
let (i, attributes) = parse_attribute_selection(i)?;
let req = SearchRequest {
base_object,
scope,
deref_aliases,
size_limit,
time_limit,
types_only,
filter,
attributes,
};
Ok((i, req))
})(i)
}
fn parse_ldap_search_result_entry(i: &[u8]) -> Result<SearchResultEntry> {
parse_ber_tagged_implicit_g(4, |i, _hdr, _depth| {
let (i, object_name) = parse_ldap_dn(i)?;
let (i, attributes) = parse_partial_attribute_list(i)?;
let res = SearchResultEntry {
object_name,
attributes,
};
Ok((i, res))
})(i)
}
fn parse_ldap_search_result_done(i: &[u8]) -> Result<LdapResult> {
parse_ber_tagged_implicit_g(5, |i, _, _| parse_ldap_result_content(i))(i)
}
fn parse_ldap_modify_request(i: &[u8]) -> Result<ModifyRequest> {
parse_ber_tagged_implicit_g(6, |i, _hdr, _depth| {
let (i, object) = parse_ldap_dn(i)?;
let (i, changes) =
parse_ber_sequence_defined_g(|i, _| many1(complete(parse_ldap_change))(i))(i)?;
let res = ModifyRequest { object, changes };
Ok((i, res))
})(i)
}
fn parse_ldap_modify_response(i: &[u8]) -> Result<ModifyResponse> {
parse_ber_tagged_implicit_g(7, |i, _hdr, _depth| {
let (i, result) = parse_ldap_result_content(i)?;
let res = ModifyResponse { result };
Ok((i, res))
})(i)
}
fn parse_ldap_add_request(i: &[u8]) -> Result<AddRequest> {
parse_ber_tagged_implicit_g(8, |i, _hdr, _depth| {
let (i, entry) = parse_ldap_dn(i)?;
let (i, attributes) = parse_attribute_list(i)?;
let res = AddRequest { entry, attributes };
Ok((i, res))
})(i)
}
fn parse_ldap_add_response(i: &[u8]) -> Result<LdapResult> {
parse_ber_tagged_implicit_g(9, |i, _, _| parse_ldap_result_content(i))(i)
}
fn parse_ldap_del_request(i: &[u8]) -> Result<LdapDN> {
parse_ber_tagged_implicit_g(10, |i, _hdr, _depth| {
let s = std::str::from_utf8(i).or(Err(Err::Error(LdapError::InvalidDN)))?;
let oid = LdapDN(Cow::Borrowed(s));
Ok((&b""[..], oid))
})(i)
}
fn parse_ldap_del_response(i: &[u8]) -> Result<LdapResult> {
parse_ber_tagged_implicit_g(11, |i, _, _| parse_ldap_result_content(i))(i)
}
fn parse_ldap_moddn_request(i: &[u8]) -> Result<ModDnRequest> {
parse_ber_tagged_implicit_g(12, |i, _hdr, _depth| {
let (i, entry) = parse_ldap_dn(i)?;
let (i, newrdn) = parse_relative_ldap_dn(i)?;
let (i, deleteoldrdn) =
map_res(parse_ber_bool, |o| o.as_bool())(i).map_err(Err::convert)?;
let (i, newsuperior) = opt(complete(parse_ber_tagged_implicit_g(
0,
|i, _hdr, _depth| {
let s = std::str::from_utf8(i).or(Err(Err::Error(LdapError::InvalidDN)))?;
let oid = LdapDN(Cow::Borrowed(s));
Ok((&b""[..], oid))
},
)))(i)?;
let res = ModDnRequest {
entry,
newrdn,
deleteoldrdn,
newsuperior,
};
Ok((i, res))
})(i)
}
fn parse_ldap_moddn_response(i: &[u8]) -> Result<LdapResult> {
parse_ber_tagged_implicit_g(13, |i, _, _| parse_ldap_result_content(i))(i)
}
fn parse_ldap_compare_request(i: &[u8]) -> Result<CompareRequest> {
parse_ber_tagged_implicit_g(14, |i, _hdr, _depth| {
let (i, entry) = parse_ldap_dn(i)?;
let (i, ava) = parse_ldap_attribute_value_assertion(i)?;
let res = CompareRequest { entry, ava };
Ok((i, res))
})(i)
}
fn parse_ldap_compare_response(i: &[u8]) -> Result<LdapResult> {
parse_ber_tagged_implicit_g(15, |i, _, _| parse_ldap_result_content(i))(i)
}
fn parse_ldap_abandon_request(i: &[u8]) -> Result<MessageID> {
parse_ber_tagged_implicit_g(16, |i, _hdr, _depth| {
if i.is_empty() {
return Err(Err::Incomplete(Needed::new(1)));
}
let obj = BerObject::from_int_slice(i);
let id = obj.as_u32().map_err(|e| Err::Error(LdapError::Ber(e)))?;
Ok((i, MessageID(id)))
})(i)
}
fn parse_ldap_search_result_ref(i: &[u8]) -> Result<Vec<LdapString>> {
parse_ber_tagged_implicit_g(19, |i, _hdr, _depth| many1(complete(parse_ldap_uri))(i))(i)
}
fn parse_ldap_extended_request(i: &[u8]) -> Result<ExtendedRequest> {
parse_ber_tagged_implicit_g(23, |i, _hdr, _depth| {
let (i, request_name) = parse_ber_tagged_implicit_g(0, |i, _hdr, _depth| {
let s = std::str::from_utf8(i).or(Err(Err::Error(LdapError::InvalidDN)))?;
let oid = LdapOID(Cow::Borrowed(s));
Ok((&b""[..], oid))
})(i)?;
let (i, request_value) = opt(complete(parse_ber_tagged_implicit_g(
1,
|i, _hdr, _depth| Ok((&b""[..], Cow::Borrowed(i))),
)))(i)?;
let req = ExtendedRequest {
request_name,
request_value,
};
Ok((i, req))
})(i)
}
fn parse_ldap_extended_response(i: &[u8]) -> Result<ExtendedResponse> {
parse_ber_tagged_implicit_g(24, |i, _hdr, _depth| {
let (i, result) = parse_ldap_result_content(i)?;
let (i, request_name) = opt(complete(parse_ber_tagged_implicit_g(
10,
|i, _hdr, _depth| {
let s = std::str::from_utf8(i).or(Err(Err::Error(LdapError::InvalidDN)))?;
let oid = LdapOID(Cow::Borrowed(s));
Ok((&b""[..], oid))
},
)))(i)?;
let (i, request_value) = opt(complete(parse_ber_tagged_implicit_g(
11,
|i, _hdr, _depth| Ok((&b""[..], Cow::Borrowed(i))),
)))(i)?;
let resp = ExtendedResponse {
result,
request_name,
request_value,
};
Ok((i, resp))
})(i)
}
fn parse_ldap_intermediate_response(i: &[u8]) -> Result<IntermediateResponse> {
parse_ber_tagged_implicit_g(25, |i, _hdr, _depth| {
let (i, request_name) = opt(complete(parse_ber_tagged_implicit_g(
0,
|i, _hdr, _depth| {
let s = std::str::from_utf8(i).or(Err(Err::Error(LdapError::InvalidDN)))?;
let oid = LdapOID(Cow::Borrowed(s));
Ok((&b""[..], oid))
},
)))(i)?;
let (i, request_value) = opt(complete(parse_ber_tagged_implicit_g(
1,
|i, _hdr, _depth| Ok((&b""[..], Cow::Borrowed(i))),
)))(i)?;
let resp = IntermediateResponse {
request_name,
request_value,
};
Ok((i, resp))
})(i)
}
fn parse_authentication_choice(i: &[u8]) -> Result<AuthenticationChoice> {
let (rem, header) = ber_read_element_header(i).map_err(Err::convert)?;
match header.tag.0 {
0 => {
let sz = header
.len
.primitive()
.map_err(|e| Err::Error(LdapError::Ber(e)))?;
let (i, b) = take(sz)(rem)?;
Ok((i, AuthenticationChoice::Simple(Cow::Borrowed(b))))
}
3 => map(parse_sasl_credentials, AuthenticationChoice::Sasl)(rem),
_ => Err(Err::Error(LdapError::InvalidAuthenticationType)),
}
}
fn parse_sasl_credentials(i: &[u8]) -> Result<SaslCredentials> {
let (i, mechanism) = parse_ldap_string(i)?;
let (i, credentials) = opt(complete(map(
parse_ldap_octet_string_as_slice,
Cow::Borrowed,
)))(i)?;
let credentials = SaslCredentials {
mechanism,
credentials,
};
Ok((i, credentials))
}
fn parse_attribute_selection(i: &[u8]) -> Result<Vec<LdapString>> {
parse_ber_sequence_defined_g(|i, _| many0(complete(parse_ldap_string))(i))(i)
}
fn parse_partial_attribute_list(i: &[u8]) -> Result<Vec<PartialAttribute>> {
parse_ber_sequence_defined_g(|i, _| many0(complete(parse_ldap_partial_attribute))(i))(i)
}
fn parse_attribute_list(i: &[u8]) -> Result<Vec<Attribute>> {
parse_ber_sequence_defined_g(|i, _| many0(complete(parse_ldap_attribute))(i))(i)
}
fn parse_ldap_change(i: &[u8]) -> Result<Change> {
parse_ber_sequence_defined_g(|i, _| {
let (i, operation) = map(parse_ldap_enum_as_u32, Operation)(i)?;
let (i, modification) = parse_ldap_partial_attribute(i)?;
let change = Change {
operation,
modification,
};
Ok((i, change))
})(i)
}
fn parse_ldap_control(i: &[u8]) -> Result<Control> {
parse_ber_sequence_defined_g(|i, _| {
let (i, control_type) = parse_ldap_oid(i)?;
let (i, maybe_critical) =
opt(complete(map_res(parse_ber_bool, |o| o.as_bool())))(i).map_err(Err::convert)?;
let criticality = maybe_critical.unwrap_or(false);
let (i, control_value) = opt(complete(map(
parse_ldap_octet_string_as_slice,
Cow::Borrowed,
)))(i)?;
let control = Control {
control_type,
criticality,
control_value,
};
Ok((i, control))
})(i)
}
#[cfg(test)]
mod tests {
use super::*;
use der_parser::oid;
use hex_literal::hex;
#[test]
fn test_parse_bind_request() {
const DATA: &[u8] = include_bytes!("../assets/bind_request.bin");
let (rem, req) = parse_ldap_bind_request(DATA).expect("parsing failed");
assert!(rem.is_empty());
assert_eq!(&req.name.0, "xxxxxxxxxxx@xx.xxx.xxxxx.net");
assert_eq!(
req.authentication,
AuthenticationChoice::Simple(Cow::Borrowed(b"passwor8d1"))
);
}
#[test]
fn test_parse_bind_request_sasl() {
const DATA: &[u8] = include_bytes!("../assets/bind_request_sasl.bin");
let (rem, req) = parse_ldap_bind_request(DATA).expect("parsing failed");
assert!(rem.is_empty());
assert_eq!(&req.name.0, "");
if let AuthenticationChoice::Sasl(sasl_credentials) = &req.authentication {
assert_eq!(&sasl_credentials.mechanism.0, "GSS-SPNEGO");
} else {
panic!("wrong authentication type");
}
}
#[test]
fn test_parse_bind_response_minimal() {
const DATA: &[u8] = &hex!("61 84 00 00 00 07 0a 01 00 04 00 04 00");
let (rem, resp) = parse_ldap_bind_response(DATA).expect("parsing failed");
assert!(rem.is_empty());
assert_eq!(resp.result.result_code, ResultCode::Success);
}
#[test]
fn test_parse_bind_response_sasl() {
const DATA: &[u8] = include_bytes!("../assets/bind_response_sasl.bin");
let (rem, resp) = parse_ldap_bind_response(DATA).expect("parsing failed");
assert!(rem.is_empty());
assert_eq!(resp.result.result_code, ResultCode::Success);
assert!(resp.server_sasl_creds.is_some());
}
#[test]
fn test_parse_unbind_request() {
const DATA: &[u8] = &hex!("42 00");
let (rem, req) = parse_ldap_unbind_request(DATA).expect("parsing failed");
assert!(rem.is_empty());
assert_eq!(req, ProtocolOp::UnbindRequest);
}
#[test]
fn test_parse_search_request() {
const DATA: &[u8] = include_bytes!("../assets/search_request.bin");
let (rem, resp) = parse_ldap_search_request(DATA).expect("parsing failed");
assert!(rem.is_empty());
assert_eq!(&resp.base_object.0, "DC=xx,DC=xxx,DC=xxxxx,DC=net");
assert_eq!(resp.scope, SearchScope::WholeSubtree);
assert_eq!(resp.attributes.len(), 1);
}
#[test]
fn test_parse_search_result_entry() {
const DATA: &[u8] = include_bytes!("../assets/search_result_entry.bin");
let (rem, resp) = parse_ldap_search_result_entry(DATA).expect("parsing failed");
assert!(rem.is_empty());
assert_eq!(resp.attributes.len(), 1);
}
#[test]
fn test_parse_search_result_done() {
const DATA: &[u8] = include_bytes!("../assets/search_result_done.bin");
let (rem, resp) = parse_ldap_search_result_done(DATA).expect("parsing failed");
assert!(rem.is_empty());
assert_eq!(resp.result_code, ResultCode::Success);
}
#[test]
fn test_parse_search_result_ref() {
const DATA: &[u8] = include_bytes!("../assets/search_result_ref.bin");
let (rem, v) = parse_ldap_search_result_ref(DATA).expect("parsing failed");
assert!(rem.is_empty());
assert_eq!(v.len(), 1);
assert_eq!(
&v[0].0,
"ldap://DomainDnsZones.rccad.net/DC=DomainDnsZones,DC=rccad,DC=net"
);
}
#[test]
fn test_parse_extended_req() {
const DATA: &[u8] = include_bytes!("../assets/extended-req.bin");
let (rem, req) = parse_ldap_extended_request(DATA).expect("parsing failed");
assert!(rem.is_empty());
assert_eq!(
req.request_name.0,
oid!(1.3.6 .1 .4 .1 .1466 .20037).to_string()
);
assert!(req.request_value.is_none());
}
#[test]
fn test_parse_extended_response() {
const DATA: &[u8] = &hex!("78 07 0a 01 00 04 00 04 00");
let (rem, resp) = parse_ldap_extended_response(DATA).expect("parsing failed");
assert!(rem.is_empty());
assert_eq!(resp.result.result_code, ResultCode::Success);
}
#[test]
fn test_parse_modify_request() {
const DATA: &[u8] = include_bytes!("../assets/modify-request.bin");
let (rem, req) = parse_ldap_modify_request(DATA).expect("parsing failed");
assert!(rem.is_empty());
assert_eq!(&req.object.0, "cn=username1,ou=users,dc=xxx,dc=internet");
assert_eq!(req.changes.len(), 1);
assert_eq!(req.changes[0].modification.attr_type.0, "description");
}
#[test]
fn test_parse_modify_response() {
const DATA: &[u8] = include_bytes!("../assets/modify-response.bin");
let (rem, resp) = parse_ldap_modify_response(DATA).expect("parsing failed");
assert!(rem.is_empty());
assert_eq!(resp.result.result_code, ResultCode::Success);
}
#[test]
fn test_parse_add_request() {
const DATA: &[u8] = include_bytes!("../assets/add-request.bin");
let (rem, req) = parse_ldap_add_request(DATA).expect("parsing failed");
assert!(rem.is_empty());
assert_eq!(&req.entry.0, "cn=username1,ou=users,dc=xxx,dc=internet");
assert_eq!(req.attributes.len(), 4);
}
#[test]
fn test_parse_add_response() {
const DATA: &[u8] = include_bytes!("../assets/add-response.bin");
let (rem, resp) = parse_ldap_add_response(DATA).expect("parsing failed");
assert!(rem.is_empty());
assert_eq!(resp.result_code, ResultCode::Success);
}
#[test]
fn test_parse_del_request() {
const DATA: &[u8] = include_bytes!("../assets/del-request.bin");
let (rem, req) = parse_ldap_del_request(DATA).expect("parsing failed");
assert!(rem.is_empty());
assert_eq!(&req.0, "cn=username2,ou=users2,dc=xxx,dc=internet");
}
#[test]
fn test_parse_del_response() {
const DATA: &[u8] = include_bytes!("../assets/del-response.bin");
let (rem, resp) = parse_ldap_del_response(DATA).expect("parsing failed");
assert!(rem.is_empty());
assert_eq!(resp.result_code, ResultCode::Success);
}
#[test]
fn test_parse_moddn_request() {
const DATA: &[u8] = include_bytes!("../assets/moddn-request.bin");
let (rem, req) = parse_ldap_moddn_request(DATA).expect("parsing failed");
assert!(rem.is_empty());
assert_eq!(&req.entry.0, "cn=username1,ou=users,dc=xxx,dc=internet");
assert_eq!(&req.newrdn.0, "cn=username2");
assert!(req.deleteoldrdn);
assert_eq!(&req.newsuperior.unwrap().0, "ou=users,dc=xxx,dc=internet");
}
#[test]
fn test_parse_moddn_response() {
const DATA: &[u8] = include_bytes!("../assets/moddn-response.bin");
let (rem, resp) = parse_ldap_moddn_response(DATA).expect("parsing failed");
assert!(rem.is_empty());
assert_eq!(resp.result_code, ResultCode::Success);
}
#[test]
fn test_parse_compare_request() {
const DATA: &[u8] = include_bytes!("../assets/compare-request.bin");
let (rem, req) = parse_ldap_compare_request(DATA).expect("parsing failed");
assert!(rem.is_empty());
assert_eq!(&req.entry.0, "cn=username2,ou=users2,dc=xxx,dc=internet");
assert_eq!(&req.ava.attribute_desc.0, "cn");
}
#[test]
fn test_parse_compare_response() {
const DATA: &[u8] = include_bytes!("../assets/compare-response.bin");
let (rem, resp) = parse_ldap_compare_response(DATA).expect("parsing failed");
assert!(rem.is_empty());
assert_eq!(resp.result_code, ResultCode::CompareTrue);
}
}