From: Maximiliano Sandoval <m.sandoval@proxmox.com>
To: pmg-devel@lists.proxmox.com
Subject: [pmg-devel] [RFC PATCH] fix #4926: run pmg-smtp-filter and pmgpolicy without root rights
Date: Wed, 22 May 2024 12:35:37 +0200 [thread overview]
Message-ID: <20240522103537.274071-1-m.sandoval@proxmox.com> (raw)
New users 'pmg-smpt-filter' and 'pmgpolicy' are created for their
respective processes. A shared group named 'pmg' is introduced for
processes that need to be accessible from multiple processes like
spamassassin, rrdcached or the /var/spool/pmg directory.
We also create new users for the ruledb.
Signed-off-by: Maximiliano Sandoval <m.sandoval@proxmox.com>
---
debian/pmg-smtp-filter.service | 5 ++-
debian/pmgpolicy.service | 5 ++-
debian/postinst | 64 ++++++++++++++++++++++++++++++++++
src/PMG/Config.pm | 12 +++----
src/PMG/DBTools.pm | 27 ++++++++++++--
src/PMG/MailQueue.pm | 7 ++--
src/PMG/Report.pm | 2 +-
src/PMG/Utils.pm | 2 +-
src/bin/pmg-smtp-filter | 8 ++---
src/bin/pmgpolicy | 8 ++---
10 files changed, 117 insertions(+), 23 deletions(-)
diff --git a/debian/pmg-smtp-filter.service b/debian/pmg-smtp-filter.service
index cbf2d6f..aae07b7 100644
--- a/debian/pmg-smtp-filter.service
+++ b/debian/pmg-smtp-filter.service
@@ -11,10 +11,13 @@ ExecStart=/usr/bin/pmg-smtp-filter
KillMode=mixed
TimeoutStopSec=40
ExecReload=/bin/kill -HUP $MAINPID
-PIDFile=/run/pmg-smtp-filter.pid
+PIDFile=/run/pmg-smtp-filter/pmg-smtp-filter.pid
Type=forking
Restart=on-abort
RestartSec=10
+User=pmg-smtp-filter
+Group=pmg-smtp-filter
+RuntimeDirectory=pmg-smtp-filter
[Install]
WantedBy=multi-user.target
diff --git a/debian/pmgpolicy.service b/debian/pmgpolicy.service
index 517a5d6..cebeac6 100644
--- a/debian/pmgpolicy.service
+++ b/debian/pmgpolicy.service
@@ -10,8 +10,11 @@ ExecStart=/usr/bin/pmgpolicy
KillMode=mixed
TimeoutStopSec=40
ExecReload=/bin/kill -HUP $MAINPID
-PIDFile=/run/pmgpolicy.pid
+PIDFile=/run/pmgpolicy/pmgpolicy.pid
Type=forking
+User=pmgpolicy
+Group=pmgpolicy
+RuntimeDirectory=pmgpolicy
[Install]
WantedBy=multi-user.target
diff --git a/debian/postinst b/debian/postinst
index 770c944..1308df0 100644
--- a/debian/postinst
+++ b/debian/postinst
@@ -48,6 +48,66 @@ migrate_apt_auth_conf() {
fi
}
+migrate_pmg_smtp_filter() {
+ PMGPOLICY_USER="pmgpolicy"
+ PMG_SMTP_FILTER_USER="pmg-smtp-filter"
+ PMG_GROUP="pmg"
+
+ # Add shared pmg group for usage together with rrdcached
+ if ! getent group | grep -q "^$PMG_GROUP:" ; then
+ echo -n "Adding group $PMG_GROUP.."
+ addgroup --quiet --system $PMG_GROUP 2>/dev/null ||true
+ echo "..done"
+ fi
+
+ for user in $PMGPOLICY_USER $PMG_SMTP_FILTER_USER; do
+ if ! getent passwd | grep -q "^$user:"; then
+ echo -n "Adding system user $user.."
+ adduser --quiet \
+ --system \
+ --no-create-home \
+ --disabled-password \
+ --home /nonexistent \
+ --group \
+ $user 2>/dev/null || true
+ echo "..done"
+ fi
+
+ if ! getent group $PMG_GROUP | grep -q "$user"; then
+ echo -n "Adding user $user to $PMG_GROUP group.."
+ adduser --quiet $user $PMG_GROUP 2>/dev/null ||true
+ echo "..done"
+ fi
+
+ if ! getent group systemd-journal | grep -q $user ; then
+ echo -n "Adding user $user to systemd-journal group.."
+ adduser --quiet $user systemd-journal 2>/dev/null ||true
+ echo "..done"
+ fi
+ done
+
+ chown :pmg /var/spool/pmg/active
+ chown :pmg /var/spool/pmg/virus
+ chown :pmg /var/spool/pmg/spam
+ chown :pmg /var/spool/pmg/attachment
+ chmod g+w /var/spool/pmg/active
+ chmod g+w /var/spool/pmg/virus
+ chmod g+w /var/spool/pmg/spam
+ chmod g+w /var/spool/pmg/attachment
+
+ chown :pmg /var/lib/pmg
+
+ # FIXME: This is not ideal
+ if ! cat /etc/default/rrdcached | grep -q "^SOCKGROUP=pmg$"; then
+ sed -i "s/#SOCKGROUP=root/SOCKGROUP=pmg/" /etc/default/rrdcached
+ if systemctl --quiet is-active rrdcached.service ; then
+ deb-systemd-invoke reload-or-try-restart rrdcached.service >/dev/null || true
+ fi
+ fi
+
+ pmgdb update >/dev/null 2>&1 &
+}
+
case "$1" in
triggered)
@@ -67,6 +127,10 @@ case "$1" in
if test ! -e /proxmox_install_mode ; then
+ if test -n "$2" && dpkg --compare-versions "$2" 'lt' '8.1.3'; then
+ migrate_pmg_smtp_filter
+ fi
+
pmgconf="/etc/pmg/pmg.conf"
if test -n "$2" && dpkg --compare-versions "$2" 'lt' '8.0.2'; then
# on upgrade add pre 8.0 default values for advfilter, use_awl and use_bayes
diff --git a/src/PMG/Config.pm b/src/PMG/Config.pm
index a0daba3..a91bb10 100644
--- a/src/PMG/Config.pm
+++ b/src/PMG/Config.pm
@@ -1594,13 +1594,13 @@ sub rewrite_config_spam {
# delete AW and bayes databases if those features are disabled
if (!$use_awl) {
- $changes = 1 if unlink '/root/.spamassassin/auto-whitelist';
+ $changes = 1 if unlink '/var/lib/pmg/spamassassin/auto-whitelist';
}
if (!$use_bayes) {
- $changes = 1 if unlink '/root/.spamassassin/bayes_journal';
- $changes = 1 if unlink '/root/.spamassassin/bayes_seen';
- $changes = 1 if unlink '/root/.spamassassin/bayes_toks';
+ $changes = 1 if unlink '/var/lib/pmg/spamassassin/bayes_journal';
+ $changes = 1 if unlink '/var/lib/pmg/spamassassin/bayes_seen';
+ $changes = 1 if unlink '/var/lib/pmg/spamassassin/bayes_toks';
}
# make sure we have the custom SA files (else cluster sync fails)
@@ -1819,8 +1819,8 @@ my $pmg_service_params = {
},
};
-my $smtp_filter_cfg = '/run/pmg-smtp-filter.cfg';
-my $smtp_filter_cfg_lock = '/run/pmg-smtp-filter.cfg.lck';
+my $smtp_filter_cfg = '/run/pmg-smtp-filter/pmg-smtp-filter.cfg';
+my $smtp_filter_cfg_lock = '/run/pmg-smtp-filter/pmg-smtp-filter.cfg.lck';
sub dump_smtp_filter_config {
my ($self) = @_;
diff --git a/src/PMG/DBTools.pm b/src/PMG/DBTools.pm
index 8770d06..96bac00 100644
--- a/src/PMG/DBTools.pm
+++ b/src/PMG/DBTools.pm
@@ -38,7 +38,7 @@ sub cgreylist_merge_sql {
}
sub open_ruledb {
- my ($database, $host, $port) = @_;
+ my ($database, $host, $port, $user) = @_;
$port //= 5432;
@@ -74,13 +74,20 @@ sub open_ruledb {
return $rdb;
} else {
my $dsn = "DBI:Pg:dbname=$database;host=/var/run/postgresql;port=$port";
- my $user = $> == 0 ? 'root' : 'www-data';
+ $user //= $> == 0 ? 'root' : 'www-data';
my $dbh = DBI->connect($dsn, $user, undef, { PrintError => 0, RaiseError => 1 });
return $dbh;
}
}
+sub open_ruledb_as {
+ my ($database, $user) = @_;
+
+ open_ruledb($database, undef, undef, $user);
+}
+
+
sub delete_ruledb {
my ($dbname) = @_;
@@ -609,6 +616,22 @@ sub upgradedb {
}
}
+ foreach my $user ("pmgpolicy", "pmg-smtp-filter") {
+ eval {
+ my $silent_opts = { outfunc => sub {}, errfunc => sub {} };
+ postgres_admin_cmd('createuser', $silent_opts, '-D', $user);
+
+ $dbh->begin_work;
+ $dbh->do("GRANT USAGE, SELECT ON ALL SEQUENCES IN SCHEMA public TO \"$user\"");
+ $dbh->do("GRANT SELECT, INSERT, UPDATE, DELETE ON ALL TABLES IN SCHEMA public TO \"$user\"");
+ $dbh->commit;
+
+ };
+ if (my $err = $@) {
+ $dbh->rollback;
+ }
+ }
+
foreach my $table (keys %$tables) {
eval { $dbh->do("ANALYZE $table"); };
warn $@ if $@;
diff --git a/src/PMG/MailQueue.pm b/src/PMG/MailQueue.pm
index 4e37cb9..adbf28c 100644
--- a/src/PMG/MailQueue.pm
+++ b/src/PMG/MailQueue.pm
@@ -33,12 +33,13 @@ sub create_spooldirs {
"$spooldir/attachment",
]) if $cleanup;
- mkpath([
+ mkpath(
"$spooldir/active",
"$spooldir/spam",
"$spooldir/virus",
"$spooldir/attachment",
- ]);
+ { group=>'pmg', chmod=>0775 },
+ );
if ($lcid) {
mkpath "$spooldir/cluster/$lcid/virus";
@@ -68,7 +69,7 @@ sub new_fileid {
my $uid;
my $subsubdir = '';
- if (!($fh = IO::File->new ($path, 'w+', 0600))) {
+ if (!($fh = IO::File->new ($path, 'w+', 0660))) {
die "unable to create file '$path': $! : ERROR";
}
diff --git a/src/PMG/Report.pm b/src/PMG/Report.pm
index 100a197..3512ecf 100644
--- a/src/PMG/Report.pm
+++ b/src/PMG/Report.pm
@@ -123,7 +123,7 @@ sub check_dns_resolution {
debug => 0,
local_tests_only => 0,
home_dir_for_helpers => '/root',
- userstate_dir => '/root/.spamassassin',
+ userstate_dir => '/var/lib/pmg/spamassassin',
dont_copy_prefs => 1,
stop_at_threshold => 0,
});
diff --git a/src/PMG/Utils.pm b/src/PMG/Utils.pm
index 5d9ded4..09cb42d 100644
--- a/src/PMG/Utils.pm
+++ b/src/PMG/Utils.pm
@@ -1462,7 +1462,7 @@ sub get_pg_server_version {
sub reload_smtp_filter {
- my $pid_file = '/run/pmg-smtp-filter.pid';
+ my $pid_file = '/run/pmg-smtp-filter/pmg-smtp-filter.pid';
my $pid = PVE::Tools::file_read_firstline($pid_file);
return 0 if !$pid;
diff --git a/src/bin/pmg-smtp-filter b/src/bin/pmg-smtp-filter
index 6061459..4a6a643 100755
--- a/src/bin/pmg-smtp-filter
+++ b/src/bin/pmg-smtp-filter
@@ -80,7 +80,7 @@ if (!GetOptions(
exit (-1);
}
-$opt_pidfile = "/run/${prog_name}.pid" if !$opt_pidfile;
+$opt_pidfile = "/run/pmg-smtp-filter/${prog_name}.pid" if !$opt_pidfile;
my $max_servers = 1;
my $min_servers = 1;
@@ -387,7 +387,7 @@ sub load_config {
PMG::MailQueue::create_spooldirs($self->{cinfo}->{local}->{cid});
eval {
- my $dbh = PMG::DBTools::open_ruledb ($database);
+ my $dbh = PMG::DBTools::open_ruledb_as($database, 'pmg-smtp-filter');
$self->{ruledb} = PMG::RuleDB->new ($dbh);
# load rulecache
@@ -460,7 +460,7 @@ sub pre_loop_hook {
debug => 0,
local_tests_only => $opt_testmode || !$rbl_checks,
home_dir_for_helpers => '/root',
- userstate_dir => '/root/.spamassassin',
+ userstate_dir => "/var/lib/pmg/spamassassin",
dont_copy_prefs => 1,
stop_at_threshold => 0,
});
@@ -538,7 +538,7 @@ sub run_dequeue {
my $cinfo = PVE::INotify::read_file("cluster.conf");
- my $dbh = eval { PMG::DBTools::open_ruledb($database) };
+ my $dbh = eval { PMG::DBTools::open_ruledb_as($database, 'pmg-smtp-filter') };
if ($err = $@) {
$self->log (0, "ERROR: $err");
return;
diff --git a/src/bin/pmgpolicy b/src/bin/pmgpolicy
index df2e66f..5e5c69e 100755
--- a/src/bin/pmgpolicy
+++ b/src/bin/pmgpolicy
@@ -56,7 +56,7 @@ if (!GetOptions(%_opts)) {
exit (-1);
}
-$opt_pidfile = "/run/pmgpolicy.pid" if !$opt_pidfile;
+$opt_pidfile = "/run/pmgpolicy/pmgpolicy.pid" if !$opt_pidfile;
$opt_max_dequeue = 0 if $opt_testmode;
initlog('pmgpolicy', 'mail');
@@ -142,7 +142,7 @@ sub run_dequeue {
my $dbh;
eval {
- $dbh = PMG::DBTools::open_ruledb($database);
+ $dbh = PMG::DBTools::open_ruledb_as($database, 'pmgpolicy');
};
my $err = $@;
@@ -343,7 +343,7 @@ sub load_config {
my $dbh;
eval {
- $dbh = PMG::DBTools::open_ruledb($database);
+ $dbh = PMG::DBTools::open_ruledb_as($database, 'pmgpolicy');
$self->{ruledb} = PMG::RuleDB->new($dbh);
$self->{rulecache} = PMG::RuleCache->new($self->{ruledb});
};
@@ -523,7 +523,7 @@ sub greylist_value {
$self->log(0, 'Database connection broken - trying to reconnect');
my $dbh;
eval {
- $dbh = PMG::DBTools::open_ruledb($database);
+ $dbh = PMG::DBTools::open_ruledb_as($database, 'pmgpolicy');
};
my $err = $@;
if ($err) {
--
2.39.2
_______________________________________________
pmg-devel mailing list
pmg-devel@lists.proxmox.com
https://lists.proxmox.com/cgi-bin/mailman/listinfo/pmg-devel
reply other threads:[~2024-05-22 10:35 UTC|newest]
Thread overview: [no followups] expand[flat|nested] mbox.gz Atom feed
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20240522103537.274071-1-m.sandoval@proxmox.com \
--to=m.sandoval@proxmox.com \
--cc=pmg-devel@lists.proxmox.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.