use Net::SSLeay;
use Digest::SHA;
+use PVE::SafeSyslog;
use PVE::Tools;
use PVE::Ticket;
+use PVE::INotify;
use Crypt::OpenSSL::RSA;
+use PMG::Utils;
+use PMG::Config;
+
my $min_ticket_lifetime = -60*5; # allow 5 minutes time drift
my $max_ticket_lifetime = 60*60*2; # 2 hours
-my $basedir = "/etc/proxmox";
+my $basedir = "/etc/pmg";
my $pmg_api_cert_fn = "$basedir/pmg-api.pem";
my $authprivkeyfn = "$basedir/pmg-authkey.key";
my $authpubkeyfn = "$basedir/pmg-authkey.pub";
-# only write output if something fails
-sub run_silent_cmd {
- my ($cmd) = @_;
-
- my $outbuf = '';
-
- my $record_output = sub {
- $outbuf .= shift;
- $outbuf .= "\n";
- };
-
- eval {
- PVE::Tools::run_command($cmd, outfunc => $record_output,
- errfunc => $record_output);
- };
-
- my $err = $@;
-
- if ($err) {
- print STDERR $outbuf;
- die $err;
- }
-}
-
sub generate_api_cert {
- my ($nodename, $force) = @_;
+ my ($force) = @_;
+
+ my $nodename = PVE::INotify::nodename();
if (-f $pmg_api_cert_fn) {
return $pmg_api_cert_fn if !$force;
'-days', '3650'];
eval {
- run_silent_cmd($cmd);
+ PMG::Utils::run_silent_cmd($cmd);
chown(0, $gid, $tmp_fn) || die "chown failed - $!\n";
chmod(0640, $tmp_fn) || die "chmod failed - $!\n";
rename($tmp_fn, $pmg_api_cert_fn) || die "rename failed - $!\n";
my $cmd = ['openssl', 'genrsa', '-out', $tmp_fn, '2048'];
eval {
- run_silent_cmd($cmd);
+ PMG::Utils::run_silent_cmd($cmd);
chown(0, $gid, $tmp_fn) || die "chown failed - $!\n";
chmod(0640, $tmp_fn) || die "chmod failed - $!\n";
rename($tmp_fn, $pmg_csrf_key_fn) || die "rename failed - $!\n";
return if -f "$authprivkeyfn";
eval {
- run_silent_cmd(['openssl', 'genrsa', '-out', $authprivkeyfn, '2048']);
+ my $cmd = ['openssl', 'genrsa', '-out', $authprivkeyfn, '2048'];
+ PMG::Utils::run_silent_cmd($cmd);
- run_silent_cmd(['openssl', 'rsa', '-in', $authprivkeyfn, '-pubout', '-out', $authpubkeyfn]);
+ $cmd = ['openssl', 'rsa', '-in', $authprivkeyfn, '-pubout',
+ '-out', $authpubkeyfn];
+ PMG::Utils::run_silent_cmd($cmd);
};
die "unable to generate pmg auth key:\n$@" if $@;
}
-my $pve_auth_priv_key;
-sub get_privkey {
+my $read_rsa_priv_key = sub {
+ my ($filename, $fh) = @_;
- return $pve_auth_priv_key if $pve_auth_priv_key;
+ local $/ = undef; # slurp mode
- my $input = PVE::Tools::file_get_contents($authprivkeyfn);
+ my $input = <$fh>;
- $pve_auth_priv_key = Crypt::OpenSSL::RSA->new_private_key($input);
+ return Crypt::OpenSSL::RSA->new_private_key($input);
- return $pve_auth_priv_key;
-}
+};
-my $pve_auth_pub_key;
-sub get_pubkey {
+PVE::INotify::register_file('auth_priv_key', $authprivkeyfn,
+ $read_rsa_priv_key, undef, undef,
+ noclone => 1);
- return $pve_auth_pub_key if $pve_auth_pub_key;
+my $read_rsa_pub_key = sub {
+ my ($filename, $fh) = @_;
- my $input = PVE::Tools::file_get_contents($authpubkeyfn);
+ local $/ = undef; # slurp mode
- $pve_auth_pub_key = Crypt::OpenSSL::RSA->new_public_key($input);
+ my $input = <$fh>;
- return $pve_auth_pub_key;
-}
+ return Crypt::OpenSSL::RSA->new_public_key($input);
+};
-my $csrf_prevention_secret;
-my $get_csrfr_secret = sub {
- if (!$csrf_prevention_secret) {
- my $input = PVE::Tools::file_get_contents($pmg_csrf_key_fn);
- $csrf_prevention_secret = Digest::SHA::sha1_base64($input);
- print "SECRET:$csrf_prevention_secret\n";
- }
- return $csrf_prevention_secret;
+PVE::INotify::register_file('auth_pub_key', $authpubkeyfn,
+ $read_rsa_pub_key, undef, undef,
+ noclone => 1);
+
+my $read_csrf_secret = sub {
+ my ($filename, $fh) = @_;
+
+ local $/ = undef; # slurp mode
+
+ my $input = <$fh>;
+
+ return Digest::SHA::sha1_base64($input);
};
+PVE::INotify::register_file('csrf_secret', $pmg_csrf_key_fn,
+ $read_csrf_secret, undef, undef,
+ noclone => 1);
sub verify_csrf_prevention_token {
my ($username, $token, $noerr) = @_;
- my $secret = &$get_csrfr_secret();
+ my $secret = PVE::INotify::read_file('csrf_secret');
return PVE::Ticket::verify_csrf_prevention_token(
$secret, $username, $token, $min_ticket_lifetime,
sub assemble_csrf_prevention_token {
my ($username) = @_;
- my $secret = &$get_csrfr_secret();
+ my $secret = PVE::INotify::read_file('csrf_secret');
return PVE::Ticket::assemble_csrf_prevention_token ($secret, $username);
}
sub assemble_ticket {
my ($username) = @_;
- my $rsa_priv = get_privkey();
+ my $rsa_priv = PVE::INotify::read_file('auth_priv_key');
return PVE::Ticket::assemble_rsa_ticket($rsa_priv, 'PMG', $username);
}
sub verify_ticket {
my ($ticket, $noerr) = @_;
- my $rsa_pub = get_pubkey();
+ my $rsa_pub = PVE::INotify::read_file('auth_pub_key');
return PVE::Ticket::verify_rsa_ticket(
$rsa_pub, 'PMG', $ticket, undef,
sub assemble_vnc_ticket {
my ($username, $path) = @_;
- my $rsa_priv = get_privkey();
+ my $rsa_priv = PVE::INotify::read_file('auth_priv_key');
my $secret_data = "$username:$path";
sub verify_vnc_ticket {
my ($ticket, $username, $path, $noerr) = @_;
- my $rsa_pub = get_pubkey();
+ my $rsa_pub = PVE::INotify::read_file('auth_pub_key');
my $secret_data = "$username:$path";
$rsa_pub, 'PMGVNC', $ticket, $secret_data, -20, 40, $noerr);
}
+# Note: we only encode $pmail into the ticket,
+# and add '@quarantine' in verify_quarantine_ticket()
+sub assemble_quarantine_ticket {
+ my ($pmail) = @_;
+
+ my $rsa_priv = PVE::INotify::read_file('auth_priv_key');
+
+ return PVE::Ticket::assemble_rsa_ticket($rsa_priv, 'PMGQUAR', $pmail);
+}
+
+my $quarantine_lifetime;
+
+my $get_quarantine_lifetime = sub {
+
+ return $quarantine_lifetime if defined($quarantine_lifetime);
+
+ my $cfg = PMG::Config->new();
+
+ $quarantine_lifetime = $cfg->get('spamquar', 'lifetime');
+
+ return $quarantine_lifetime;
+};
+
+sub verify_quarantine_ticket {
+ my ($ticket, $noerr) = @_;
+
+ my $rsa_pub = PVE::INotify::read_file('auth_pub_key');
+
+ my $lifetime = $get_quarantine_lifetime->();
+
+ my ($username, $age) = PVE::Ticket::verify_rsa_ticket(
+ $rsa_pub, 'PMGQUAR', $ticket, undef, -20, $lifetime*86400, $noerr);
+
+ $username = "$username\@quarantine" if defined($username);
+
+ return wantarray ? ($username, $age) : $username;
+}
+
1;