Skip to content

Commit

Permalink
Merge pull request #683 from squidowl/fix/sasl
Browse files Browse the repository at this point in the history
Miscellaneous SASL Fixes
  • Loading branch information
andymandias authored Dec 30, 2024
2 parents 87371d2 + c8e447e commit 3a5f40c
Show file tree
Hide file tree
Showing 4 changed files with 49 additions and 10 deletions.
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,9 @@ Added:
- Timeout delay for notifications
- Case mapping support via `ISUPPORT`

Fixed:
- Long username & password combinations could cause SASL authentication to fail

# 2024.14 (2024-10-29)

Fixed:
Expand Down
19 changes: 14 additions & 5 deletions data/src/client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -770,7 +770,7 @@ impl Client {

log::warn!("[{}] capabilities not acknowledged: {caps}", self.server);

// End we didn't move to sasl or already ended
// End if we didn't move to sasl or already ended
if self.registration_step < RegistrationStep::Sasl {
self.registration_step = RegistrationStep::End;
self.handle.try_send(command!("CAP", "END"))?;
Expand Down Expand Up @@ -887,10 +887,9 @@ impl Client {
if let Some(sasl) = self.config.sasl.as_ref() {
log::info!("[{}] sasl auth: {}", self.server, sasl.command());

self.handle
.try_send(command!("AUTHENTICATE", sasl.param()))?;
self.registration_step = RegistrationStep::End;
self.handle.try_send(command!("CAP", "END"))?;
for param in sasl.params() {
self.handle.try_send(command!("AUTHENTICATE", param))?;
}
}
}
Command::Numeric(RPL_LOGGEDIN, args) => {
Expand Down Expand Up @@ -1762,6 +1761,16 @@ impl Client {

return Ok(events);
}
Command::Numeric(RPL_SASLSUCCESS, _) => {
self.registration_step = RegistrationStep::End;
self.handle.try_send(command!("CAP", "END"))?;
}
Command::Numeric(ERR_SASLFAIL | ERR_SASLTOOLONG, _) => {
log::debug!("[{}] sasl auth failed", self.server);

self.registration_step = RegistrationStep::End;
self.handle.try_send(command!("CAP", "END"))?;
}
_ => {}
}

Expand Down
35 changes: 31 additions & 4 deletions data/src/config/server.rs
Original file line number Diff line number Diff line change
Expand Up @@ -218,7 +218,9 @@ impl Sasl {
}
}

pub fn param(&self) -> String {
pub fn params(&self) -> Vec<String> {
const CHUNK_SIZE: usize = 400;

match self {
Sasl::Plain {
username, password, ..
Expand All @@ -229,10 +231,35 @@ impl Sasl {
.as_ref()
.expect("SASL password must exist at this point!");

base64::engine::general_purpose::STANDARD
.encode(format!("{username}\x00{username}\x00{password}"))
// Exclude authorization ID, to use the authentication ID as the authorization ID
// https://datatracker.ietf.org/doc/html/rfc4616#section-2
let encoding = base64::engine::general_purpose::STANDARD
.encode(format!("\x00{username}\x00{password}"));

let chunks = encoding
.as_bytes()
.chunks(CHUNK_SIZE)
.collect::<Vec<&[u8]>>();

let signal_end_of_response = chunks
.iter()
.last()
.is_none_or(|chunk| chunk.len() == CHUNK_SIZE);

let mut params = chunks
.into_iter()
.map(|chunk| {
String::from_utf8(chunk.into()).expect("chunks should be valid UTF-8")
})
.collect::<Vec<String>>();

if signal_end_of_response {
params.push("+".into())
}

params
}
Sasl::External { .. } => "+".into(),
Sasl::External { .. } => vec!["+".into()],
}
}

Expand Down
2 changes: 1 addition & 1 deletion src/screen/dashboard.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1880,7 +1880,7 @@ impl Dashboard {
&client::Notification::FileTransferRequest(request.from.clone()),
Some(server),
);

let query =
target::Query::parse(request.from.as_ref(), chantypes, statusmsg, casemapping).ok()?;

Expand Down

0 comments on commit 3a5f40c

Please sign in to comment.