use ldap3_proto::LdapMsg; use ldap3_proto::proto::LdapOp; use crate::db::{Database, DatabaseInterface}; use crate::ldap::{LdapClientState, LdapStream, LdapStreamError, op_bind, op_ext}; #[tracing::instrument(name = "ldap", skip(stream, db), fields(session = %stream.session))] pub async fn ldap_handler(mut stream: LdapStream, mut db: Database) { tracing::info! { remote_addr = ?stream.remote_addr, "New client connection" }; let mut state = LdapClientState::new(); loop { match stream.next().await { Ok(msg) => match ldap_handler_inner(&mut stream, msg, &mut state, &mut db).await { Ok(should_keep_alive) => { if !should_keep_alive { tracing::debug!("Finished connection"); return; } } Err(e) => { tracing::debug!( reason = ?e, "Failed to respond" ); return; } }, Err(e) => { tracing::debug!( reason = ?e, "Closing connection" ); return; } } } } /// Return true to keep the connection going, false to close it. #[tracing::instrument(name = "ldap-handler", skip(client_state, db, stream))] pub async fn ldap_handler_inner( stream: &mut LdapStream, msg: LdapMsg, client_state: &mut LdapClientState, db: &mut Database, ) -> Result { tracing::debug!(msg = ?msg, "Received LDAP message"); match msg { // Disconnect LdapMsg { msgid: _, op: LdapOp::UnbindRequest, ctrl: _, } => { client_state.unbind(); // TODO: keep the connection open? Ok(true) } LdapMsg { msgid, op: LdapOp::ExtendedRequest(ler), ctrl: _, } => { op_ext(stream, ler, msgid, client_state).await?; Ok(true) } LdapMsg { msgid, op: LdapOp::BindRequest(lbr), ctrl: _, } => { if let Some(bound_dn) = op_bind(stream, db, lbr, msgid).await? { tracing::debug!("Successful bind"); client_state.bind(bound_dn); Ok(true) } else { tracing::debug!("Unsuccessful bind"); // TODO: abort connection here? Ok(false) } } // Unsupported message _ => { tracing::warn!("Unsupported client message, closing connection"); Ok(false) } } }