diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/config.rs | 14 | ||||
-rw-r--r-- | src/imap/mod.rs | 40 | ||||
-rw-r--r-- | src/main.rs | 9 | ||||
-rw-r--r-- | src/server.rs | 18 |
4 files changed, 67 insertions, 14 deletions
diff --git a/src/config.rs b/src/config.rs index b9c1f09..0269773 100644 --- a/src/config.rs +++ b/src/config.rs @@ -9,7 +9,7 @@ use serde::{Deserialize, Serialize}; #[derive(Serialize, Deserialize, Debug, Clone)] pub struct CompanionConfig { pub pid: Option<PathBuf>, - pub imap: ImapConfig, + pub imap: ImapUnsecureConfig, #[serde(flatten)] pub users: LoginStaticConfig, @@ -18,8 +18,9 @@ pub struct CompanionConfig { #[derive(Serialize, Deserialize, Debug, Clone)] pub struct ProviderConfig { pub pid: Option<PathBuf>, - pub imap: ImapConfig, - pub lmtp: LmtpConfig, + pub imap: Option<ImapConfig>, + pub imap_unsecure: Option<ImapUnsecureConfig>, + pub lmtp: Option<LmtpConfig>, pub users: UserManagement, } @@ -40,6 +41,13 @@ pub struct LmtpConfig { #[derive(Serialize, Deserialize, Debug, Clone)] pub struct ImapConfig { pub bind_addr: SocketAddr, + pub certs: PathBuf, + pub key: PathBuf, +} + +#[derive(Serialize, Deserialize, Debug, Clone)] +pub struct ImapUnsecureConfig { + pub bind_addr: SocketAddr, } #[derive(Serialize, Deserialize, Debug, Clone)] diff --git a/src/imap/mod.rs b/src/imap/mod.rs index 3f685e6..b08a4ff 100644 --- a/src/imap/mod.rs +++ b/src/imap/mod.rs @@ -26,8 +26,10 @@ use imap_codec::imap_types::response::{Code, CommandContinuationRequest, Respons use imap_codec::imap_types::{core::Text, response::Greeting}; use imap_flow::server::{ServerFlow, ServerFlowEvent, ServerFlowOptions}; use imap_flow::stream::AnyStream; +use tokio_rustls::TlsAcceptor; +use rustls_pemfile::{certs, private_key}; -use crate::config::ImapConfig; +use crate::config::{ImapConfig, ImapUnsecureConfig}; use crate::imap::capability::ServerCapability; use crate::imap::request::Request; use crate::imap::response::{Body, ResponseOrIdle}; @@ -39,6 +41,7 @@ pub struct Server { bind_addr: SocketAddr, login_provider: ArcLoginProvider, capabilities: ServerCapability, + tls: Option<TlsAcceptor>, } #[derive(Clone)] @@ -49,11 +52,29 @@ struct ClientContext { server_capabilities: ServerCapability, } -pub fn new(config: ImapConfig, login: ArcLoginProvider) -> Server { +pub fn new(config: ImapConfig, login: ArcLoginProvider) -> Result<Server> { + let loaded_certs = certs(&mut std::io::BufReader::new(std::fs::File::open(config.certs)?)).collect::<Result<Vec<_>, _>>()?; + let loaded_key = private_key(&mut std::io::BufReader::new(std::fs::File::open(config.key)?))?.unwrap(); + + let tls_config = rustls::ServerConfig::builder() + .with_no_client_auth() + .with_single_cert(loaded_certs, loaded_key)?; + let acceptor = TlsAcceptor::from(Arc::new(tls_config)); + + Ok(Server { + bind_addr: config.bind_addr, + login_provider: login, + capabilities: ServerCapability::default(), + tls: Some(acceptor), + }) +} + +pub fn new_unsecure(config: ImapUnsecureConfig, login: ArcLoginProvider) -> Server { Server { bind_addr: config.bind_addr, login_provider: login, capabilities: ServerCapability::default(), + tls: None, } } @@ -78,6 +99,19 @@ impl Server { _ = must_exit.changed() => continue, }; tracing::info!("IMAP: accepted connection from {}", remote_addr); + let stream = match self.tls.clone() { + Some(acceptor) => { + let stream = match acceptor.accept(socket).await { + Ok(v) => v, + Err(e) => { + tracing::error!(err=?e, "TLS negociation failed"); + continue; + } + }; + AnyStream::new(stream) + }, + None => AnyStream::new(socket), + }; let client = ClientContext { addr: remote_addr.clone(), @@ -85,7 +119,7 @@ impl Server { must_exit: must_exit.clone(), server_capabilities: self.capabilities.clone(), }; - let conn = tokio::spawn(NetLoop::handler(client, AnyStream::new(socket))); + let conn = tokio::spawn(NetLoop::handler(client, stream)); connections.push(conn); } drop(tcp); diff --git a/src/main.rs b/src/main.rs index a7462bc..3e3674c 100644 --- a/src/main.rs +++ b/src/main.rs @@ -167,13 +167,14 @@ async fn main() -> Result<()> { use std::net::*; AnyConfig::Provider(ProviderConfig { pid: None, - imap: ImapConfig { + imap: None, + imap_unsecure: Some(ImapUnsecureConfig { bind_addr: SocketAddr::new(IpAddr::V6(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1)), 1143), - }, - lmtp: LmtpConfig { + }), + lmtp: Some(LmtpConfig { bind_addr: SocketAddr::new(IpAddr::V6(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1)), 1025), hostname: "example.tld".to_string(), - }, + }), users: UserManagement::Demo, }) } else { diff --git a/src/server.rs b/src/server.rs index bd2fd5d..0df1caf 100644 --- a/src/server.rs +++ b/src/server.rs @@ -15,6 +15,7 @@ use crate::login::{demo_provider::*, ldap_provider::*, static_provider::*}; pub struct Server { lmtp_server: Option<Arc<LmtpServer>>, + imap_unsecure_server: Option<imap::Server>, imap_server: Option<imap::Server>, pid_file: Option<PathBuf>, } @@ -25,10 +26,11 @@ impl Server { let login = Arc::new(StaticLoginProvider::new(config.users).await?); let lmtp_server = None; - let imap_server = Some(imap::new(config.imap, login.clone())); + let imap_unsecure_server = Some(imap::new_unsecure(config.imap, login.clone())); Ok(Self { lmtp_server, - imap_server, + imap_unsecure_server, + imap_server: None, pid_file: config.pid, }) } @@ -41,11 +43,13 @@ impl Server { UserManagement::Ldap(x) => Arc::new(LdapLoginProvider::new(x)?), }; - let lmtp_server = Some(LmtpServer::new(config.lmtp, login.clone())); - let imap_server = Some(imap::new(config.imap, login.clone())); + let lmtp_server = config.lmtp.map(|lmtp| LmtpServer::new(lmtp, login.clone())); + let imap_unsecure_server = config.imap_unsecure.map(|imap| imap::new_unsecure(imap, login.clone())); + let imap_server = config.imap.map(|imap| imap::new(imap, login.clone())).transpose()?; Ok(Self { lmtp_server, + imap_unsecure_server, imap_server, pid_file: config.pid, }) @@ -80,6 +84,12 @@ impl Server { } }, async { + match self.imap_unsecure_server { + None => Ok(()), + Some(s) => s.run(exit_signal.clone()).await, + } + }, + async { match self.imap_server { None => Ok(()), Some(s) => s.run(exit_signal.clone()).await, |