diff --git a/src/op/bind.rs b/src/op/bind.rs index cfa9d65..e5ac34a 100644 --- a/src/op/bind.rs +++ b/src/op/bind.rs @@ -34,6 +34,33 @@ pub async fn bind( ) -> Result, LdapError> { 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(); debug!("Received bind request on DN: {}", lbr.dn); @@ -52,6 +79,7 @@ pub async fn bind( .iter() .find(|x| x.from.to_lowercase() == requested_domain) else { + // TODO: we should probably return an error to the client here debug!("No mapping found for domain {requested_domain}"); return Err(LdapError::InvalidQuery); };