aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--flake.nix32
-rw-r--r--src/auth.rs106
-rw-r--r--src/lmtp.rs4
3 files changed, 74 insertions, 68 deletions
diff --git a/flake.nix b/flake.nix
index 6cfad79..0c0f783 100644
--- a/flake.nix
+++ b/flake.nix
@@ -54,21 +54,6 @@
];
};
- pkgVanilla = import nixpkgs { system = "x86_64-linux"; };
-
- shell = pkgVanilla.mkShell {
- buildInputs = [
- cargo2nix.packages.x86_64-linux.default
- fenix.packages.x86_64-linux.minimal.toolchain
- fenix.packages.x86_64-linux.rust-analyzer
- ];
- shellHook = ''
- echo "AEROGRAME DEVELOPMENT SHELL ${fenix.packages.x86_64-linux.minimal.rustc}"
- export RUST_SRC_PATH="${fenix.packages.x86_64-linux.latest.rust-src}/lib/rustlib/src/rust/library"
- export RUST_ANALYZER_INTERNALS_DO_NOT_USE='this is unstable'
- '';
- };
-
rustTarget = if targetHost == "armv6l-unknown-linux-musleabihf" then "arm-unknown-linux-musleabihf" else targetHost;
# release builds
@@ -180,9 +165,9 @@
version = crate.version;
};
packages = {
+ inherit fhs container;
debug = (rustDebug.workspace.aerogramme {}).bin;
aerogramme = bin;
- container = container;
default = self.packages.${targetHost}.aerogramme;
};
});
@@ -197,6 +182,20 @@
};
alba = albatros.packages.x86_64-linux.alba;
+ # Shell
+ shell = gpkgs.mkShell {
+ buildInputs = [
+ cargo2nix.packages.x86_64-linux.default
+ fenix.packages.x86_64-linux.minimal.toolchain
+ fenix.packages.x86_64-linux.rust-analyzer
+ ];
+ shellHook = ''
+ echo "AEROGRAME DEVELOPMENT SHELL ${fenix.packages.x86_64-linux.minimal.rustc}"
+ export RUST_SRC_PATH="${fenix.packages.x86_64-linux.latest.rust-src}/lib/rustlib/src/rust/library"
+ export RUST_ANALYZER_INTERNALS_DO_NOT_USE='this is unstable'
+ '';
+ };
+
# Used only to fetch the "version"
version = platformArtifacts.meta.x86_64-unknown-linux-musl.version;
@@ -224,6 +223,7 @@
in
{
+ devShells.x86_64-linux.default = shell;
packages = {
x86_64-linux = {
inherit build push;
diff --git a/src/auth.rs b/src/auth.rs
index 81ba496..064c90c 100644
--- a/src/auth.rs
+++ b/src/auth.rs
@@ -202,7 +202,41 @@ enum State {
const SERVER_MAJOR: u64 = 1;
const SERVER_MINOR: u64 = 2;
+const EMPTY_AUTHZ: &[u8] = &[];
impl State {
+ async fn try_auth_plain<'a>(&self, data: &'a [u8], login: &ArcLoginProvider) -> AuthRes {
+ // Check that we can extract user's login+pass
+ let (ubin, pbin) = match auth_plain(&data) {
+ Ok(([], (authz, user, pass))) if authz == user || authz == EMPTY_AUTHZ => (user, pass),
+ Ok(_) => {
+ tracing::error!("Impersonating user is not supported");
+ return AuthRes::Failed(None, None);
+ }
+ Err(e) => {
+ tracing::error!(err=?e, "Could not parse the SASL PLAIN data chunk");
+ return AuthRes::Failed(None, None);
+ }
+ };
+
+ // Try to convert it to UTF-8
+ let (user, password) = match (std::str::from_utf8(ubin), std::str::from_utf8(pbin)) {
+ (Ok(u), Ok(p)) => (u, p),
+ _ => {
+ tracing::error!("Username or password contain invalid UTF-8 characters");
+ return AuthRes::Failed(None, None);
+ }
+ };
+
+ // Try to connect user
+ match login.login(user, password).await {
+ Ok(_) => AuthRes::Success(user.to_string()),
+ Err(e) => {
+ tracing::warn!(err=?e, "login failed");
+ AuthRes::Failed(Some(user.to_string()), None)
+ }
+ }
+ }
+
async fn progress(&mut self, cmd: ClientCommand, login: &ArcLoginProvider) {
let new_state = 'state: {
match (std::mem::replace(self, State::Error), cmd) {
@@ -219,8 +253,18 @@ impl State {
Self::HandshakeDone
}
- (Self::HandshakeDone { .. }, ClientCommand::Auth { id, mech, .. })
- | (Self::AuthDone { .. }, ClientCommand::Auth { id, mech, .. }) => {
+ (
+ Self::HandshakeDone { .. },
+ ClientCommand::Auth {
+ id, mech, options, ..
+ },
+ )
+ | (
+ Self::AuthDone { .. },
+ ClientCommand::Auth {
+ id, mech, options, ..
+ },
+ ) => {
if mech != Mechanism::Plain {
tracing::error!(mechanism=?mech, "Unsupported Authentication Mechanism");
break 'state Self::AuthDone {
@@ -229,7 +273,13 @@ impl State {
};
}
- Self::AuthPlainProgress { id }
+ match options.last() {
+ Some(AuthOption::Resp(data)) => Self::AuthDone {
+ id,
+ res: self.try_auth_plain(&data, login).await,
+ },
+ _ => Self::AuthPlainProgress { id },
+ }
}
(Self::AuthPlainProgress { id }, ClientCommand::Cont { id: cid, data }) => {
// Check that ID matches
@@ -245,53 +295,9 @@ impl State {
};
}
- // Check that we can extract user's login+pass
- let (ubin, pbin) = match auth_plain(&data) {
- Ok(([], ([], user, pass))) => (user, pass),
- Ok(_) => {
- tracing::error!("Impersonating user is not supported");
- break 'state Self::AuthDone {
- id,
- res: AuthRes::Failed(None, None),
- };
- }
- Err(e) => {
- tracing::error!(err=?e, "Could not parse the SASL PLAIN data chunk");
- break 'state Self::AuthDone {
- id,
- res: AuthRes::Failed(None, None),
- };
- }
- };
-
- // Try to convert it to UTF-8
- let (user, password) =
- match (std::str::from_utf8(ubin), std::str::from_utf8(pbin)) {
- (Ok(u), Ok(p)) => (u, p),
- _ => {
- tracing::error!(
- "Username or password contain invalid UTF-8 characters"
- );
- break 'state Self::AuthDone {
- id,
- res: AuthRes::Failed(None, None),
- };
- }
- };
-
- // Try to connect user
- match login.login(user, password).await {
- Ok(_) => Self::AuthDone {
- id,
- res: AuthRes::Success(user.to_string()),
- },
- Err(e) => {
- tracing::warn!(err=?e, "login failed");
- Self::AuthDone {
- id,
- res: AuthRes::Failed(Some(user.to_string()), None),
- }
- }
+ Self::AuthDone {
+ id,
+ res: self.try_auth_plain(&data, login).await,
}
}
_ => {
diff --git a/src/lmtp.rs b/src/lmtp.rs
index 28c4d51..dcd4bcc 100644
--- a/src/lmtp.rs
+++ b/src/lmtp.rs
@@ -16,7 +16,7 @@ use tokio::select;
use tokio::sync::watch;
use tokio_util::compat::*;
-use smtp_message::{Email, EscapedDataReader, DataUnescaper, Reply, ReplyCode};
+use smtp_message::{DataUnescaper, Email, EscapedDataReader, Reply, ReplyCode};
use smtp_server::{reply, Config, ConnectionMetadata, Decision, MailMetadata};
use crate::config::*;
@@ -186,7 +186,7 @@ impl Config for LmtpServer {
// Unescape email, shrink it also to remove last dot
let unesc_res = DataUnescaper::new(true).unescape(&mut text);
text.truncate(unesc_res.written);
- tracing::debug!(prev_sz=raw_size, new_sz=text.len(), "unescaped");
+ tracing::debug!(prev_sz = raw_size, new_sz = text.len(), "unescaped");
let encrypted_message = match EncryptedMessage::new(text) {
Ok(x) => Arc::new(x),