From bb5efce091215432fd2b82fbf50aff1536d415f6 Mon Sep 17 00:00:00 2001 From: Guilhem Moulin Date: Mon, 5 Dec 2016 14:54:28 +0100 Subject: "config-certs" now points to a list of files or directories. --- Changelog | 2 ++ Makefile | 1 + config/lacme.conf | 6 ++--- lacme | 65 ++++++++++++++++++++++++++++++++++--------------------- lacme.md | 21 ++++++++++-------- 5 files changed, 58 insertions(+), 37 deletions(-) diff --git a/Changelog b/Changelog index 3018a4d..f685306 100644 --- a/Changelog +++ b/Changelog @@ -8,6 +8,8 @@ lacme (0.2) upstream; ignored, and the two processes communicate through a socket pair. + lacme: add an option --quiet to avoid mentioning valid certs (useful in cronjobs) + + "config-certs" now points to a space separated list of files or + directories. New default "lacme-certs.conf lacme-certs.d/". - Minor manpage fixes - More useful message upon Validation Challenge failure. diff --git a/Makefile b/Makefile index 4e5f06d..d83c843 100644 --- a/Makefile +++ b/Makefile @@ -25,6 +25,7 @@ all: ${MANPAGES} install: ${MANPAGES} install -d $(DESTDIR)/etc/lacme + install -d $(DESTDIR)/etc/lacme/lacme-certs.d install -m0644 -t $(DESTDIR)/etc/lacme config/*.conf install -d $(DESTDIR)/usr/share/lacme install -m0644 -t $(DESTDIR)/usr/share/lacme certs/lets-encrypt-x[1-4]-cross-signed.pem diff --git a/config/lacme.conf b/config/lacme.conf index 08afeb4..f963128 100644 --- a/config/lacme.conf +++ b/config/lacme.conf @@ -1,7 +1,7 @@ -# For certificate issuance (new-cert command), specify the certificate -# configuration file to use +# For certificate issuance (new-cert command), specify a space-separated +# certificate configuration files or directories to use # -#config-certs = /etc/lacme/lacme-certs.conf +#config-certs = lacme-certs.conf lacme-certs.d/ [client] diff --git a/lacme b/lacme index 86071fd..3b7c174 100755 --- a/lacme +++ b/lacme @@ -60,7 +60,7 @@ sub usage(;$$) { } exit $rv; } -usage(1) unless GetOptions(\%OPTS, qw/config=s config-certs=s socket=s agreement-uri=s quiet|q debug help|h/); +usage(1) unless GetOptions(\%OPTS, qw/config=s config-certs=s@ socket=s agreement-uri=s quiet|q debug help|h/); usage(0) if $OPTS{help}; $COMMAND = shift(@ARGV) // usage(1, "Missing command"); @@ -68,15 +68,15 @@ $COMMAND = $COMMAND =~ /\A(new-reg|reg=\p{Print}*|new-cert|revoke-cert)\z/ ? $1 : usage(1, "Invalid command: $COMMAND"); # validate and untaint $COMMAND @ARGV = map { /\A(\p{Print}*)\z/ ? $1 : die } @ARGV; # untaint @ARGV +my $CONFFILENAME = $OPTS{config} // first { -f $_ } + ( "./$NAME.conf" + , ($ENV{XDG_CONFIG_HOME} // "$ENV{HOME}/.config")."/lacme/$NAME.conf" + , "/etc/lacme/$NAME.conf" + ); do { - my $conffile = $OPTS{config} // first { -f $_ } - ( "./$NAME.conf" - , ($ENV{XDG_CONFIG_HOME} // "$ENV{HOME}/.config")."/lacme/$NAME.conf" - , "/etc/lacme/$NAME.conf" - ); - die "Error: Can't find configuration file\n" unless defined $conffile; - print STDERR "Using configuration file: $conffile\n" if $OPTS{debug}; - open $CONFFILE, '<', $conffile or die "Can't open $conffile: $!\n"; + 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> }; # don't close $CONFFILE so we can pass it to the client @@ -559,24 +559,39 @@ if ($COMMAND eq 'new-reg' or $COMMAND =~ /^reg=/) { # new-cert [SECTION ..] # elsif ($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.d/" ]; my $conf; - do { - my $conffile = $OPTS{'config-certs'} // $CONFIG->{_}->{'config-certs'} // first { -f $_ } - ( "./$NAME-certs.conf" - , ($ENV{XDG_CONFIG_HOME} // "$ENV{HOME}/.config")."/lacme/$NAME-certs.conf" - , "/etc/lacme/$NAME-certs.conf" - ); - die "Error: Can't find certificate configuration file\n" unless defined $conffile; - my $h = Config::Tiny::->read($conffile) or die Config::Tiny::->errstr()."\n"; - my $defaults = delete $h->{_} // {}; - my @valid = qw/certificate certificate-chain certificate-key min-days CAfile - hash keyUsage subject subjectAltName chown chmod notify/; - foreach my $s (keys %$h) { - $conf->{$s} = { map { $_ => delete $h->{$s}->{$_} } @valid }; - die "Unknown option(s) in [$s]: ".join(', ', keys %{$h->{$s}})."\n" if %{$h->{$s}}; - $conf->{$s}->{$_} //= $defaults->{$_} foreach keys %$defaults; + foreach my $conffile (@$conffiles) { + $conffile = ($CONFFILENAME =~ s#[^/]+\z##r).$conffile unless $conffile =~ /\A\//; + my @filenames; + unless ($conffile =~ s#/\z## or -d $conffile) { + @filenames = ($conffile); + } else { + opendir my $dh, $conffile or die "Can't opendir $conffile: $!\n"; + while (readdir $dh) { + if (/\.conf\z/) { + push @filenames, "$conffile/$_"; + } elsif ($_ ne '.' and $_ ne '..') { + warn "$conffile/$_ has unknown suffix, skipping\n"; + } + } + closedir $dh; } - }; + foreach my $filename (sort @filenames) { + print STDERR "Reading $filename\n" if $OPTS{debug}; + my $h = Config::Tiny::->read($filename) or die Config::Tiny::->errstr()."\n"; + my $defaults = delete $h->{_} // {}; + my @valid = qw/certificate certificate-chain certificate-key min-days CAfile + hash keyUsage subject subjectAltName chown chmod notify/; + foreach my $s (keys %$h) { + $conf->{$s} = { map { $_ => delete $h->{$s}->{$_} } @valid }; + die "Unknown option(s) in [$s]: ".join(', ', keys %{$h->{$s}})."\n" if %{$h->{$s}}; + $conf->{$s}->{$_} //= $defaults->{$_} foreach keys %$defaults; + } + } + } my $challenge_dir; my $rv = 0; diff --git a/lacme.md b/lacme.md index 24973db..69e3ce2 100644 --- a/lacme.md +++ b/lacme.md @@ -151,9 +151,18 @@ Default section *config-certs* : For certificate issuances (`new-cert` command), specify the - certificate configuration file to use (see the **[certificate - configuration file](#certificate-configuration-file)** section below - for the configuration options). + space-separated list of certificate configuration files or + directories to use (see the **[certificate configuration + file](#certificate-configuration-file)** section below for the + configuration options). + + Paths not starting with `/` are relative to the directory name of + the **[configuration filename](#configuration-file)**. The list of + files and directories is processed in order, with the later items + taking precedence. Files in a directory are processed in + lexicographic order, only considering the ones with suffix `.conf`. + + Default: `lacme-certs.conf lacme-certs.d/`. `[client]` section ------------------ @@ -303,12 +312,6 @@ Certificate configuration file For certificate issuances (`new-cert` command), a separate file is used to configure paths to the certificate and key, as well as the subject, subjectAltName, etc. to generate Certificate Signing Requests. -If `--config-certs=` is not given, and if the `config-certs` -configuration option is absent, then `lacme` uses the first existing -configuration file among *./lacme-certs.conf*, -*$XDG_CONFIG_HOME/lacme/lacme-certs.conf* (or -*~/.config/lacme/lacme-certs.conf* if the `XDG_CONFIG_HOME` environment -variable is not set), and */etc/lacme/lacme-certs.conf*. Each section denotes a separate certificate issuance. Valid options are: -- cgit v1.2.3