From 37a1daaf01431038de4ea983c4093fd2e271336f Mon Sep 17 00:00:00 2001 From: Guilhem Moulin Date: Thu, 1 Dec 2016 10:56:11 +0100 Subject: lacme.conf: mention the default groupname for the ACME client. --- config/lacme.conf | 1 + 1 file changed, 1 insertion(+) diff --git a/config/lacme.conf b/config/lacme.conf index 39cfd36..a52689a 100644 --- a/config/lacme.conf +++ b/config/lacme.conf @@ -25,6 +25,7 @@ # groupname to drop privileges to (setting both effective and real gid, # and also setting the list of supplementary gids to that single group). # Preserve root privileges if the value is empty (not recommended). +# Default: "nogroup". # #group = nogroup -- cgit v1.2.3 From 8184304b3e7c5ae92779f7f6bc8c4bb1aeb2d8eb Mon Sep 17 00:00:00 2001 From: Guilhem Moulin Date: Thu, 1 Dec 2016 11:39:38 +0100 Subject: Revert "lacme: avoid spawning multiple accountd processes." This reverts commit 8faab5db6571972156f45b5838b23dbb0fadd5c4. We can't reuse the socket pair as we don't connect(2) to it. --- lacme | 44 ++++++++++++++++++++------------------------ 1 file changed, 20 insertions(+), 24 deletions(-) diff --git a/lacme b/lacme index cf2f9eb..839d53d 100755 --- a/lacme +++ b/lacme @@ -395,7 +395,6 @@ sub spawn_webserver() { # If $args->{in} is defined, the data is written to the client's STDIN. # If $args->{out} is defined, its value is set to client's STDOUT data. # -my $ACCOUNTD = 0; sub acme_client($@) { my $args = shift; my @args = @_; @@ -403,30 +402,27 @@ sub acme_client($@) { my $client; my $conf = $CONFIG->{client}; if (defined (my $accountd = $CONFIG->{accountd})) { - unless ($ACCOUNTD) { - socketpair($client, my $s, AF_UNIX, SOCK_STREAM, PF_UNSPEC) or die "socketpair: $!"; - my $pid = fork() // "fork: $!"; - unless ($pid) { - drop_privileges($accountd->{user}, $accountd->{group}, '/'); - set_FD_CLOEXEC($s, 0); - $client->close() or die "Can't close: $!"; - my @cmd = ($accountd->{command}, '--fdopen='.fileno($s)); - push @cmd, '--config='.$accountd->{config} if defined $accountd->{config}; - push @cmd, '--privkey='.$accountd->{privkey} if defined $accountd->{privkey}; - push @cmd, '--quiet' unless lc $accountd->{quiet} eq 'no'; - push @cmd, '--debug' if $OPTS{debug}; - exec { $cmd[0] } @cmd or die; - } - print STDERR "[$$] Forking lacme-accountd, child PID $pid\n" if $OPTS{debug}; - $ACCOUNTD = $pid; - $s->close() or die "Can't close: $!"; - push @CLEANUP, sub() { - print STDERR "[$$] Shutting down lacme-accountd\n" if $OPTS{debug}; - shutdown($client, SHUT_RDWR) or warn "shutdown: $!"; - kill 15 => $pid; - waitpid $pid => 0; - }; + socketpair($client, my $s, AF_UNIX, SOCK_STREAM, PF_UNSPEC) or die "socketpair: $!"; + my $pid = fork() // "fork: $!"; + unless ($pid) { + drop_privileges($accountd->{user}, $accountd->{group}, '/'); + set_FD_CLOEXEC($s, 0); + $client->close() or die "Can't close: $!"; + my @cmd = ($accountd->{command}, '--fdopen='.fileno($s)); + push @cmd, '--config='.$accountd->{config} if defined $accountd->{config}; + push @cmd, '--privkey='.$accountd->{privkey} if defined $accountd->{privkey}; + push @cmd, '--quiet' unless lc $accountd->{quiet} eq 'no'; + push @cmd, '--debug' if $OPTS{debug}; + exec { $cmd[0] } @cmd or die; } + print STDERR "[$$] Forking lacme-accountd, child PID $pid\n" if $OPTS{debug}; + $s->close() or die "Can't close: $!"; + push @CLEANUP, sub() { + print STDERR "[$$] Shutting down lacme-accountd\n" if $OPTS{debug}; + shutdown($client, SHUT_RDWR) or warn "shutdown: $!"; + kill 15 => $pid; + waitpid $pid => 0; + }; } else { my @stat; -- cgit v1.2.3 From 4d24f126319cf86b33d7c999f8ceabe0bb1f4abc Mon Sep 17 00:00:00 2001 From: Guilhem Moulin Date: Thu, 1 Dec 2016 11:57:31 +0100 Subject: lacme: terminate the accountd when the ACME client terminates. --- lacme | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/lacme b/lacme index 839d53d..edcc77e 100755 --- a/lacme +++ b/lacme @@ -399,7 +399,7 @@ sub acme_client($@) { my $args = shift; my @args = @_; - my $client; + my ($client, $cleanup); my $conf = $CONFIG->{client}; if (defined (my $accountd = $CONFIG->{accountd})) { socketpair($client, my $s, AF_UNIX, SOCK_STREAM, PF_UNSPEC) or die "socketpair: $!"; @@ -417,12 +417,12 @@ sub acme_client($@) { } print STDERR "[$$] Forking lacme-accountd, child PID $pid\n" if $OPTS{debug}; $s->close() or die "Can't close: $!"; - push @CLEANUP, sub() { + $cleanup = sub() { print STDERR "[$$] Shutting down lacme-accountd\n" if $OPTS{debug}; shutdown($client, SHUT_RDWR) or warn "shutdown: $!"; - kill 15 => $pid; - waitpid $pid => 0; + $client->close() or warn "close: $!"; }; + push @CLEANUP, $cleanup; } else { my @stat; @@ -451,12 +451,18 @@ sub acme_client($@) { # child doesn't have access to the parent's memory my @fileno = map { fileno($_) =~ /^(\d+)$/ ? $1 : die } ($CONFFILE, $client); # untaint fileno set_FD_CLOEXEC($client, 1); - spawn({%$args{qw/in out/}, child => sub() { + my $rv = spawn({%$args{qw/in out/}, child => sub() { drop_privileges($conf->{user}, $conf->{group}, $args->{chdir} // '/'); set_FD_CLOEXEC($_, 0) foreach ($CONFFILE, $client); seek($CONFFILE, SEEK_SET, 0) or die "Can't seek: $!"; $ENV{DEBUG} = $OPTS{debug}; }}, $conf->{command}, $COMMAND, @fileno, @args); + + if (defined $cleanup) { + @CLEANUP = grep { $_ ne $cleanup } @CLEANUP; + $cleanup->(); + } + return $rv; } sub spawn($@) { -- cgit v1.2.3 From 78acf82bd5f19b2d317de2c27e9ea2b7cd0d5633 Mon Sep 17 00:00:00 2001 From: Guilhem Moulin Date: Thu, 1 Dec 2016 13:50:01 +0100 Subject: manpage: change reg ID example to 123456. --- lacme.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lacme.md b/lacme.md index b086fe7..41d6428 100644 --- a/lacme.md +++ b/lacme.md @@ -383,7 +383,7 @@ Examples ======== ~$ sudo lacme new-reg mailto:noreply@example.com - ~$ sudo lacme reg=/acme/reg/137760 --agreement-uri=https://letsencrypt.org/documents/LE-SA-v1.1.1-August-1-2016.pdf + ~$ sudo lacme reg=/acme/reg/123456 --agreement-uri=https://letsencrypt.org/documents/LE-SA-v1.1.1-August-1-2016.pdf ~$ sudo lacme new-cert ~$ sudo lacme revoke-cert /path/to/server/certificate.pem -- cgit v1.2.3 From d39ec1c01a622996b5470ec6ce359be254f5274e Mon Sep 17 00:00:00 2001 From: Guilhem Moulin Date: Thu, 1 Dec 2016 13:52:14 +0100 Subject: wibble --- config/lacme-certs.conf | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/config/lacme-certs.conf b/config/lacme-certs.conf index 9b9df2f..45c46a8 100644 --- a/config/lacme-certs.conf +++ b/config/lacme-certs.conf @@ -7,8 +7,12 @@ # Comma-separated list of Key Usages, see x509v3_config(5ssl). #keyUsage = digitalSignature, keyEncipherment + #[www] +# Path the service's private key. This option is required. +#certificate-key = /etc/nginx/ssl/srv.key + # Where to store the issued certificate (in PEM format). #certificate = /etc/nginx/ssl/srv.pem @@ -16,9 +20,6 @@ # of the file specified specified with the CAfile option (in PEM format). #certificate-chain = /etc/nginx/ssl/srv.chain.pem -# Path the service's private key. This option is required. -#certificate-key = /etc/nginx/ssl/srv.key - # For an existing certificate, the minimum number of days before its # expiration date the section is considered for re-issuance. #min-days = 10 @@ -39,7 +40,7 @@ # certificate-chain with. #chown = root:root -# octal mode to chmod the issued certificate and certificate-chain with. +# Octal mode to chmod the issued certificate and certificate-chain with. #chmod = 0644 # Command to pass the the system's command shell ("/bin/sh -c") after -- cgit v1.2.3 From ac0362fb5a5e83b0ed6c1e31c2c1f3d1dfbc1ced Mon Sep 17 00:00:00 2001 From: Guilhem Moulin Date: Thu, 1 Dec 2016 13:59:25 +0100 Subject: Improve formatting of config files. --- config/lacme-certs.conf | 16 ++++++++++++++-- config/lacme.conf | 16 +++++++++++++--- 2 files changed, 27 insertions(+), 5 deletions(-) diff --git a/config/lacme-certs.conf b/config/lacme-certs.conf index 45c46a8..12fcd54 100644 --- a/config/lacme-certs.conf +++ b/config/lacme-certs.conf @@ -1,50 +1,62 @@ -# Each non-default section denotes a separate certificate issuance. -# Options in the default section apply to each sections. +# Each non-default section refer to separate certificate issuance +# requests. Options in the default section apply to each sections. # Message digest to sign the Certificate Signing Request with. +# #hash = sha512 # Comma-separated list of Key Usages, see x509v3_config(5ssl). +# #keyUsage = digitalSignature, keyEncipherment #[www] # Path the service's private key. This option is required. +# #certificate-key = /etc/nginx/ssl/srv.key # Where to store the issued certificate (in PEM format). +# #certificate = /etc/nginx/ssl/srv.pem # Where to store the issued certificate, concatenated with the content # of the file specified specified with the CAfile option (in PEM format). +# #certificate-chain = /etc/nginx/ssl/srv.chain.pem # For an existing certificate, the minimum number of days before its # expiration date the section is considered for re-issuance. +# #min-days = 10 # Path to the issuer's certificate. This is used for certificate-chain # and to verify the validity of each issued certificate. Specifying an # empty value skip certificate validation. +# #CAfile = /usr/share/lacme/lets-encrypt-x3-cross-signed.pem # Subject field of the Certificate Signing Request. This option is # required. +# #subject = /CN=example.org # Comma-separated list of Subject Alternative Names. +# #subjectAltName = DNS:example.org,DNS:www.example.org # username[:groupname] to chown the issued certificate and # certificate-chain with. +# #chown = root:root # Octal mode to chmod the issued certificate and certificate-chain with. +# #chmod = 0644 # Command to pass the the system's command shell ("/bin/sh -c") after # successful installation of the certificate and/or certificate-chain. +# #notify = /bin/systemctl reload nginx diff --git a/config/lacme.conf b/config/lacme.conf index a52689a..08afeb4 100644 --- a/config/lacme.conf +++ b/config/lacme.conf @@ -3,7 +3,9 @@ # #config-certs = /etc/lacme/lacme-certs.conf + [client] + # The value of "socket" specifies the path to the lacme-accountd(1) # UNIX-domain socket to connect to for signature requests from the ACME # client. lacme(1) aborts if the socket is readable or writable by @@ -30,6 +32,7 @@ #group = nogroup # Path to the ACME client executable. +# #command = /usr/lib/lacme/client # Root URI of the ACME server. NOTE: Use the staging server for testing @@ -44,12 +47,15 @@ #timeout = 10 # Whether to verify the server certificate chain. +# #SSL_verify = yes # Specify the version of the SSL protocol used to transmit data. +# #SSL_version = SSLv23:!TLSv1_1:!TLSv1:!SSLv3:!SSLv2 # Specify the cipher list for the connection. +# #SSL_cipher_list = EECDH+AESGCM:!MEDIUM:!LOW:!EXP:!aNULL:!eNULL @@ -88,10 +94,10 @@ #iptables = Yes -# lacme-accound(1) section. Comment out the following section to make -# lacme(1) connect to an existing UNIX-domain socket bound by a running -# acme-accountd(1) process. [accountd] +# lacme-accound(1) section. Comment out this section (including its +# header) to make lacme(1) connect to an existing UNIX-domain socket +# bound by a running acme-accountd(1) process. # username to drop privileges to (setting both effective and real uid). # Preserve root privileges if the value is empty. @@ -105,16 +111,20 @@ #group = root # Path to the lacme-accountd(1) executable. +# #command = /usr/bin/lacme-accountd # Path to the lacme-accountd(1) configuration file. +# #config = /etc/lacme/lacme-accountd.conf # The (private) account key to use for signing requests. See # lacme-accountd(1) for details. +# #privkey = file:/path/to/account.key # Be quiet. +# #quiet = Yes ; vim:ft=dosini -- cgit v1.2.3 From 43670c2dc73148babfd8790070fc24982a71fd82 Mon Sep 17 00:00:00 2001 From: Guilhem Moulin Date: Sat, 3 Dec 2016 16:22:03 +0100 Subject: Precise that --socket=PATH is ignored when the config file as an "accountd" section. --- lacme.md | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/lacme.md b/lacme.md index 41d6428..24973db 100644 --- a/lacme.md +++ b/lacme.md @@ -115,9 +115,13 @@ Generic options : Use *path* as the [`lacme-accountd`(1)] UNIX-domain socket to connect to for signature requests from the [ACME] client. `lacme` aborts if `path` is readable or writable by other users, or if its - parent directory is writable by other users. This overrides the - *socket* option of the [`[client]` section](#client-section) of the - configuration file. + parent directory is writable by other users. + This command-line option overrides the *socket* option of the + [`[client]` section](#client-section) of the configuration file. + Moreover this option is ignored when the configuration file has an + [`[accountd]` section](#accountd-section); in that case `lacme` + spawns [`lacme-accountd`(1)], and the two processes communicate + through a socket pair. `-h`, `--help` -- cgit v1.2.3 From 807f56024225a02963792bd97ded87a6094ef7eb Mon Sep 17 00:00:00 2001 From: Guilhem Moulin Date: Sat, 3 Dec 2016 17:00:06 +0100 Subject: s/--fdopen/--fd-conn/ --- lacme | 2 +- lacme-accountd | 9 +++++---- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/lacme b/lacme index edcc77e..03ce556 100755 --- a/lacme +++ b/lacme @@ -408,7 +408,7 @@ sub acme_client($@) { drop_privileges($accountd->{user}, $accountd->{group}, '/'); set_FD_CLOEXEC($s, 0); $client->close() or die "Can't close: $!"; - my @cmd = ($accountd->{command}, '--fdopen='.fileno($s)); + my @cmd = ($accountd->{command}, '--fd-conn='.fileno($s)); push @cmd, '--config='.$accountd->{config} if defined $accountd->{config}; push @cmd, '--privkey='.$accountd->{privkey} if defined $accountd->{privkey}; push @cmd, '--quiet' unless lc $accountd->{quiet} eq 'no'; diff --git a/lacme-accountd b/lacme-accountd index 411538d..55ae0c0 100755 --- a/lacme-accountd +++ b/lacme-accountd @@ -59,7 +59,7 @@ sub usage(;$$) { } exit $rv; } -usage(1) unless GetOptions(\%OPTS, qw/config=s privkey=s socket=s fdopen=i quiet|q debug help|h/); +usage(1) unless GetOptions(\%OPTS, qw/config=s privkey=s socket=s fd-conn=i quiet|q debug help|h/); usage(0) if $OPTS{help}; do { @@ -137,8 +137,9 @@ $JWK = JSON::->new->encode($JWK); # to support the abstract namespace.) The downside is that we have to # delete the file manually. # -if (defined $OPTS{fdopen}) { - die "Invalid file descriptor" unless $OPTS{fdopen} =~ /\A(\d+)\z/; +if (defined $OPTS{'fd-conn'}) { + die "Invalid file descriptor" unless $OPTS{'fd-conn'} =~ /\A(\d+)\z/; + # untaint and fdopen(3) our end of the socket pair open $S, '+<&=', $1 or die "fdopen $1: $!"; } else { my $sockname = $OPTS{socket} // (defined $ENV{XDG_RUNTIME_DIR} ? "$ENV{XDG_RUNTIME_DIR}/S.lacme" : undef); @@ -182,7 +183,7 @@ sub conn($;$) { } } -if (defined $OPTS{fdopen}) { +if (defined $OPTS{'fd-conn'}) { conn($S, $$); } else { $SIG{PIPE} = 'IGNORE'; # ignore broken pipes -- cgit v1.2.3 From c18ca98345ba54462a3199679f15c80da0634eef Mon Sep 17 00:00:00 2001 From: Guilhem Moulin Date: Sat, 3 Dec 2016 16:53:48 +0100 Subject: Prepare new release. --- Changelog | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/Changelog b/Changelog index b8d5780..3018a4d 100644 --- a/Changelog +++ b/Changelog @@ -1,3 +1,18 @@ +lacme (0.2) upstream; + + + Honor Retry-After headers for certificate issuance and challenge + responses. + + Update example of Subscriber Agreement URL to v1.1.1. + + lacme: automaticall spawn lacme-acountd when a "[accountd]" section + is present in the configuration file. The "socket" option is then + ignored, and the two processes communicate through a socket pair. + + lacme: add an option --quiet to avoid mentioning valid certs (useful + in cronjobs) + - Minor manpage fixes + - More useful message upon Validation Challenge failure. + + -- Guilhem Moulin Sat, 03 Dec 2016 16:40:56 +0100 + lacme (0.1) upstream; * Initial public release. Development was started in December 2015. -- cgit v1.2.3 From 1d1072ac291b1a086d4b15cd611cb74e41667115 Mon Sep 17 00:00:00 2001 From: Guilhem Moulin Date: Mon, 5 Dec 2016 16:22:59 +0100 Subject: s/fd-conn/conn-fd/ --- lacme | 2 +- lacme-accountd | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/lacme b/lacme index 03ce556..86071fd 100755 --- a/lacme +++ b/lacme @@ -408,7 +408,7 @@ sub acme_client($@) { drop_privileges($accountd->{user}, $accountd->{group}, '/'); set_FD_CLOEXEC($s, 0); $client->close() or die "Can't close: $!"; - my @cmd = ($accountd->{command}, '--fd-conn='.fileno($s)); + my @cmd = ($accountd->{command}, '--conn-fd='.fileno($s)); push @cmd, '--config='.$accountd->{config} if defined $accountd->{config}; push @cmd, '--privkey='.$accountd->{privkey} if defined $accountd->{privkey}; push @cmd, '--quiet' unless lc $accountd->{quiet} eq 'no'; diff --git a/lacme-accountd b/lacme-accountd index 55ae0c0..00d6ccd 100755 --- a/lacme-accountd +++ b/lacme-accountd @@ -59,7 +59,7 @@ sub usage(;$$) { } exit $rv; } -usage(1) unless GetOptions(\%OPTS, qw/config=s privkey=s socket=s fd-conn=i quiet|q debug help|h/); +usage(1) unless GetOptions(\%OPTS, qw/config=s privkey=s socket=s conn-fd=i quiet|q debug help|h/); usage(0) if $OPTS{help}; do { @@ -137,8 +137,8 @@ $JWK = JSON::->new->encode($JWK); # to support the abstract namespace.) The downside is that we have to # delete the file manually. # -if (defined $OPTS{'fd-conn'}) { - die "Invalid file descriptor" unless $OPTS{'fd-conn'} =~ /\A(\d+)\z/; +if (defined $OPTS{'conn-fd'}) { + die "Invalid file descriptor" unless $OPTS{'conn-fd'} =~ /\A(\d+)\z/; # untaint and fdopen(3) our end of the socket pair open $S, '+<&=', $1 or die "fdopen $1: $!"; } else { @@ -183,7 +183,7 @@ sub conn($;$) { } } -if (defined $OPTS{'fd-conn'}) { +if (defined $OPTS{'conn-fd'}) { conn($S, $$); } else { $SIG{PIPE} = 'IGNORE'; # ignore broken pipes -- cgit v1.2.3 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 From 0eb9f40182299b2615f5ac0190d40429f5f64ed7 Mon Sep 17 00:00:00 2001 From: Guilhem Moulin Date: Mon, 5 Dec 2016 16:45:27 +0100 Subject: s/lacme-certs.d/lacme-certs.conf.d/ --- Changelog | 2 +- Makefile | 2 +- config/lacme.conf | 3 ++- lacme | 2 +- lacme.md | 2 +- 5 files changed, 6 insertions(+), 5 deletions(-) diff --git a/Changelog b/Changelog index f685306..6f212b0 100644 --- a/Changelog +++ b/Changelog @@ -9,7 +9,7 @@ lacme (0.2) upstream; + 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/". + directories. New default "lacme-certs.conf lacme-certs.conf.d/". - Minor manpage fixes - More useful message upon Validation Challenge failure. diff --git a/Makefile b/Makefile index d83c843..3b61341 100644 --- a/Makefile +++ b/Makefile @@ -25,7 +25,7 @@ all: ${MANPAGES} install: ${MANPAGES} install -d $(DESTDIR)/etc/lacme - install -d $(DESTDIR)/etc/lacme/lacme-certs.d + install -d $(DESTDIR)/etc/lacme/lacme-certs.conf.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 f963128..c5efb03 100644 --- a/config/lacme.conf +++ b/config/lacme.conf @@ -1,7 +1,7 @@ # For certificate issuance (new-cert command), specify a space-separated # certificate configuration files or directories to use # -#config-certs = lacme-certs.conf lacme-certs.d/ +#config-certs = lacme-certs.conf lacme-certs.conf.d/ [client] @@ -85,6 +85,7 @@ #group = www-data # Path to the ACME webserver executable. +# #command = /usr/lib/lacme/webserver # Whether to automatically install iptables(8) rules to open the diff --git a/lacme b/lacme index 3b7c174..cb49818 100755 --- a/lacme +++ b/lacme @@ -561,7 +561,7 @@ if ($COMMAND eq 'new-reg' or $COMMAND =~ /^reg=/) { 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/" ]; + : [ "$NAME-certs.conf", "$NAME-certs.conf.d/" ]; my $conf; foreach my $conffile (@$conffiles) { $conffile = ($CONFFILENAME =~ s#[^/]+\z##r).$conffile unless $conffile =~ /\A\//; diff --git a/lacme.md b/lacme.md index 69e3ce2..f5b5559 100644 --- a/lacme.md +++ b/lacme.md @@ -162,7 +162,7 @@ Default section 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/`. + Default: `lacme-certs.conf lacme-certs.conf.d/`. `[client]` section ------------------ -- cgit v1.2.3