From 6f375631548a3562635af555bd453e4de40bf135 Mon Sep 17 00:00:00 2001 From: Guilhem Moulin Date: Mon, 22 Feb 2021 14:33:34 +0100 Subject: accountd::conn(): Minor refactoring. --- lacme-accountd | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) (limited to 'lacme-accountd') diff --git a/lacme-accountd b/lacme-accountd index 0f5deb2..5794ec1 100755 --- a/lacme-accountd +++ b/lacme-accountd @@ -239,19 +239,22 @@ sub conn($$$) { $data =~ s/\r\n\z// or panic(); my ($header, $payload) = split(/\./, $data, 2); - unless (defined $header and $header =~ /\A[A-Za-z0-9\-_]+\z/) { + if (defined $header and $header =~ /\A[A-Za-z0-9\-_]+\z/) { + $header = decode_base64url($header); + } else { info("[$id] >>> Error: Refusing to sign request: Malformed protected header"); last; } - unless (defined $payload and $payload =~ /\A[A-Za-z0-9\-_]*\z/) { - # POST-as-GET yields an empty payload + if (defined $payload and $payload =~ /\A[A-Za-z0-9\-_]*\z/) { + # empty payloads are valid, cf. POST-as-GET + $payload = decode_base64url($payload); + } else { info("[$id] >>> Error: Refusing to sign request: Malformed payload"); last; } - logmsg(noquiet => "[$id] >>> OK signing request: ", - "header=base64url(", decode_base64url($header), "); ", - "playload=base64url(", decode_base64url($payload), ")"); + my $req = "header=base64url($header); playload=base64url($payload)"; + logmsg(noquiet => "[$id] >>> OK signing request: ", $req); my $sig = $SIGN->($data); $out->printflush( encode_base64url($sig), "\r\n" ) or warn "print: $!"; -- cgit v1.2.3 From 87fa9468a26c1902423839473049cd3325098c1a Mon Sep 17 00:00:00 2001 From: Guilhem Moulin Date: Mon, 22 Feb 2021 14:49:00 +0100 Subject: lacme-account: Improve log messages. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Again… --- Changelog | 1 + lacme-accountd | 23 ++++++++++++----------- tests/accountd | 6 +++--- tests/accountd-kid | 8 ++++---- tests/accountd-remote | 2 +- 5 files changed, 21 insertions(+), 19 deletions(-) (limited to 'lacme-accountd') diff --git a/Changelog b/Changelog index 3765bf9..faf32a8 100644 --- a/Changelog +++ b/Changelog @@ -1,5 +1,6 @@ lacme (0.8.1) upstream; + + lacme-accountd: improve log messages. - lacme: in the [accountd] config, let lacme-accountd(1) do the %-expansion for 'config', not lacme(8) when building the command. diff --git a/lacme-accountd b/lacme-accountd index 5794ec1..68d0f39 100755 --- a/lacme-accountd +++ b/lacme-accountd @@ -83,7 +83,8 @@ sub error(@) { } sub panic(@) { my @loc = caller; - my @msg = (@_, " at line $loc[2] in $loc[1]"); + my @msg = ("PANIC at line $loc[2] in $loc[1]"); + push @msg, ": ", @_ if @_; info(@msg); exit 255; } @@ -234,29 +235,29 @@ sub conn($$$) { $out->printflush( "$PROTOCOL_VERSION OK ", $EXTRA_GREETING_STR, "\r\n", $JWK_STR, "\r\n" ) or warn "print: $!"; - # sign whatever comes in while (defined (my $data = $in->getline())) { $data =~ s/\r\n\z// or panic(); + # validate JWS Signing Input from RFC 7515: + # ASCII(BASE64URL(UTF8(JWS Protected Header)) || '.' || BASE64URL(JWS Payload)) my ($header, $payload) = split(/\./, $data, 2); if (defined $header and $header =~ /\A[A-Za-z0-9\-_]+\z/) { $header = decode_base64url($header); } else { - info("[$id] >>> Error: Refusing to sign request: Malformed protected header"); + info("[$id] NOSIGN [malformed JWS Protected Header]"); last; } if (defined $payload and $payload =~ /\A[A-Za-z0-9\-_]*\z/) { - # empty payloads are valid, cf. POST-as-GET + # empty payloads are valid, and used for POST-as-GET (RFC 8555 sec. 6.3) $payload = decode_base64url($payload); } else { - info("[$id] >>> Error: Refusing to sign request: Malformed payload"); + info("[$id] NOSIGN [malformed JWS Payload]"); last; } - my $req = "header=base64url($header); playload=base64url($payload)"; - logmsg(noquiet => "[$id] >>> OK signing request: ", $req); - - my $sig = $SIGN->($data); + my $req = "header=base64url($header) playload=base64url($payload)"; + my $sig = $SIGN->($data) // panic(); + logmsg(noquiet => "[$id] SIGNED ", $req); $out->printflush( encode_base64url($sig), "\r\n" ) or warn "print: $!"; } } @@ -270,9 +271,9 @@ if (defined $OPTS{stdio}) { next if $! == EINTR; # try again if accept(2) was interrupted by a signal panic("accept: $!"); }; - logmsg(noquiet => "[$count] >>> Accepted new connection"); + logmsg(noquiet => "[$count] Accepted new connection"); conn($conn, $conn, $count); - logmsg(noquiet => "[$count] >>> Connection terminated"); + logmsg(noquiet => "[$count] Connection terminated"); $conn->close() or warn "close: $!"; } } diff --git a/tests/accountd b/tests/accountd index a603c16..7e8fd4c 100644 --- a/tests/accountd +++ b/tests/accountd @@ -79,9 +79,9 @@ wait # ensure signature requests are logged grep -Fq "Starting lacme Account Key Manager at /home/lacme-account/S.lacme" ~lacme-account/.local/share/lacme/accountd.log -grep -Fq "[0] >>> Accepted new connection" ~lacme-account/.local/share/lacme/accountd.log -grep -Fq "[1] >>> Accepted new connection" ~lacme-account/.local/share/lacme/accountd.log +grep -Fq "[0] Accepted new connection" ~lacme-account/.local/share/lacme/accountd.log +grep -Fq "[1] Accepted new connection" ~lacme-account/.local/share/lacme/accountd.log grep -Fq "Shutting down and closing lacme Account Key Manager" ~lacme-account/.local/share/lacme/accountd.log -grep -F ">>> OK signing request:" ~lacme-account/.local/share/lacme/accountd.log +grep -F "] SIGNED header=base64url({" ~lacme-account/.local/share/lacme/accountd.log # vim: set filetype=sh : diff --git a/tests/accountd-kid b/tests/accountd-kid index e1bd63d..f55facf 100644 --- a/tests/accountd-kid +++ b/tests/accountd-kid @@ -28,8 +28,8 @@ runuser -u lacme-account -- lacme-accountd --socket="$SOCKET" --quiet & PID=$! ! lacme --socket="$SOCKET" account 2>"$STDERR" || fail grepstderr -Fxq "WARNING: lacme-accountd supplied an empty JWK; try removing 'keyid' setting from lacme-accountd.conf if the ACME resource request fails." grepstderr -Fxq "400 Bad Request (Parse error reading JWS)" -! grep -F ">>> OK signing request: header=" ~lacme-account/.local/share/lacme/accountd.log | \ - grep -vF ">>> OK signing request: header=base64url({\"alg\":\"RS256\",\"jwk\":{}," || exit 1 +grep -F "] SIGNED header=base64url({" ~lacme-account/.local/share/lacme/accountd.log >/tmp/signed +! grep -vF "] SIGNED header=base64url({\"alg\":\"RS256\",\"jwk\":{}," >> OK signing request: header=" ~lacme-account/.local/share/lacme/accountd.log | \ - grep -vF ">>> OK signing request: header=base64url({\"alg\":\"RS256\",\"kid\":\"$keyid\"," || exit 1 +grep -F "] SIGNED header=base64url({" ~lacme-account/.local/share/lacme/accountd.log >/tmp/signed +! grep -vF "] SIGNED header=base64url({\"alg\":\"RS256\",\"kid\":\"$keyid\"," >> OK signing request:" ~lacme-account/.local/share/lacme/accountd.log +grep -F "] SIGNED header=base64url({" ~lacme-account/.local/share/lacme/accountd.log # vim: set filetype=sh : -- cgit v1.2.3 From 045d169339c5b973f0924269e6ca485e48de3668 Mon Sep 17 00:00:00 2001 From: Guilhem Moulin Date: Mon, 22 Feb 2021 20:32:33 +0100 Subject: lacme-accountd: Refuse to sign JWS with an invalid Protected Header. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit “The JWS Protected Header is a JSON object” — RFC 7515 sec. 2. “The JWS Protected Header MUST include the following fields: - "alg" - "nonce" - "url" - either "jwk" or "kid"” — RFC 8555 sec. 6.2. --- Changelog | 1 + lacme-accountd | 13 +++++++++++++ tests/accountd-validate | 36 ++++++++++++++++++++++++++++++++++++ 3 files changed, 50 insertions(+) create mode 100644 tests/accountd-validate (limited to 'lacme-accountd') diff --git a/Changelog b/Changelog index faf32a8..da34ddc 100644 --- a/Changelog +++ b/Changelog @@ -1,6 +1,7 @@ lacme (0.8.1) upstream; + lacme-accountd: improve log messages. + + lacme-accountd: refuse to sign JWS with an invalid Protected Header. - lacme: in the [accountd] config, let lacme-accountd(1) do the %-expansion for 'config', not lacme(8) when building the command. diff --git a/lacme-accountd b/lacme-accountd index 68d0f39..5478cc2 100755 --- a/lacme-accountd +++ b/lacme-accountd @@ -256,6 +256,19 @@ sub conn($$$) { } my $req = "header=base64url($header) playload=base64url($payload)"; + + eval { $header = JSON::->new->decode($header); }; + if ($@ or # couldn't decode (parse error) + # RFC 7515: not a JSON object + !defined($header) or ref($header) ne "HASH" or + # RFC 8555 sec. 6.2: the protected Header MUST include all these fields + grep !defined, @$header{qw/alg nonce url/} or + # RFC 8555 sec. 6.2: the protected header MUST include any of these fields + !grep defined, @$header{qw/jwk kid/}) { + info("[$id] NOSIGN [invalid JWS Protected Header] ", $req); + last; + } + my $sig = $SIGN->($data) // panic(); logmsg(noquiet => "[$id] SIGNED ", $req); $out->printflush( encode_base64url($sig), "\r\n" ) or warn "print: $!"; diff --git a/tests/accountd-validate b/tests/accountd-validate new file mode 100644 index 0000000..d4be5ee --- /dev/null +++ b/tests/accountd-validate @@ -0,0 +1,36 @@ +# JWS Signing Input (RFC 7515) validation + +# missing or empty protected header +printf "\\r\\n" | lacme-accountd --stdio 2>"$STDERR" +grepstderr -Fq "] NOSIGN [malformed JWS Protected Header]" +printf ".foo\\r\\n" | lacme-accountd --stdio 2>"$STDERR" +grepstderr -Fq "] NOSIGN [malformed JWS Protected Header]" + +# invalid base64url-encoded protected header +printf "foo/bar.baz\\r\\n" | lacme-accountd --stdio 2>"$STDERR" +grepstderr -Fq "] NOSIGN [malformed JWS Protected Header]" + +# missing payload +printf "foo\\r\\n" | lacme-accountd --stdio 2>"$STDERR" +grepstderr -Fq "] NOSIGN [malformed JWS Payload]" + +# invalid base64url-encoded payload +printf "foo.bar/baz\\r\\n" | lacme-accountd --stdio 2>"$STDERR" +grepstderr -Fq "] NOSIGN [malformed JWS Payload]" + +# invalid JWS Protected Header: not a JSON object; missing fields "alg", +# "nonce", "url", or either "jwk" or "kid" +for s in "null" "\"str\"" "{}" "{\"alg\":\"\",\"nonce\":\"\",\"url\":\"\"}" "{\"jwk\":{}}"; do + s="$(printf "%s" "$s" | base64 -w0 | sed "s/=*$//" | tr "+/" "-_")" + printf "%s.\\r\\n" "$s" | lacme-accountd --stdio 2>"$STDERR" + grepstderr -F "] NOSIGN [invalid JWS Protected Header]" +done + +# valid JWS Protected Header and Payload +h="{\"alg\":\"\",\"nonce\":\"\",\"url\":\"\",\"jwk\":{}}" +s="$(printf "%s" "$h" | base64 -w0 | sed "s/=*$//" | tr "+/" "-_")" +p="$(printf "%s" "JWS Payload" | base64 -w0 | sed "s/=*$//" | tr "+/" "-_")" +printf "%s.%s\\r\\n" "$s" "$p" | lacme-accountd --stdio 2>"$STDERR" +grepstderr -F "] SIGNED header=base64url($h) playload=base64url(JWS Payload)" + +# vim: set filetype=sh : -- cgit v1.2.3 From 0fb2ebb14c538d736d9260fc6fae51d02375a999 Mon Sep 17 00:00:00 2001 From: Guilhem Moulin Date: Mon, 22 Feb 2021 23:20:15 +0100 Subject: lacme-accountd: panic() upon internal error of the signing routine. It might croak and we want to log that error also. --- lacme-accountd | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'lacme-accountd') diff --git a/lacme-accountd b/lacme-accountd index 5478cc2..5109888 100755 --- a/lacme-accountd +++ b/lacme-accountd @@ -269,7 +269,8 @@ sub conn($$$) { last; } - my $sig = $SIGN->($data) // panic(); + my $sig = eval { $SIGN->($data) }; + panic($@) if $@ or !defined $sig; logmsg(noquiet => "[$id] SIGNED ", $req); $out->printflush( encode_base64url($sig), "\r\n" ) or warn "print: $!"; } -- cgit v1.2.3 From 2d08a72c2f6b2afb04fb5382a5f592075a0004a8 Mon Sep 17 00:00:00 2001 From: Guilhem Moulin Date: Tue, 23 Feb 2021 00:28:56 +0100 Subject: lacme-accountd: don't log debug messages unless --debug is set. --- Changelog | 1 + lacme-accountd | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) (limited to 'lacme-accountd') diff --git a/Changelog b/Changelog index da34ddc..c4dd0fc 100644 --- a/Changelog +++ b/Changelog @@ -4,6 +4,7 @@ lacme (0.8.1) upstream; + lacme-accountd: refuse to sign JWS with an invalid Protected Header. - 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. -- Guilhem Moulin Mon, 22 Feb 2021 12:04:28 +0100 diff --git a/lacme-accountd b/lacme-accountd index 5109888..47a4c32 100755 --- a/lacme-accountd +++ b/lacme-accountd @@ -67,7 +67,7 @@ usage(0) if $OPTS{help}; my $LOG; sub logmsg($@) { my $lvl = shift // "all"; - if (defined $LOG) { + if (defined $LOG and ($lvl ne "debug" or $OPTS{debug})) { my $now = localtime; $LOG->printflush("[", $now, "] ", @_, "\n") or warn "print: $!"; } -- cgit v1.2.3 From 3a527c2159cdd23f489970f935edbccc37da1901 Mon Sep 17 00:00:00 2001 From: Guilhem Moulin Date: Tue, 23 Feb 2021 00:58:46 +0100 Subject: lacme-accountd: Refactor logging logic. --- Changelog | 2 +- lacme-accountd | 27 +++++++++++++++------------ 2 files changed, 16 insertions(+), 13 deletions(-) (limited to 'lacme-accountd') diff --git a/Changelog b/Changelog index c4dd0fc..b7459fd 100644 --- a/Changelog +++ b/Changelog @@ -1,6 +1,6 @@ lacme (0.8.1) upstream; - + lacme-accountd: improve log messages. + + lacme-accountd: improve log messages and refactor logging logic. + lacme-accountd: refuse to sign JWS with an invalid Protected Header. - lacme: in the [accountd] config, let lacme-accountd(1) do the %-expansion for 'config', not lacme(8) when building the command. diff --git a/lacme-accountd b/lacme-accountd index 47a4c32..a35ac88 100755 --- a/lacme-accountd +++ b/lacme-accountd @@ -64,18 +64,21 @@ sub usage(;$$) { usage(1) unless GetOptions(\%OPTS, qw/config=s privkey=s socket=s stdio quiet|q debug help|h/); usage(0) if $OPTS{help}; -my $LOG; +my ($LOG, $LOGLEVEL); +my ($LOG_INFO, $LOG_VERBOSE, $LOG_DEBUG) = (0,1,2); sub logmsg($@) { - my $lvl = shift // "all"; - if (defined $LOG and ($lvl ne "debug" or $OPTS{debug})) { + my $lvl = shift; + if (defined $LOG and ($lvl <= $LOGLEVEL or $lvl <= $LOG_VERBOSE)) { + # --quiet flag hides verbose-level messages from the standard + # error but we add them to the logfile nonetheless my $now = localtime; $LOG->printflush("[", $now, "] ", @_, "\n") or warn "print: $!"; } - unless (($lvl eq "debug" and !$OPTS{debug}) or ($lvl eq "noquiet" and $OPTS{quiet})) { + if ($lvl <= $LOGLEVEL) { print STDERR @_, "\n" or warn "print: $!"; } } -sub info(@) { logmsg(all => @_); } +sub info(@) { logmsg($LOG_INFO => @_); } sub error(@) { my @msg = ("Error: ", @_); info(@msg); @@ -134,7 +137,7 @@ do { print STDERR "Ignoring missing configuration file at default location $conffile\n" if $OPTS{debug}; } - $OPTS{quiet} = 0 if $OPTS{debug}; + $LOGLEVEL = $OPTS{debug} ? $LOG_DEBUG : $OPTS{quiet} ? $LOG_INFO : $LOG_VERBOSE; error("'privkey' is not specified") unless defined $OPTS{privkey}; }; @@ -214,7 +217,7 @@ unless (defined $OPTS{stdio}) { my $umask = umask(0177) // panic("umask: $!"); - logmsg(noquiet => "Starting lacme Account Key Manager at $sockname"); + logmsg($LOG_VERBOSE => "Starting lacme Account Key Manager at $sockname"); socket(my $sock, PF_UNIX, SOCK_STREAM, 0) or panic("socket: $!"); my $sockaddr = Socket::sockaddr_un($sockname) // panic(); bind($sock, $sockaddr) or panic("bind: $!"); @@ -271,7 +274,7 @@ sub conn($$$) { my $sig = eval { $SIGN->($data) }; panic($@) if $@ or !defined $sig; - logmsg(noquiet => "[$id] SIGNED ", $req); + logmsg($LOG_VERBOSE => "[$id] SIGNED ", $req); $out->printflush( encode_base64url($sig), "\r\n" ) or warn "print: $!"; } } @@ -285,9 +288,9 @@ if (defined $OPTS{stdio}) { next if $! == EINTR; # try again if accept(2) was interrupted by a signal panic("accept: $!"); }; - logmsg(noquiet => "[$count] Accepted new connection"); + logmsg($LOG_VERBOSE => "[$count] Accepted new connection"); conn($conn, $conn, $count); - logmsg(noquiet => "[$count] Connection terminated"); + logmsg($LOG_VERBOSE => "[$count] Connection terminated"); $conn->close() or warn "close: $!"; } } @@ -297,11 +300,11 @@ if (defined $OPTS{stdio}) { # END { if (defined $SOCKNAME and -S $SOCKNAME) { - logmsg(debug => "Unlinking $SOCKNAME"); + logmsg($LOG_DEBUG => "Unlinking $SOCKNAME"); unlink $SOCKNAME or info("Error: unlink($SOCKNAME): $!"); } if (defined $S) { - logmsg(noquiet => "Shutting down and closing lacme Account Key Manager"); + logmsg($LOG_VERBOSE => "Shutting down and closing lacme Account Key Manager"); shutdown($S, SHUT_RDWR) or info("Error: shutdown: $!"); close $S or info("Error: close: $!"); } -- cgit v1.2.3 From faab30461b0f2b920e3dd19489ce458c0b38e6d9 Mon Sep 17 00:00:00 2001 From: Guilhem Moulin Date: Wed, 24 Feb 2021 21:06:48 +0100 Subject: If restricting access via umask() fails, don't include errno in the error message. errno is not set on umask failure, see https://perldoc.perl.org/functions/umask. --- Changelog | 2 ++ lacme | 4 ++-- lacme-accountd | 4 ++-- 3 files changed, 6 insertions(+), 4 deletions(-) (limited to 'lacme-accountd') diff --git a/Changelog b/Changelog index 1682847..e047ac5 100644 --- a/Changelog +++ b/Changelog @@ -236,6 +236,8 @@ lacme (0.2) upstream; directories. New default "lacme-certs.conf lacme-certs.conf.d/". - Minor manpage fixes - More useful message upon Validation Challenge failure. + - If restricting access via umask() fails, don't include errno in the + error message as it's not set on failure. -- Guilhem Moulin Sat, 03 Dec 2016 16:40:56 +0100 diff --git a/lacme b/lacme index 66dd6f6..fb19646 100755 --- a/lacme +++ b/lacme @@ -376,14 +376,14 @@ sub spawn_webserver() { if ($domain == AF_UNIX) { # bind(2) with a loose umask(2) to allow anyone to connect - my $umask = umask(0111) // die "umask: $!"; + my $umask = umask(0111) // die; my $path = Socket::unpack_sockaddr_un($sockaddr); bind($sock, $sockaddr) or die "Couldn't bind to $p: $!"; push @CLEANUP, sub() { print STDERR "Unlinking $path\n" if $OPTS{debug}; unlink $path or warn "Warning: Couldn't unlink $path: $!"; }; - umask($umask) // die "umask: $!"; + umask($umask) // die; } else { bind($sock, $sockaddr) or die "Couldn't bind to $p: $!"; diff --git a/lacme-accountd b/lacme-accountd index a35ac88..98c11ad 100755 --- a/lacme-accountd +++ b/lacme-accountd @@ -215,7 +215,7 @@ unless (defined $OPTS{stdio}) { my @stat = stat($dirname) or error("stat($dirname): $!"); error("Insecure permissions on $dirname") if ($stat[2] & 0022) != 0; - my $umask = umask(0177) // panic("umask: $!"); + my $umask = umask(0177) // panic(); logmsg($LOG_VERBOSE => "Starting lacme Account Key Manager at $sockname"); socket(my $sock, PF_UNIX, SOCK_STREAM, 0) or panic("socket: $!"); @@ -225,7 +225,7 @@ unless (defined $OPTS{stdio}) { ($SOCKNAME, $S) = ($sockname, $sock); listen($S, 1) or panic("listen: $!"); - umask($umask) // panic("umask: $!"); + umask($umask) // panic(); }; -- cgit v1.2.3 From b3af3526b293f396da02a6276ea86ca17dcd2d03 Mon Sep 17 00:00:00 2001 From: Guilhem Moulin Date: Wed, 25 Jan 2023 03:23:51 +0100 Subject: Prepare new release v0.8.1. --- Changelog | 2 +- client | 2 +- lacme | 2 +- lacme-accountd | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) (limited to 'lacme-accountd') diff --git a/Changelog b/Changelog index 4aa9f4f..fc658bf 100644 --- a/Changelog +++ b/Changelog @@ -28,7 +28,7 @@ lacme (0.8.1) upstream; - Makefile: replace '$(dir $@)' with '$(@D)'. - Test suite: Adjust against current Let's Encrypt staging environment. - -- Guilhem Moulin Mon, 22 Feb 2021 12:04:28 +0100 + -- Guilhem Moulin Wed, 25 Jan 2023 03:23:51 +0100 lacme (0.8.0) upstream; diff --git a/client b/client index 8439ddb..3cda821 100755 --- a/client +++ b/client @@ -43,7 +43,7 @@ use warnings; # instance own by another user and created with umask 0177) is not a # problem since SOCKET_FD can be bound as root prior to the execve(2). -our $VERSION = '0.8.0'; +our $VERSION = '0.8.1'; my $PROTOCOL_VERSION = 1; my $NAME = 'lacme-client'; diff --git a/lacme b/lacme index d7dac54..21a184c 100755 --- a/lacme +++ b/lacme @@ -22,7 +22,7 @@ use v5.14.2; use strict; use warnings; -our $VERSION = '0.8.0'; +our $VERSION = '0.8.1'; my $NAME = 'lacme'; use Errno 'EINTR'; diff --git a/lacme-accountd b/lacme-accountd index 98c11ad..a9f5469 100755 --- a/lacme-accountd +++ b/lacme-accountd @@ -23,7 +23,7 @@ use v5.14.2; use strict; use warnings; -our $VERSION = '0.8.0'; +our $VERSION = '0.8.1'; my $PROTOCOL_VERSION = 1; my $NAME = 'lacme-accountd'; -- cgit v1.2.3