aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/config.rs14
-rw-r--r--src/imap/mod.rs40
-rw-r--r--src/main.rs9
-rw-r--r--src/server.rs18
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,