feat: Support anonymous bind (for ldapsearch compatibility)

This commit is contained in:
selfhoster selfhoster 2026-08-28 11:30:22 +02:00
commit 2a087f922d

View file

@ -34,6 +34,33 @@ pub async fn bind<W: AsyncWrite + Unpin>(
) -> Result<Option<ClientState>, LdapError> { ) -> Result<Option<ClientState>, LdapError> {
trace!("{:?}", lbr); trace!("{:?}", lbr);
if lbr.dn == "" {
// Here we pretend to have successfully bound so that
// a client performing an anonymous bind can proceed with
// more requests (such as a search request).
// This supports ldap search which always performs a bind.
let resp_msg = LdapMsg {
msgid,
op: LdapOp::BindResponse(LdapBindResponse {
res: LdapResult {
code: LdapResultCode::Success,
matcheddn: "".to_string(),
message: "".to_string(),
referral: vec![],
},
saslcreds: None,
}),
ctrl: vec![],
};
w.send(resp_msg).await.map_err(|err| {
error!("Unable to send response: {err}");
LdapError::Transport
})?;
// We still treat the client as unbounded because it doesn't
// have a session to a backend.
return Ok(Some(ClientState::Unbound));
}
let request_dn = lbr.dn.clone(); let request_dn = lbr.dn.clone();
debug!("Received bind request on DN: {}", lbr.dn); debug!("Received bind request on DN: {}", lbr.dn);
@ -52,6 +79,7 @@ pub async fn bind<W: AsyncWrite + Unpin>(
.iter() .iter()
.find(|x| x.from.to_lowercase() == requested_domain) .find(|x| x.from.to_lowercase() == requested_domain)
else { else {
// TODO: we should probably return an error to the client here
debug!("No mapping found for domain {requested_domain}"); debug!("No mapping found for domain {requested_domain}");
return Err(LdapError::InvalidQuery); return Err(LdapError::InvalidQuery);
}; };