From 9a8f705eddd18ccc9a24fe0e7efe6b5a87b2be09 Mon Sep 17 00:00:00 2001 From: Guilhem Moulin Date: Thu, 25 Feb 2021 01:41:59 +0100 Subject: lacme: pass a temporary JSON file with the client configuration to the internal client. So it doesn't have to parse the INI file again. Also, while lacme.conf is world-readable by default, one might restrict permissions and add private information in there, not realizing that everything, including comments, will be readable by the client. --- Changelog | 2 ++ client | 8 +------- lacme | 26 ++++++++++++++++---------- tests/drop-privileges | 4 ++-- 4 files changed, 21 insertions(+), 19 deletions(-) diff --git a/Changelog b/Changelog index d63c754..8bf0721 100644 --- a/Changelog +++ b/Changelog @@ -11,6 +11,8 @@ lacme (0.8.1) upstream; 'chmod'. + lacme: split certificates using Net::SSLeay::PEM_* instead of calling openssl. + + lacme: pass a temporary JSON file with the client configuration to + the internal client, so it doesn't have to parse the INI file again. - lacme: in the [accountd] config, let lacme-accountd(1) do the %-expansion for 'config', not lacme(8) when building the command. - lacme-accountd: don't log debug messages unless --debug is set. diff --git a/client b/client index 33189d3..8439ddb 100755 --- a/client +++ b/client @@ -56,8 +56,6 @@ use Date::Parse (); use LWP::UserAgent (); use JSON (); -use Config::Tiny (); - # Clean up PATH $ENV{PATH} = join ':', qw{/usr/bin /bin}; delete @ENV{qw/IFS CDPATH ENV BASH_ENV/}; @@ -107,11 +105,7 @@ do { my $CONFIG = do { my $conf = do { local $/ = undef; <$CONFFILE> }; - close $CONFFILE or die "close: $!"; - my $h = Config::Tiny::->read_string($conf) or die Config::Tiny::->errstr()."\n"; - $h->{_} //= {}; - $h->{client}->{$_} //= $h->{_}->{$_} foreach keys %{$h->{_}}; # add defaults - $h->{client}; + JSON::->new->decode($conf); }; my $UA = do { my %args = %$CONFIG; diff --git a/lacme b/lacme index 13c2ef5..d7dac54 100755 --- a/lacme +++ b/lacme @@ -37,13 +37,14 @@ use Socket 1.95 qw/AF_UNIX AF_INET AF_INET6 PF_UNIX PF_INET PF_INET6 PF_UNSPEC use Config::Tiny (); use Date::Parse (); +use JSON (); use Net::SSLeay 1.46 (); # Clean up PATH $ENV{PATH} = join ':', qw{/usr/bin /bin}; delete @ENV{qw/IFS CDPATH ENV BASH_ENV/}; -my ($COMMAND, %OPTS, $CONFFILE, $CONFIG, @CLEANUP); +my ($COMMAND, %OPTS, $CONFIG, @CLEANUP); $SIG{$_} = sub() { exit 1 } foreach qw/INT TERM/; # run the END block upon SIGINT/SIGTERM @@ -99,14 +100,12 @@ sub spec_expand($) { return $str; } -sub set_FD_CLOEXEC($$); my $CONFFILENAME = spec_expand($OPTS{config} // "%E/lacme/$NAME.conf"); do { print STDERR "Using configuration file: $CONFFILENAME\n" if $OPTS{debug}; - open $CONFFILE, '<', $CONFFILENAME or die "Can't open $CONFFILENAME: $!\n"; - my $conf = do { local $/ = undef; <$CONFFILE> }; - # don't close $CONFFILE so we can pass it to the client - set_FD_CLOEXEC($CONFFILE, 1); + open my $fh, '<', $CONFFILENAME or die "Can't open $CONFFILENAME: $!\n"; + my $conf = do { local $/ = undef; <$fh> }; + close $fh or die "close: $!"; my $h = Config::Tiny::->read_string($conf) or die Config::Tiny::->errstr()."\n"; my $defaults = delete $h->{_} // {}; @@ -573,19 +572,26 @@ sub acme_client($@) { die "connect: $!"; } } + set_FD_CLOEXEC($client, 1); + + my $client_config; + do { + my $tmp = File::Temp::->new(TMPDIR => 1, TEMPLATE => "lacme-client.conf.json-XXXXXXXXXX", UNLINK => 1) // die; + print $tmp JSON::->new->encode($conf); + open $client_config, "<", $tmp->filename() or die "open: $!"; + }; # use execve(2) rather than a Perl pseudo-process to ensure that the # child doesn't have access to the parent's memory my ($cmd, @args2) = split(/\s+/, $conf->{command}) or die "Empty client command\n"; - my @fileno = map { fileno($_) =~ /^(\d+)$/ ? $1 : die } ($CONFFILE, $client); # untaint fileno - set_FD_CLOEXEC($client, 1); + my @fileno = map { fileno($_) =~ /^(\d+)$/ ? $1 : die } ($client_config, $client); # untaint fileno my $rv = spawn({in => $args->{in}, out => $args->{out}, child => sub() { drop_privileges($conf->{user}, $conf->{group}, $args->{chdir} // '/'); umask(0022) // die; - set_FD_CLOEXEC($_, 0) foreach ($CONFFILE, $client); - seek($CONFFILE, SEEK_SET, 0) or die "seek: $!"; + set_FD_CLOEXEC($_, 0) for ($client_config, $client); $ENV{DEBUG} = $OPTS{debug} // 0; }}, $cmd, @args2, $COMMAND, @fileno, @args); + close $client_config or die "close: $!\n"; if (defined $cleanup) { @CLEANUP = grep { $_ ne $cleanup } @CLEANUP; diff --git a/tests/drop-privileges b/tests/drop-privileges index fd432d9..8deb8f1 100644 --- a/tests/drop-privileges +++ b/tests/drop-privileges @@ -123,8 +123,8 @@ check_client() { grep -Exq "[0-9]+ 0700 $UID:$GID socket:\[[0-9]+\]" "$prefix/fd" || return 1 sed -ri '0,\#^[0-9]+ .* socket:\[[0-9]+\]$# {//d}' "$prefix/fd" - grep -Exq "[0-9]+ 0500 $UID:$GID /etc/lacme/lacme\.conf" "$prefix/fd" || return 1 - sed -ri '0,\#^[0-9]+ .* /etc/lacme/lacme\.conf$# {//d}' "$prefix/fd" + grep -Eq "^[0-9]+ 0500 $UID:$GID /tmp/lacme-client.conf\.json-" "$prefix/fd" || return 1 + sed -ri '0,\#^[0-9]+ .* /tmp/lacme-client.conf\.json-# {//d}' "$prefix/fd" ! test -s "$prefix/fd" || return 1 } check_webserver() { -- cgit v1.2.3