Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 4 additions & 3 deletions sable_ircd/src/command/handlers/services/sasl.rs
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ async fn handle_authenticate(

match services
.require()?
.send_remote_request(authenticate_request.into())
.send_remote_request(authenticate_request.clone().into())
.await
{
Ok(RemoteServerResponse::Services(RemoteServicesServerResponse::Authenticate(status))) => {
Expand Down Expand Up @@ -95,8 +95,9 @@ async fn handle_authenticate(
}
}
}
_ => {
response.numeric(make_numeric!(SaslAborted));
msg => {
tracing::error!("Unexpected services response to {authenticate_request:?}: {msg:?}");
response.numeric(make_numeric!(UnknownError, "Unknown SASL error"));
}
}
Ok(())
Expand Down
1 change: 1 addition & 0 deletions sable_ircd/src/messages/numeric.rs
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@ define_messages! {
374(EndOfInfo) => { () => ":End of /INFO list" },


400(UnknownError) => { (reason: &str) => ":{reason}" },
401(NoSuchTarget) => { (unknown: &str) => "{unknown} :No such nick/channel" },
402(NoSuchServer) => { (server_name: &ServerName) => "{server_name} :No such server" },
403(NoSuchChannel) => { (chname: &ChannelName) => "{chname} :No such channel" },
Expand Down
19 changes: 14 additions & 5 deletions sable_services/src/server/command/sasl_commands.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,18 +23,27 @@ impl<DB: DatabaseConnection> ServicesServer<DB> {
}

pub fn authenticate(&self, session_id: SaslSessionId, data: Vec<u8>) -> CommandResult {
let Some(session) = self.sasl_sessions.get(&session_id) else {
let session_entry = self.sasl_sessions.entry(session_id);
let dashmap::mapref::entry::Entry::Occupied(session_entry) = session_entry else {
return Ok(Authenticate(Fail).into());
};
let session = session_entry.get();

let Some(mechanism) = self.sasl_mechanisms.get(&session.mechanism) else {
self.sasl_sessions.remove(&session_id);
session_entry.remove();
return Ok(Authenticate(Fail).into());
};

let response = mechanism.step(self, &session, data)?;

Ok(Authenticate(response).into())
match mechanism.step(self, session, data) {
Ok(response) => Ok(Authenticate(response).into()),
Err(e) => {
tracing::debug!(?session_id, "SASL {} step failed: {e}", mechanism.name());
// Equivalent to self.fail_authenticate(session_id) but we can't call it here
// because we already have the lock.
session_entry.remove();
Ok(Authenticate(Fail).into())
}
}
}

pub fn abort_authenticate(&self, session_id: SaslSessionId) -> CommandResult {
Expand Down
2 changes: 2 additions & 0 deletions sable_services/src/server/sasl/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ use AuthenticateStatus::*;
pub type SaslResult = Result<AuthenticateStatus, CommandError>;

pub trait SaslMechanism<DB>: Send + Sync + 'static {
fn name(&self) -> String;

fn step(&self, server: &ServicesServer<DB>, session: &SaslSession, data: Vec<u8>)
-> SaslResult;
}
Expand Down
4 changes: 4 additions & 0 deletions sable_services/src/server/sasl/plain.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,10 @@ use sable_network::prelude::*;
pub struct SaslPlain;

impl<DB: DatabaseConnection> SaslMechanism<DB> for SaslPlain {
fn name(&self) -> String {
"PLAIN".to_string()
}

fn step(
&self,
server: &ServicesServer<DB>,
Expand Down
Loading