diff --git a/crates/jmap/src/api/config.rs b/crates/jmap/src/api/config.rs index d42a2da2..23085e33 100644 --- a/crates/jmap/src/api/config.rs +++ b/crates/jmap/src/api/config.rs @@ -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 diff --git a/crates/jmap/src/api/session.rs b/crates/jmap/src/api/session.rs index 5c750b78..6f5ee95a 100644 --- a/crates/jmap/src/api/session.rs +++ b/crates/jmap/src/api/session.rs @@ -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 = 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, diff --git a/crates/jmap/src/lib.rs b/crates/jmap/src/lib.rs index d372f252..d99ef8bc 100644 --- a/crates/jmap/src/lib.rs +++ b/crates/jmap/src/lib.rs @@ -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::("sieve.jmap.default-expiry.vacation")? + .property::("sieve.untrusted.default-expiry.vacation")? .unwrap_or(Duration::from_secs(30 * 86400)) .as_secs(), ) .with_default_duplicate_expiry( config - .property::("sieve.jmap.default-expiry.duplicate")? + .property::("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::>(); 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::>(); 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(), ) diff --git a/crates/smtp/src/config/scripts.rs b/crates/smtp/src/config/scripts.rs index 8f367d85..5de38795 100644 --- a/crates/smtp/src/config/scripts.rs +++ b/crates/smtp/src/config/scripts.rs @@ -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::("sieve.smtp.limits.duplicate-expiry")? { + if let Some(value) = self.property::("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, diff --git a/resources/config/smtp/sieve.toml b/resources/config/common/sieve.toml similarity index 50% rename from resources/config/smtp/sieve.toml rename to resources/config/common/sieve.toml index 6d05f0e5..d41cee31 100644 --- a/resources/config/smtp/sieve.toml +++ b/resources/config/common/sieve.toml @@ -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."; diff --git a/resources/config/config.toml b/resources/config/config.toml index 5f6183b1..301ef9f3 100644 --- a/resources/config/config.toml +++ b/resources/config/config.toml @@ -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" ] diff --git a/resources/config/jmap/sieve.toml b/resources/config/jmap/sieve.toml deleted file mode 100644 index 67d1d21e..00000000 --- a/resources/config/jmap/sieve.toml +++ /dev/null @@ -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" diff --git a/resources/config/smtp/spamfilter.toml b/resources/config/smtp/spamfilter.toml index b0d5e16e..c381804b 100644 --- a/resources/config/smtp/spamfilter.toml +++ b/resources/config/smtp/spamfilter.toml @@ -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", diff --git a/tests/src/smtp/inbound/antispam.rs b/tests/src/smtp/inbound/antispam.rs index 1fe3985e..abcb75d5 100644 --- a/tests/src/smtp/inbound/antispam.rs +++ b/tests/src/smtp/inbound/antispam.rs @@ -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] = &[ diff --git a/tests/src/smtp/inbound/rewrite.rs b/tests/src/smtp/inbound/rewrite.rs index 51b33d2b..e67d70db 100644 --- a/tests/src/smtp/inbound/rewrite.rs +++ b/tests/src/smtp/inbound/rewrite.rs @@ -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"]; diff --git a/tests/src/smtp/inbound/scripts.rs b/tests/src/smtp/inbound/scripts.rs index c6043c18..b91b9a8c 100644 --- a/tests/src/smtp/inbound/scripts.rs +++ b/tests/src/smtp/inbound/scripts.rs @@ -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]