From 29fa7feb5bb96a4d3550f3b8841baa41271517f7 Mon Sep 17 00:00:00 2001 From: Stoiko Ivanov Date: Fri, 21 Sep 2018 15:51:42 +0200 Subject: [PATCH] add PMG::API2::DestinationTLSPolicy to handle /etc/pmg/tls_policy via API, using PMG::API2::Transport as base/inspiration. This enables PMG to enforce TLS on a per-domain basis. See http://www.postfix.org/postconf.5.html#smtp_tls_policy_maps and http://www.postfix.org/TLS_README.html#client_tls_policy for reference. Signed-off-by: Stoiko Ivanov --- Makefile | 1 + PMG/API2/Config.pm | 7 + PMG/API2/DestinationTLSPolicy.pm | 214 +++++++++++++++++++++++++++++++ 3 files changed, 222 insertions(+) create mode 100644 PMG/API2/DestinationTLSPolicy.pm diff --git a/Makefile b/Makefile index 4346e37..53d97fd 100644 --- a/Makefile +++ b/Makefile @@ -123,6 +123,7 @@ LIBSOURCES = \ PMG/API2/Services.pm \ PMG/API2/Tasks.pm \ PMG/API2/LDAP.pm \ + PMG/API2/DestinationTLSPolicy.pm\ PMG/API2/Domains.pm \ PMG/API2/Fetchmail.pm \ PMG/API2/Users.pm \ diff --git a/PMG/API2/Config.pm b/PMG/API2/Config.pm index e0bf2c1..3b688fa 100644 --- a/PMG/API2/Config.pm +++ b/PMG/API2/Config.pm @@ -22,6 +22,7 @@ use PMG::API2::MyNetworks; use PMG::API2::SMTPWhitelist; use PMG::API2::MimeTypes; use PMG::API2::Fetchmail; +use PMG::API2::DestinationTLSPolicy; use base qw(PVE::RESTHandler); @@ -75,6 +76,11 @@ __PACKAGE__->register_method ({ path => 'mimetypes', }); +__PACKAGE__->register_method ({ + subclass => "PMG::API2::DestinationTLSPolicy", + path => 'tlspolicy', +}); + __PACKAGE__->register_method ({ name => 'index', path => '', @@ -111,6 +117,7 @@ __PACKAGE__->register_method ({ push @$res, { section => 'transport' }; push @$res, { section => 'whitelist' }; push @$res, { section => 'regextest' }; + push @$res, { section => 'tlspolicy' }; return $res; }}); diff --git a/PMG/API2/DestinationTLSPolicy.pm b/PMG/API2/DestinationTLSPolicy.pm new file mode 100644 index 0000000..4c1ab56 --- /dev/null +++ b/PMG/API2/DestinationTLSPolicy.pm @@ -0,0 +1,214 @@ +package PMG::API2::DestinationTLSPolicy; + +use strict; +use warnings; + +use PVE::RESTHandler; +use PVE::INotify; +use PVE::Exception qw(raise_param_exc); + +use PMG::Config; + +use base qw(PVE::RESTHandler); + +__PACKAGE__->register_method ({ + name => 'index', + path => '', + method => 'GET', + description => "List tls_policy entries.", + proxyto => 'master', + permissions => { check => [ 'admin', 'audit' ] }, + parameters => { + additionalProperties => 0, + properties => {}, + }, + returns => { + type => 'array', + items => { + type => 'object', + properties => { + domain => { type => 'string', format => 'transport-domain'}, + policy => { type => 'string', format => 'tls-policy'}, + }, + }, + links => [ { rel => 'child', href => "{domain}" } ], + }, + code => sub { + my ($param) = @_; + + my $res = []; + + my $policies = PVE::INotify::read_file('tls_policy'); + foreach my $policy (sort keys %$policies) { + push @$res, $policies->{$policy}; + } + + return $res; + }}); + +__PACKAGE__->register_method ({ + name => 'create', + path => '', + method => 'POST', + proxyto => 'master', + protected => 1, + permissions => { check => [ 'admin' ] }, + description => "Add tls_policy entry.", + parameters => { + additionalProperties => 0, + properties => { + domain => { + description => "Domain name.", + type => 'string', format => 'transport-domain', + }, + policy => { + description => "TLS policy", + type => 'string', format => 'tls-policy', + }, + }, + }, + returns => { type => 'null' }, + code => sub { + my ($param) = @_; + my $domain = $param->{domain}; + + my $code = sub { + my $tls_policy = PVE::INotify::read_file('tls_policy'); + raise_param_exc({ domain => "DestinationTLSPolicy entry for '$domain' already exists" }) + if $tls_policy->{$domain}; + + $tls_policy->{$domain} = { + domain => $domain, + policy => $param->{policy}, + }; + + PVE::INotify::write_file('tls_policy', $tls_policy); + PMG::Config::postmap_tls_policy(); + }; + + PMG::Config::lock_config($code, "add tls_policy entry failed"); + + return undef; + }}); + +__PACKAGE__->register_method ({ + name => 'read', + path => '{domain}', + method => 'GET', + description => "Read tls_policy entry.", + proxyto => 'master', + permissions => { check => [ 'admin', 'audit' ] }, + parameters => { + additionalProperties => 0, + properties => { + domain => { + description => "Domain name.", + type => 'string', format => 'transport-domain', + }, + }, + }, + returns => { + type => "object", + properties => { + domain => { type => 'string', format => 'transport-domain'}, + policy => { type => 'string', format => 'tls-policy'}, + }, + }, + code => sub { + my ($param) = @_; + my $domain = $param->{domain}; + + my $tls_policy = PVE::INotify::read_file('tls_policy'); + + if (my $entry = $tls_policy->{$domain}) { + return $entry; + } + + raise_param_exc({ domain => "DestinationTLSPolicy entry for '$domain' does not exist" }); + }}); + +__PACKAGE__->register_method ({ + name => 'write', + path => '{domain}', + method => 'PUT', + description => "Update tls_policy entry.", + protected => 1, + permissions => { check => [ 'admin' ] }, + proxyto => 'master', + parameters => { + additionalProperties => 0, + properties => { + domain => { + description => "Domain name.", + type => 'string', format => 'transport-domain', + }, + policy => { + description => "TLS policy", + type => 'string', format => 'tls-policy', + }, + }, + }, + returns => { type => 'null' }, + code => sub { + my ($param) = @_; + my $domain = $param->{domain}; + my $policy = $param->{policy}; + + my $code = sub { + + my $tls_policy = PVE::INotify::read_file('tls_policy'); + + raise_param_exc({ domain => "DestinationTLSPolicy entry for '$domain' does not exist" }) + if !$tls_policy->{$domain}; + + $tls_policy->{$domain}->{policy} = $policy; + + PVE::INotify::write_file('tls_policy', $tls_policy); + PMG::Config::postmap_tls_policy(); + }; + + PMG::Config::lock_config($code, "update tls_policy entry failed"); + + return undef; + }}); + +__PACKAGE__->register_method ({ + name => 'delete', + path => '{domain}', + method => 'DELETE', + description => "Delete a tls_policy entry", + protected => 1, + permissions => { check => [ 'admin' ] }, + proxyto => 'master', + parameters => { + additionalProperties => 0, + properties => { + domain => { + description => "Domain name.", + type => 'string', format => 'transport-domain', + }, + } + }, + returns => { type => 'null' }, + code => sub { + my ($param) = @_; + my $domain = $param->{domain}; + + my $code = sub { + my $tls_policy = PVE::INotify::read_file('tls_policy'); + + raise_param_exc({ domain => "DestinationTLSPolicy entry for '$domain' does not exist" }) + if !$tls_policy->{$domain}; + + delete $tls_policy->{$domain}; + + PVE::INotify::write_file('tls_policy', $tls_policy); + PMG::Config::postmap_tls_policy(); + }; + + PMG::Config::lock_config($code, "delete tls_policy entry failed"); + + return undef; + }}); + +1; -- 2.39.2