aboutsummaryrefslogtreecommitdiffstats
path: root/lacme
diff options
context:
space:
mode:
Diffstat (limited to 'lacme')
-rwxr-xr-xlacme39
1 files changed, 31 insertions, 8 deletions
diff --git a/lacme b/lacme
index 9a62cbb..ad7e1d8 100755
--- a/lacme
+++ b/lacme
@@ -75,13 +75,33 @@ $COMMAND = $COMMAND =~ /\A(account|newOrder|new-cert|revokeCert|revoke-cert)\z/
: usage(1, "Invalid command: $COMMAND"); # validate and untaint $COMMAND
@ARGV = map { /\A(\p{Print}*)\z/ ? $1 : die } @ARGV; # untaint @ARGV
+sub env_fallback($$) {
+ my $v = $ENV{ shift() };
+ return (defined $v and $v ne "") ? $v : shift;
+}
+sub spec_expand($) {
+ my $str = shift;
+ $str =~ s#%(.)# my $x =
+ $1 eq "C" ? ($< == 0 ? "@@localstatedir@@/cache" : env_fallback(XDG_CACHE_HOME => "$ENV{HOME}/.cache"))
+ : $1 eq "E" ? ($< == 0 ? "@@sysconfdir@@" : env_fallback(XDG_CONFIG_HOME => "$ENV{HOME}/.config"))
+ : $1 eq "g" ? (getgrgid((split /\s/,$()[0]))[0]
+ : $1 eq "G" ? $( =~ s/\s.*//r
+ : $1 eq "h" ? (getpwuid($<))[7]
+ : $1 eq "u" ? (getpwuid($<))[0]
+ : $1 eq "U" ? $<
+ : $1 eq "t" ? ($< == 0 ? "@@runstatedir@@" : $ENV{XDG_RUNTIME_DIR})
+ : $1 eq "T" ? env_fallback(TMPDIR => "/tmp")
+ : $1 eq "%" ? "%"
+ : die "Error: \"$str\" has unknown specifier %$1\n";
+ die "Error: undefined expansion %$1 in \"$str\"\n" unless defined $x;
+ $x;
+ #ge;
+ return $str;
+}
+
sub set_FD_CLOEXEC($$);
-my $CONFFILENAME = $OPTS{config} // first { -f $_ }
- ( ($ENV{XDG_CONFIG_HOME} // "$ENV{HOME}/.config") . "/lacme/$NAME.conf"
- , "@@sysconfdir@@/lacme/$NAME.conf"
- );
+my $CONFFILENAME = spec_expand($OPTS{config} // "%E/lacme/$NAME.conf");
do {
- die "Error: Can't find configuration file\n" unless defined $CONFFILENAME;
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> };
@@ -93,7 +113,7 @@ do {
my $accountd = defined $OPTS{socket} ? 0 : exists $h->{accountd} ? 1 : 0;
my %valid = (
client => {
- socket => (defined $ENV{XDG_RUNTIME_DIR} ? "$ENV{XDG_RUNTIME_DIR}/S.lacme" : undef),
+ socket => '%t/S.lacme',
user => '@@lacme_client_user@@',
group => '@@lacme_client_group@@',
command => '@@libexecdir@@/lacme/client',
@@ -285,6 +305,7 @@ sub spawn_webserver() {
# Use existing HTTPd to serve challenge files using 'challenge-directory'
# as document root
if (defined (my $dir = $conf->{'challenge-directory'})) {
+ $dir = spec_expand($dir);
print STDERR "[$$] Using existing webserver on $dir\n" if $OPTS{debug};
# lacme(8) doesn't have the list of challenge files to delete on
# cleanup -- instead, we unlink all files and fails at
@@ -513,8 +534,9 @@ sub acme_client($@) {
set_FD_CLOEXEC($s, 1);
$ENV{GPG_TTY} = $GPG_TTY if defined $GPG_TTY;
my ($cmd, @args) = split(/\s+/, $accountd->{command}) or die "Empty accountd command\n";
+ $_ = spec_expand($_) foreach ($cmd, @args); # expand %-specifiers after privilege drop and whitespace split
push @args, '--stdio';
- push @args, '--config='.$accountd->{config} if $accountd->{config} ne '';
+ push @args, '--config='.spec_expand($accountd->{config}) if $accountd->{config} ne '';
push @args, '--privkey='.$accountd->{privkey} if $accountd->{privkey} ne ''; # XXX deprecated in 0.8.0
push @args, '--quiet' unless lc $accountd->{quiet} eq 'no';
push @args, '--debug' if $OPTS{debug};
@@ -531,7 +553,7 @@ sub acme_client($@) {
}
else {
my @stat;
- my $sockname = $OPTS{socket} // $conf->{socket} // die "Missing socket option\n";
+ my $sockname = spec_expand($OPTS{socket} // $conf->{socket});
$sockname = $sockname =~ /\A(\p{Print}+)\z/ ? $1 : die "Invalid socket name\n"; # untaint $sockname
# ensure we're the only user with write access to the parent dir
@@ -697,6 +719,7 @@ elsif ($COMMAND eq 'newOrder' or $COMMAND eq 'new-cert') {
my $conffiles = defined $OPTS{'config-certs'} ? $OPTS{'config-certs'}
: defined $CONFIG->{_}->{'config-certs'} ? [ split(/\s+/, $CONFIG->{_}->{'config-certs'}) ]
: [ "$NAME-certs.conf", "$NAME-certs.conf.d/" ];
+ $_ = spec_expand($_) foreach @$conffiles;
my ($conf, %defaults);
foreach my $conffile (@$conffiles) {
$conffile = dirname($CONFFILENAME) .'/'. $conffile unless $conffile =~ /\A\//;