Trusted/untrusted Sieve runtimes

This commit is contained in:
mdecimus 2023-10-23 18:58:04 +02:00
parent 73ccf7be65
commit b5fe327e83
11 changed files with 111 additions and 99 deletions

View file

@ -85,10 +85,10 @@ impl crate::Config {
.property("jmap.email.parse.max-items")?
.unwrap_or(10),
sieve_max_script_name: settings
.property("sieve.jmap.limits.name-length")?
.property("sieve.untrusted.limits.name-length")?
.unwrap_or(512),
sieve_max_scripts: settings
.property("sieve.jmap.limits.max-scripts")?
.property("sieve.untrusted.limits.max-scripts")?
.unwrap_or(256),
capabilities: BaseCapabilities::default(),
session_cache_ttl: settings

View file

@ -379,7 +379,7 @@ impl SieveCapabilities {
pub fn new(config: &crate::Config, settings: &utils::config::Config) -> Self {
let mut notification_methods = Vec::new();
for (_, uri) in settings.values("sieve.jmap.notification-uris") {
for (_, uri) in settings.values("sieve.untrusted.notification-uris") {
notification_methods.push(uri.to_string());
}
if notification_methods.is_empty() {
@ -389,7 +389,7 @@ impl SieveCapabilities {
let mut capabilities: AHashSet<sieve::compiler::grammar::Capability> =
AHashSet::from_iter(sieve::compiler::grammar::Capability::all().iter().cloned());
for (_, capability) in settings.values("sieve.jmap.disabled-capabilities") {
for (_, capability) in settings.values("sieve.untrusted.disabled-capabilities") {
capabilities.remove(&sieve::compiler::grammar::Capability::parse(capability));
}
@ -402,12 +402,12 @@ impl SieveCapabilities {
SieveCapabilities {
max_script_name: config.sieve_max_script_name,
max_script_size: settings
.property("sieve.jmap.max-script-size")
.property("sieve.untrusted.max-script-size")
.failed("Invalid configuration file")
.unwrap_or(1024 * 1024),
max_scripts: config.sieve_max_scripts,
max_redirects: settings
.property("sieve.jmap.max-redirects")
.property("sieve.untrusted.max-redirects")
.failed("Invalid configuration file")
.unwrap_or(1),
extensions,

View file

@ -228,98 +228,110 @@ impl JMAP {
sieve_compiler: Compiler::new()
.with_max_script_size(
config
.property("sieve.jmap.limits.script-size")?
.property("sieve.untrusted.limits.script-size")?
.unwrap_or(1024 * 1024),
)
.with_max_string_size(
config
.property("sieve.jmap.limits.string-length")?
.property("sieve.untrusted.limits.string-length")?
.unwrap_or(4096),
)
.with_max_variable_name_size(
config
.property("sieve.jmap.limits.variable-name-length")?
.property("sieve.untrusted.limits.variable-name-length")?
.unwrap_or(32),
)
.with_max_nested_blocks(
config
.property("sieve.jmap.limits.nested-blocks")?
.property("sieve.untrusted.limits.nested-blocks")?
.unwrap_or(15),
)
.with_max_nested_tests(
config
.property("sieve.jmap.limits.nested-tests")?
.property("sieve.untrusted.limits.nested-tests")?
.unwrap_or(15),
)
.with_max_nested_foreverypart(
config
.property("sieve.jmap.limits.nested-foreverypart")?
.property("sieve.untrusted.limits.nested-foreverypart")?
.unwrap_or(3),
)
.with_max_match_variables(
config
.property("sieve.jmap.limits.match-variables")?
.property("sieve.untrusted.limits.match-variables")?
.unwrap_or(30),
)
.with_max_local_variables(
config
.property("sieve.jmap.limits.local-variables")?
.property("sieve.untrusted.limits.local-variables")?
.unwrap_or(128),
)
.with_max_header_size(
config
.property("sieve.jmap.limits.header-size")?
.property("sieve.untrusted.limits.header-size")?
.unwrap_or(1024),
)
.with_max_includes(config.property("sieve.jmap.limits.includes")?.unwrap_or(3)),
.with_max_includes(
config
.property("sieve.untrusted.limits.includes")?
.unwrap_or(3),
),
sieve_runtime: Runtime::new()
.with_max_nested_includes(
config
.property("sieve.jmap.limits.nested-includes")?
.property("sieve.untrusted.limits.nested-includes")?
.unwrap_or(3),
)
.with_cpu_limit(config.property("sieve.jmap.limits.cpu")?.unwrap_or(5000))
.with_cpu_limit(
config
.property("sieve.untrusted.limits.cpu")?
.unwrap_or(5000),
)
.with_max_variable_size(
config
.property("sieve.jmap.limits.variable-size")?
.property("sieve.untrusted.limits.variable-size")?
.unwrap_or(4096),
)
.with_max_redirects(config.property("sieve.jmap.limits.redirects")?.unwrap_or(1))
.with_max_redirects(
config
.property("sieve.untrusted.limits.redirects")?
.unwrap_or(1),
)
.with_max_received_headers(
config
.property("sieve.jmap.limits.received-headers")?
.property("sieve.untrusted.limits.received-headers")?
.unwrap_or(10),
)
.with_max_header_size(
config
.property("sieve.jmap.limits.header-size")?
.property("sieve.untrusted.limits.header-size")?
.unwrap_or(1024),
)
.with_max_out_messages(
config
.property("sieve.jmap.limits.outgoing-messages")?
.property("sieve.untrusted.limits.outgoing-messages")?
.unwrap_or(3),
)
.with_default_vacation_expiry(
config
.property::<Duration>("sieve.jmap.default-expiry.vacation")?
.property::<Duration>("sieve.untrusted.default-expiry.vacation")?
.unwrap_or(Duration::from_secs(30 * 86400))
.as_secs(),
)
.with_default_duplicate_expiry(
config
.property::<Duration>("sieve.jmap.default-expiry.duplicate")?
.property::<Duration>("sieve.untrusted.default-expiry.duplicate")?
.unwrap_or(Duration::from_secs(7 * 86400))
.as_secs(),
)
.without_capabilities(
config
.values("sieve.jmap.disable-capabilities")
.values("sieve.untrusted.disable-capabilities")
.map(|(_, v)| v),
)
.with_valid_notification_uris({
let values = config
.values("sieve.jmap.notification-uris")
.values("sieve.untrusted.notification-uris")
.map(|(_, v)| v.to_string())
.collect::<Vec<_>>();
if !values.is_empty() {
@ -330,7 +342,7 @@ impl JMAP {
})
.with_protected_headers({
let values = config
.values("sieve.jmap.protected-headers")
.values("sieve.untrusted.protected-headers")
.map(|(_, v)| v.to_string())
.collect::<Vec<_>>();
if !values.is_empty() {
@ -346,13 +358,13 @@ impl JMAP {
})
.with_vacation_default_subject(
config
.value("sieve.jmap.vacation.default-subject")
.value("sieve.untrusted.vacation.default-subject")
.unwrap_or("Automated reply")
.to_string(),
)
.with_vacation_subject_prefix(
config
.value("sieve.jmap.vacation.subject-prefix")
.value("sieve.untrusted.vacation.subject-prefix")
.unwrap_or("Auto: ")
.to_string(),
)

View file

@ -95,7 +95,7 @@ impl ConfigSieve for Config {
.with_max_header_size(10240)
.with_max_includes(10)
.with_no_capability_check(
self.property_or_static("sieve.smtp.no-capability-check", "false")?,
self.property_or_static("sieve.trusted.no-capability-check", "false")?,
)
.register_functions(&mut fnc_map);
@ -115,32 +115,32 @@ impl ConfigSieve for Config {
.with_capability(Capability::Expressions)
.with_capability(Capability::While)
.with_max_variable_size(
self.property_or_static("sieve.smtp.limits.variable-size", "52428800")?,
self.property_or_static("sieve.trusted.limits.variable-size", "52428800")?,
)
.with_max_header_size(10240)
.with_valid_notification_uri("mailto")
.with_valid_ext_lists(ctx.directory.lookups.keys().map(|k| k.to_string()))
.with_functions(&mut fnc_map);
if let Some(value) = self.property("sieve.smtp.limits.redirects")? {
if let Some(value) = self.property("sieve.trusted.limits.redirects")? {
runtime.set_max_redirects(value);
}
if let Some(value) = self.property("sieve.smtp.limits.out-messages")? {
if let Some(value) = self.property("sieve.trusted.limits.out-messages")? {
runtime.set_max_out_messages(value);
}
if let Some(value) = self.property("sieve.smtp.limits.cpu")? {
if let Some(value) = self.property("sieve.trusted.limits.cpu")? {
runtime.set_cpu_limit(value);
}
if let Some(value) = self.property("sieve.smtp.limits.nested-includes")? {
if let Some(value) = self.property("sieve.trusted.limits.nested-includes")? {
runtime.set_max_nested_includes(value);
}
if let Some(value) = self.property("sieve.smtp.limits.received-headers")? {
if let Some(value) = self.property("sieve.trusted.limits.received-headers")? {
runtime.set_max_received_headers(value);
}
if let Some(value) = self.property::<Duration>("sieve.smtp.limits.duplicate-expiry")? {
if let Some(value) = self.property::<Duration>("sieve.trusted.limits.duplicate-expiry")? {
runtime.set_default_duplicate_expiry(value.as_secs());
}
let hostname = if let Some(hostname) = self.value("sieve.smtp.hostname") {
let hostname = if let Some(hostname) = self.value("sieve.trusted.hostname") {
hostname
} else {
self.value_require("server.hostname")?
@ -148,13 +148,13 @@ impl ConfigSieve for Config {
runtime.set_local_hostname(hostname.to_string());
// Parse scripts
for id in self.sub_keys("sieve.smtp.scripts") {
let key = ("sieve.smtp.scripts", id);
for id in self.sub_keys("sieve.trusted.scripts") {
let key = ("sieve.trusted.scripts", id);
let script = if !self.contains_key(key) {
let mut script = Vec::new();
for sub_key in self.sub_keys(key) {
script.extend(self.file_contents(("sieve.smtp.scripts", id, sub_key))?);
script.extend(self.file_contents(("sieve.trusted.scripts", id, sub_key))?);
}
script
} else {
@ -172,14 +172,14 @@ impl ConfigSieve for Config {
// Parse DKIM signatures
let mut sign = Vec::new();
for (pos, id) in self.values("sieve.smtp.sign") {
for (pos, id) in self.values("sieve.trusted.sign") {
if let Some(dkim) = ctx.signers.get(id) {
sign.push(dkim.clone());
} else {
return Err(format!(
"No DKIM signer found with id {:?} for key {:?}.",
id,
("sieve.smtp.sign", pos).as_key()
("sieve.trusted.sign", pos).as_key()
));
}
}
@ -190,15 +190,15 @@ impl ConfigSieve for Config {
lookup: ctx.directory.lookups.clone(),
config: SieveConfig {
from_addr: self
.value("sieve.smtp.from-addr")
.value("sieve.trusted.from-addr")
.map(|a| a.to_string())
.unwrap_or(format!("MAILER-DAEMON@{hostname}")),
from_name: self
.value("sieve.smtp.from-name")
.value("sieve.trusted.from-name")
.unwrap_or("Mailer Daemon")
.to_string(),
return_path: self
.value("sieve.smtp.return-path")
.value("sieve.trusted.return-path")
.unwrap_or_default()
.to_string(),
sign,

View file

@ -1,8 +1,45 @@
#############################################
# SMTP Sieve interpreter configuration
# Sieve untrusted runtime configuration
#############################################
[sieve.smtp]
[sieve.untrusted]
disable-capabilities = []
notification-uris = ["mailto"]
protected-headers = ["Original-Subject", "Original-From", "Received", "Auto-Submitted"]
[sieve.untrusted.limits]
name-length = 512
max-scripts = 256
script-size = 102400
string-length = 4096
variable-name-length = 32
variable-size = 4096
nested-blocks = 15
nested-tests = 15
nested-foreverypart = 3
match-variables = 30
local-variables = 128
header-size = 1024
includes = 3
nested-includes = 3
cpu = 5000
redirects = 1
received-headers = 10
outgoing-messages = 3
[sieve.untrusted.vacation]
default-subject = "Automated reply"
subject-prefix = "Auto: "
[sieve.untrusted.default-expiry]
vacation = "30d"
duplicate = "7d"
#############################################
# Sieve trusted runtime configuration
#############################################
[sieve.trusted]
from-name = "Automated Message"
from-addr = "no-reply@%{DEFAULT_DOMAIN}%"
return-path = ""
@ -10,7 +47,7 @@ return-path = ""
no-capability-check = true
sign = ["rsa"]
[sieve.smtp.limits]
[sieve.trusted.limits]
redirects = 3
out-messages = 5
received-headers = 50
@ -18,7 +55,7 @@ cpu = 1048576
nested-includes = 5
duplicate-expiry = "7d"
[sieve.smtp.scripts]
[sieve.trusted.scripts]
#connect = '''require ["variables", "extlists", "reject"];
# if string :list "${env.remote_ip}" "default/blocked-ips" {
# reject "Your IP '${env.remote_ip}' is not welcomed here.";

View file

@ -11,6 +11,7 @@ base_path = "__BASE_PATH__"
files = [ "%{BASE_PATH}%/etc/common/server.toml",
"%{BASE_PATH}%/etc/common/tls.toml",
"%{BASE_PATH}%/etc/common/tracing.toml",
"%{BASE_PATH}%/etc/common/sieve.toml",
"%{BASE_PATH}%/etc/directory/sql.toml",
"%{BASE_PATH}%/etc/imap/listener.toml",
"%{BASE_PATH}%/etc/imap/settings.toml",
@ -20,7 +21,6 @@ files = [ "%{BASE_PATH}%/etc/common/server.toml",
"%{BASE_PATH}%/etc/jmap/protocol.toml",
"%{BASE_PATH}%/etc/jmap/push.toml",
"%{BASE_PATH}%/etc/jmap/ratelimit.toml",
"%{BASE_PATH}%/etc/jmap/sieve.toml",
"%{BASE_PATH}%/etc/jmap/store.toml",
"%{BASE_PATH}%/etc/jmap/websockets.toml",
"%{BASE_PATH}%/etc/smtp/auth.toml",
@ -31,6 +31,5 @@ files = [ "%{BASE_PATH}%/etc/common/server.toml",
"%{BASE_PATH}%/etc/smtp/report.toml",
"%{BASE_PATH}%/etc/smtp/resolver.toml",
"%{BASE_PATH}%/etc/smtp/session.toml",
"%{BASE_PATH}%/etc/smtp/sieve.toml",
"%{BASE_PATH}%/etc/smtp/signature.toml",
"%{BASE_PATH}%/etc/smtp/spamfilter.toml" ]

View file

@ -1,36 +0,0 @@
#############################################
# JMAP Sieve interpreter configuration
#############################################
[sieve.jmap]
disable-capabilities = []
notification-uris = ["mailto"]
protected-headers = ["Original-Subject", "Original-From", "Received", "Auto-Submitted"]
[sieve.jmap.limits]
name-length = 512
max-scripts = 256
script-size = 102400
string-length = 4096
variable-name-length = 32
variable-size = 4096
nested-blocks = 15
nested-tests = 15
nested-foreverypart = 3
match-variables = 30
local-variables = 128
header-size = 1024
includes = 3
nested-includes = 3
cpu = 5000
redirects = 1
received-headers = 10
outgoing-messages = 3
[sieve.jmap.vacation]
default-subject = "Automated reply"
subject-prefix = "Auto: "
[sieve.jmap.default-expiry]
vacation = "30d"
duplicate = "7d"

View file

@ -82,7 +82,7 @@ values = "file://%{BASE_PATH}%/etc/spamfilter/maps/spam_trap.list"
type = "map"
values = "file://%{BASE_PATH}%/etc/spamfilter/maps/scores.map"
[sieve.smtp.scripts]
[sieve.trusted.scripts]
spam-filter = ["file://%{BASE_PATH}%/etc/spamfilter/scripts/config.sieve",
"file://%{BASE_PATH}%/etc/spamfilter/scripts/prelude.sieve",
"file://%{BASE_PATH}%/etc/spamfilter/scripts/from.sieve",

View file

@ -27,14 +27,14 @@ use utils::config::Config;
use crate::smtp::{TestConfig, TestSMTP};
const CONFIG: &str = r#"
[sieve.smtp]
[sieve.trusted]
from-name = "Sieve Daemon"
from-addr = "sieve@foobar.org"
return-path = ""
hostname = "mx.foobar.org"
no-capability-check = true
[sieve.smtp.limits]
[sieve.trusted.limits]
redirects = 3
out-messages = 5
received-headers = 50
@ -127,7 +127,7 @@ values = "file://%CFG_PATH%/maps/scores.map"
[resolver]
public-suffix = "file://%LIST_PATH%/public-suffix.dat"
[sieve.smtp.scripts]
[sieve.trusted.scripts]
"#;
const CREATE_TABLES: &[&str; 3] = &[

View file

@ -46,13 +46,13 @@ rewrite = [ { all-of = [ { if = "rcpt-domain", eq = "foobar.net" },
script = [ { if = "rcpt-domain", eq = "foobar.org", then = "rcpt" },
{ else = false } ]
[sieve.smtp]
[sieve.trusted]
from-name = "Sieve Daemon"
from-addr = "sieve@foobar.org"
return-path = ""
hostname = "mx.foobar.org"
[sieve.smtp.limits]
[sieve.trusted.limits]
redirects = 3
out-messages = 5
received-headers = 50
@ -60,7 +60,7 @@ cpu = 10000
nested-includes = 5
duplicate-expiry = "7d"
[sieve.smtp.scripts]
[sieve.trusted.scripts]
mail = '''
require ["variables", "envelope"];

View file

@ -60,14 +60,14 @@ command = [ { if = "remote-ip", eq = "10.0.0.123", then = "/bin/bash" },
arguments = ["%CFG_PATH%/pipe_me.sh", "hello", "world"]
timeout = "10s"
[sieve.smtp]
[sieve.trusted]
from-name = "Sieve Daemon"
from-addr = "sieve@foobar.org"
return-path = ""
hostname = "mx.foobar.org"
sign = ["rsa"]
[sieve.smtp.limits]
[sieve.trusted.limits]
redirects = 3
out-messages = 5
received-headers = 50
@ -75,7 +75,7 @@ cpu = 10000
nested-includes = 5
duplicate-expiry = "7d"
[sieve.smtp.scripts]
[sieve.trusted.scripts]
"#;
#[tokio::test]