Steps towards encryption

- Added certstore and retrieval of the local trust root.
- Major work on keeping the context between calls to the milter.
- Added a context for an email in processing
- Added Husk specific errors
This commit is contained in:
Malte Meiboom
2025-12-09 12:11:07 +01:00
parent 0f3a05e811
commit 56647806b7
10 changed files with 197 additions and 40 deletions
+42 -24
View File
@@ -25,13 +25,15 @@ use indymilter::{
};
use crate::types::husk_context::HuskContext;
use crate::config::HuskConfig;
use crate::config::{HuskConfig, HuskConfigContainer};
pub struct Daemon { }
impl Daemon {
pub async fn run(config: &HuskConfig) -> anyhow::Result<()> {
pub async fn run(config_container: HuskConfigContainer) -> anyhow::Result<()> {
let config: HuskConfig = config_container.clone().into();
let listener = TcpListener::bind(&config.connection)
.await
@@ -40,7 +42,7 @@ impl Daemon {
let callbacks = Callbacks::new()
.on_negotiate(|cx, actions, opts| Box::pin(Self::handle_negotiate(cx, actions, opts)))
.on_connect(|cx, hostname, socket_info| Box::pin(Self::handle_connect(cx, hostname, socket_info)))
.on_helo(|cx, hostname| Box::pin(Self::handle_helo(cx, hostname)))
.on_helo(move |cx, hostname| Box::pin(Self::handle_helo(cx, config_container.clone(), hostname)))
.on_mail(|cx, args| Box::pin(Self::handle_mail(cx, args)))
.on_rcpt(|cx, args| Box::pin(Self::handle_rcpt(cx, args)))
.on_data(|cx| Box::pin(Self::handle_data(cx)))
@@ -62,7 +64,7 @@ impl Daemon {
}
async fn handle_negotiate(
_cx: &mut NegotiateContext<HuskContext>,
_cx: &mut NegotiateContext<HuskContext<'_>>,
actions: Actions,
opts: ProtoOpts,
) -> Status {
@@ -72,7 +74,7 @@ impl Daemon {
}
async fn handle_connect(
_cx: &mut Context<HuskContext>,
_cx: &mut Context<HuskContext<'_>>,
hostname: CString,
socket_info: SocketInfo,
) -> Status {
@@ -82,15 +84,28 @@ impl Daemon {
Status::Continue
}
async fn handle_helo(_cx: &mut Context<HuskContext>, hostname: CString) -> Status {
async fn handle_helo(cx: &mut Context<HuskContext<'_>>, config_container: HuskConfigContainer, hostname: CString) -> Status {
log::debug!("HELO: hostname: {hostname:?}");
Status::Continue
let config: HuskConfig = config_container.into();
// setup Context
match HuskContext::new(&config) {
Ok(context) => {
cx.data = Some(context).take();
Status::Continue
},
Err(e) => {
log::error!("{}", e);
Status::Tempfail
}
}
}
async fn handle_mail(cx: &mut Context<HuskContext>, args: Vec<CString>) -> Status {
async fn handle_mail(cx: &mut Context<HuskContext<'_>>, args: Vec<CString>) -> Status {
log::debug!("MAIL: {args:?}");
// XXX
let sender = match args.first() {
Some(cs) => {
match cs.to_str() {
@@ -101,68 +116,71 @@ impl Daemon {
None => { "missing".to_string() }
};
// setup Context
if let Some(mut context) = HuskContext::new() {
if let Some(ref mut context) = cx.data {
context.set_sender(sender);
cx.data = Some(context).take();
Status::Continue
} else {
Status::Tempfail
}
Status::Continue
}
async fn handle_rcpt(_cx: &mut Context<HuskContext>, args: Vec<CString>) -> Status {
async fn handle_rcpt(cx: &mut Context<HuskContext<'_>>, args: Vec<CString>) -> Status {
log::debug!("RCPT: {args:?}");
if let Some(ref mut context) = cx.data {
}
Status::Continue
}
async fn handle_data(_cx: &mut Context<HuskContext>) -> Status {
async fn handle_data(_cx: &mut Context<HuskContext<'_>>) -> Status {
log::debug!("DATA");
Status::Continue
}
async fn handle_header(_cx: &mut Context<HuskContext>, name: CString, value: CString) -> Status {
async fn handle_header(_cx: &mut Context<HuskContext<'_>>, name: CString, value: CString) -> Status {
log::debug!("HEADER: {name:?} = {value:?}");
Status::Continue
}
async fn handle_eoh(_cx: &mut Context<HuskContext>) -> Status {
async fn handle_eoh(_cx: &mut Context<HuskContext<'_>>) -> Status {
log::debug!("EOH");
Status::Continue
}
async fn handle_body(_cx: &mut Context<HuskContext>, chunk: Bytes) -> Status {
async fn handle_body(_cx: &mut Context<HuskContext<'_>>, chunk: Bytes) -> Status {
log::debug!("BODY: chunk with {:?} bytes received", &chunk.len());
Status::Continue
}
async fn handle_eom(cx: &mut EomContext<HuskContext>) -> Status {
async fn handle_eom(cx: &mut EomContext<HuskContext<'_>>) -> Status {
log::debug!("EOM");
if let Some(ref mut context_data) = cx.data {
log::debug!("Mail from {:?} complete", context_data.sender);
if let Some(ref mut context) = cx.data {
log::debug!("Mail from {:?} complete", context.mail.sender);
}
Status::Continue
}
async fn handle_abort(_cx: &mut Context<HuskContext>) -> Status {
async fn handle_abort(_cx: &mut Context<HuskContext<'_>>) -> Status {
log::debug!("ABORT");
Status::Continue
}
async fn handle_close(_cx: &mut Context<HuskContext>) -> Status {
async fn handle_close(_cx: &mut Context<HuskContext<'_>>) -> Status {
log::debug!("CLOSE");
Status::Continue
}
async fn handle_unknown(_cx: &mut Context<HuskContext>, arg: CString) -> Status {
async fn handle_unknown(_cx: &mut Context<HuskContext<'_>>, arg: CString) -> Status {
log::debug!("UNKNOWN: {arg:?}");
Status::Continue