Package: lacme
Version: 0.5-1
Severity: wishlist
Tags: patch upstream

Dear Maintainer,

in our setup multiple http-servers can be used to serve a random file.
For the static files, the storage is syncronized filesystem replication.

When lacme creates a challenge-response for a new certificate, it is
unclear, which of the external servers will serve that request. Due to
the replication, all of the servers could have access to the challenge
file, but currently lacme only creates a symlink into a temporary
directory.

The attached patch adds a new configuration option 
`hard-copy-challenge-directory`,
which will drop the temporary file and handles the acme-challenge
directory directly.

best regards

-- System Information:
Debian Release: 10.5
  APT prefers stable
  APT policy: (500, 'stable')
Architecture: amd64 (x86_64)

Kernel: Linux 4.19.0-10-amd64 (SMP w/1 CPU core)
Locale: LANG=en_GB.UTF-8, LC_CTYPE=en_GB.UTF-8 (charmap=UTF-8), 
LANGUAGE=en_GB.UTF-8 (charmap=UTF-8)
Shell: /bin/sh linked to /bin/dash
Init: systemd (via /run/systemd/system)
LSM: AppArmor: enabled

Versions of packages lacme depends on:
ii  libconfig-tiny-perl       2.23-1
ii  libjson-perl              4.02000-1
ii  libnet-ssleay-perl        1.85-2+b1
ii  libtypes-serialiser-perl  1.0-1
ii  libwww-perl               6.36-2
ii  openssl                   1.1.1d-1+0~20191009.15+debian9~1.gbpd6badf
ii  perl                      5.28.1-6+deb10u1

Versions of packages lacme recommends:
ii  lacme-accountd              0.6-1
ii  liblwp-protocol-https-perl  6.07-2

lacme suggests no packages.

-- Configuration Files:
/etc/lacme/lacme.conf changed [not included]

-- no debconf information

--- a/config/lacme.conf 2020-09-23 14:14:46.274311863 +0200
+++ b/config/lacme.conf 2020-09-23 14:16:19.324643678 +0200
@@ -86,6 +86,10 @@
 #
 #challenge-directory =
 
+# Do not symlink the challenge-directory, but copy the challenge-files
+# explictly
+#hard-copy-challenge-directory = Yes
+
 # username to drop privileges to (setting both effective and real uid).
 # Preserve root privileges if the value is empty (not recommended).
 #
--- a/lacme     2020-09-23 14:16:28.124864204 +0200
+++ b/lacme     2020-09-23 16:14:21.456006087 +0200
@@ -28,6 +28,7 @@
 use Errno 'EINTR';
 use Fcntl qw/F_GETFD F_SETFD FD_CLOEXEC SEEK_SET/;
 use File::Temp ();
+use File::Path 'remove_tree';
 use Getopt::Long qw/:config posix_default no_ignore_case gnu_getopt 
auto_version/;
 use List::Util 'first';
 use POSIX ();
@@ -100,6 +101,7 @@
         webserver => {
             listen                => '/var/run/lacme-www.socket',
             'challenge-directory' => undef,
+            'hard-copy-challenge-directory' => 'No',
             user                  => 'www-data',
             group                 => 'www-data',
             command               => '/usr/lib/lacme/webserver',
@@ -315,10 +317,26 @@
     # serve ACME challenge reponses).
     if (defined (my $dir = $conf->{'challenge-directory'})) {
         print STDERR "[$$] Using existing webserver on $dir\n" if $OPTS{debug};
-        symlink $tmpdir, $dir or die "Can't symlink $dir -> $tmpdir: $!";
-        push @CLEANUP, sub() {
-            print STDERR "Unlinking $dir\n" if $OPTS{debug};
-            unlink $dir or warn "Warning: Can't unlink $dir: $!";
+        if (lc ($conf->{'hard-copy-challenge-directory'} // 'No') eq 'yes') {
+            mkdir $dir or die "Can't create directory $dir: $!";
+            $tmpdir = $dir;
+            push @CLEANUP, sub() {
+                my $error = undef;
+               remove_tree($dir, { safe => 1, error => \$error });
+                if($error && @$error) {
+                    for(@$error) {
+                        my ($file, $message) = %$_;
+                       my $msghead = $file?"Error removing $file in":"Error 
while removing";
+                        warn "$msghead challenge dir $dir: $message\n";
+                    }
+                }
+            }
+       } else {
+            symlink $tmpdir, $dir or die "Can't symlink $dir -> $tmpdir: $!";
+            push @CLEANUP, sub() {
+                print STDERR "Unlinking $dir\n" if $OPTS{debug};
+                unlink $dir or warn "Warning: Can't unlink $dir: $!";
+            }
         }
     }
     elsif (!@sockaddr) {
--- a/config/lacme.conf 2020-09-23 14:14:46.274311863 +0200
+++ b/config/lacme.conf 2020-09-23 14:16:19.324643678 +0200
@@ -86,6 +86,10 @@
 #
 #challenge-directory =
 
+# Do not symlink the challenge-directory, but copy the challenge-files
+# explictly
+#hard-copy-challenge-directory = Yes
+
 # username to drop privileges to (setting both effective and real uid).
 # Preserve root privileges if the value is empty (not recommended).
 #
--- a/lacme     2020-09-23 14:16:28.124864204 +0200
+++ b/lacme     2020-09-23 16:14:21.456006087 +0200
@@ -28,6 +28,7 @@
 use Errno 'EINTR';
 use Fcntl qw/F_GETFD F_SETFD FD_CLOEXEC SEEK_SET/;
 use File::Temp ();
+use File::Path 'remove_tree';
 use Getopt::Long qw/:config posix_default no_ignore_case gnu_getopt 
auto_version/;
 use List::Util 'first';
 use POSIX ();
@@ -100,6 +101,7 @@
         webserver => {
             listen                => '/var/run/lacme-www.socket',
             'challenge-directory' => undef,
+            'hard-copy-challenge-directory' => 'No',
             user                  => 'www-data',
             group                 => 'www-data',
             command               => '/usr/lib/lacme/webserver',
@@ -315,10 +317,26 @@
     # serve ACME challenge reponses).
     if (defined (my $dir = $conf->{'challenge-directory'})) {
         print STDERR "[$$] Using existing webserver on $dir\n" if $OPTS{debug};
-        symlink $tmpdir, $dir or die "Can't symlink $dir -> $tmpdir: $!";
-        push @CLEANUP, sub() {
-            print STDERR "Unlinking $dir\n" if $OPTS{debug};
-            unlink $dir or warn "Warning: Can't unlink $dir: $!";
+        if (lc ($conf->{'hard-copy-challenge-directory'} // 'No') eq 'yes') {
+            mkdir $dir or die "Can't create directory $dir: $!";
+            $tmpdir = $dir;
+            push @CLEANUP, sub() {
+                my $error = undef;
+               remove_tree($dir, { safe => 1, error => \$error });
+                if($error && @$error) {
+                    for(@$error) {
+                        my ($file, $message) = %$_;
+                       my $msghead = $file?"Error removing $file in":"Error 
while removing";
+                        warn "$msghead challenge dir $dir: $message\n";
+                    }
+                }
+            }
+       } else {
+            symlink $tmpdir, $dir or die "Can't symlink $dir -> $tmpdir: $!";
+            push @CLEANUP, sub() {
+                print STDERR "Unlinking $dir\n" if $OPTS{debug};
+                unlink $dir or warn "Warning: Can't unlink $dir: $!";
+            }
         }
     }
     elsif (!@sockaddr) {

Reply via email to