diff options
| author | Guilhem Moulin <guilhem@fripost.org> | 2021-02-18 21:07:01 +0100 | 
|---|---|---|
| committer | Guilhem Moulin <guilhem@fripost.org> | 2021-02-20 22:13:41 +0100 | 
| commit | 0ef94d85e58497dcb2c4c954cadcac918032467a (patch) | |
| tree | 9ff32832dc06f0c8b17ae19c9e9fbcd46e48d2ba | |
| parent | 4a502836164821b9faa56d363c8fb116ce032321 (diff) | |
Add %-specifiers support.
lacme(8): for --config=, --socket=, --config-certs= (and ‘socket’/
‘config-certs’/‘challenge-directory’ configuration options *before*
privilege drop; and for the [accountd] section ‘command’/‘config’
configuration options *after* privilege drop).
lacme-accountd(1): for --config=, --socket= and --privkey= (and
‘socket’/‘privkey’ configuration options).
This also changes the default configuration file location.  lacme(8) and
lacme-accountd(1) now respectively use /etc/lacme/lacme.conf resp.
/etc/lacme/lacme-accountd.conf when running as root, and
$XDG_CONFIG_HOME/lacme/lacme.conf resp. $XDG_CONFIG_HOME/lacme/lacme-accountd.conf
when running as a normal user.  There is no fallback to /etc anymore.
| -rw-r--r-- | Changelog | 23 | ||||
| -rw-r--r-- | INSTALL | 1 | ||||
| -rw-r--r-- | Makefile | 1 | ||||
| -rw-r--r-- | config/lacme-accountd.conf | 4 | ||||
| -rw-r--r-- | config/lacme.conf | 4 | ||||
| -rwxr-xr-x | lacme | 39 | ||||
| -rwxr-xr-x | lacme-accountd | 35 | ||||
| -rw-r--r-- | lacme-accountd.1.md | 67 | ||||
| -rw-r--r-- | lacme.8.md | 90 | ||||
| -rw-r--r-- | tests/accountd | 13 | ||||
| -rw-r--r-- | tests/spec-expansion | 130 | 
11 files changed, 341 insertions, 66 deletions
@@ -19,9 +19,16 @@ lacme (0.7.1) upstream;     validate provided X.509 chains using that self-contained bundle,     regardless of which CAs is marqued as trusted under /etc/ssl/certs.     This change bumps the minimum OpenSSL version to 1.1.0. - * Breaking change: lacme(8) resp. lacme-accountd(1) no longer consider -   ./lacme.conf resp. ./lacme-accountd.conf as default location for the -   configuration file. + * Breaking change: lacme(8) and lacme-accountd(1) respectively load +   their configuration file from /etc/lacme/lacme.conf resp. +   /etc/lacme/lacme-accountd.conf when running as root, and +   $XDG_CONFIG_HOME/lacme/lacme.conf resp. +   $XDG_CONFIG_HOME/lacme/lacme-accountd.conf when running as a normal +   user.  There is no fallback to /etc anymore, and the lookup in the +   current directory as prefered choice is removed too.  However +   lacme-accountd(1) can be used without configuration file under +   ~/.config/lacme as it treats a non-existent default location as an +   empty file.   * The client, webserver, and accountd commands are now split on     whitespace.  This doesn't change the default behavior but allows     using `ssh -T lacme@account.example.net lacme-accountd` to spawn a @@ -30,11 +37,17 @@ lacme (0.7.1) upstream;     https://letsencrypt.org/docs/staging-environment/ .   * lacme(8)'s 'config' option in the [accountd] section no longer have a     default value.  The previous default /etc/lacme/lacme-accountd.conf -   is still honored when there is the user running lacme doesn't have a -   ~/.config/lacme/lacme-account.conf configuration file. +   is still honored when root privileges are preserved (the default).   * Deprecate setting 'privkey' in [accountd] section of the lacme(8)     configuration file.  One need to use the lacme-accountd(1)     configuration file for that instead. + * lacme(8): add %-specifiers support for --config=, --socket=, +   --config-certs= (and 'socket'/'config-certs'/'challenge-directory' +   configuration options *before* privilege drop; and for the [accountd] +   section 'command'/'config' configuration options *after* privilege +   drop). + * lacme-accountd(1): add %-specifiers support for --config=, --socket= +   and --privkey= (and 'socket'/'privkey' configuration options).   + Improve nginx/apache2 snippets for direct serving of challenge files     (with the new 'challenge-directory' logic symlinks can be disabled).   + Split Nginx and Apapche2 static configuration snippets into seperate @@ -7,7 +7,6 @@ lacme-accountd depends on the following Perl modules:    - File::Basename (core module)    - Getopt::Long (core module)    - JSON (optionally C/XS-accelerated with JSON::XS) -  - List::Util (core module)    - MIME::Base64 (core module)    - Socket (core module) @@ -56,6 +56,7 @@ $(BUILDDIR)/%: %  	        s#@@sbindir@@#$(sbindir)#g; \  	        s#@@libexecdir@@#$(libexecdir)#g; \  	        s#@@datadir@@#$(datadir)#g; \ +	        s#@@localstatedir@@#$(localstatedir)#g; \  	        s#@@runstatedir@@#$(runstatedir)#g; \  	        s#@@sysconfdir@@#$(sysconfdir)#g; \  	        s#@@lacme_www_user@@#$(lacme_www_user)#g; \ diff --git a/config/lacme-accountd.conf b/config/lacme-accountd.conf index 10f332e..f31cf67 100644 --- a/config/lacme-accountd.conf +++ b/config/lacme-accountd.conf @@ -17,10 +17,8 @@  # for signature requests from the ACME client.  An error is raised if  # the path exists or if its parent directory is writable by other  # users. -# Default: "$XDG_RUNTIME_DIR/S.lacme" if the XDG_RUNTIME_DIR -# environment variable is set.  # -#socket = /run/user/1000/S.lacme +#socket = %t/S.lacme  # Be quiet.  Possible values: "Yes"/"No".  # diff --git a/config/lacme.conf b/config/lacme.conf index 98ecacb..198729d 100644 --- a/config/lacme.conf +++ b/config/lacme.conf @@ -10,13 +10,11 @@  # UNIX-domain socket to connect to for signature requests from the ACME  # client.  lacme(8) aborts if the socket is readable or writable by  # other users, or if its parent directory is writable by other users. -# Default: "$XDG_RUNTIME_DIR/S.lacme" if the XDG_RUNTIME_DIR environment -# variable is set.  # This setting is ignored when lacme-accountd(1) is spawned by lacme(8),  # since the two processes communicate through a socket pair.  See the  # "accountd" section below for details.  # -#socket = +#socket = %t/S.lacme  # username to drop privileges to (setting both effective and real uid).  # Skip privilege drop if the value is empty (not recommended). @@ -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\//; diff --git a/lacme-accountd b/lacme-accountd index b9a6e33..e170637 100755 --- a/lacme-accountd +++ b/lacme-accountd @@ -30,7 +30,6 @@ my $NAME = 'lacme-accountd';  use Errno 'EINTR';  use File::Basename 'dirname';  use Getopt::Long qw/:config posix_default no_ignore_case gnu_getopt auto_version/; -use List::Util 'first';  use MIME::Base64 'encode_base64url';  use Socket qw/PF_UNIX SOCK_STREAM SHUT_RDWR/; @@ -64,11 +63,32 @@ 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}; +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; +} +  do { -    my $conffile = $OPTS{config} // first { -f $_ } -        ( ($ENV{XDG_CONFIG_HOME} // "$ENV{HOME}/.config") . "/lacme/$NAME.conf" -        , "@@sysconfdir@@/lacme/$NAME.conf" -        ); +    my $conffile = spec_expand($OPTS{config} // "%E/lacme/$NAME.conf");      if (defined $OPTS{config} or -e $conffile) {          print STDERR "Using configuration file: $conffile\n" if $OPTS{debug}; @@ -94,7 +114,7 @@ do {  #  my ($JWK, $SIGN);  if ($OPTS{privkey} =~ /\A(file|gpg):(\p{Print}+)\z/) { -    my ($method, $filename) = ($1,$2); +    my ($method, $filename) = ($1, spec_expand($2));      my ($fh, @command);      if ($method eq 'file') {          # generate with `openssl genpkey -algorithm RSA` @@ -142,8 +162,7 @@ my $JWK_STR = JSON::->new->encode($JWK);  # delete the file manually.  #  unless (defined $OPTS{stdio}) { -    my $sockname = $OPTS{socket} // (defined $ENV{XDG_RUNTIME_DIR} ? "$ENV{XDG_RUNTIME_DIR}/S.lacme" : undef); -    die "Missing socket option\n" unless defined $sockname; +    my $sockname = spec_expand($OPTS{socket} // '%t/S.lacme');      $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 diff --git a/lacme-accountd.1.md b/lacme-accountd.1.md index cd6352c..4c494f2 100644 --- a/lacme-accountd.1.md +++ b/lacme-accountd.1.md @@ -41,9 +41,12 @@ Options  `--config=`*filename* -:   Use *filename* as configuration file.  `lacme-accountd` fails when -    `--config=` is used with a non-existent file, but a non-existent -    default location is treated as if it were an empty file. +:   Use *filename* as configuration file instead of +    `%E/lacme/lacme-accountd.conf`.  The value is subject to +    [%-specifier expansion](#percent-specifiers).  `lacme-accountd` +    fails when `--config=` is used with a non-existent file, but a +    non-existent default location is treated as if it were an empty +    file.      See the **[configuration file](#configuration-file)** section below      for the configuration options. @@ -57,6 +60,8 @@ Options        symmetrically encrypted)      * `gpg:`*FILE*, for a [`gpg`(1)]-encrypted private key +    *FILE* is subject to [%-specifier expansion](#percent-specifiers). +      The [`genpkey`(1ssl)] command can be used to generate a new private      (account) key: @@ -67,9 +72,14 @@ Options  `--socket=`*path* -:   Use *path* as the UNIX-domain socket to bind against for signature -    requests from the [ACME] client.  `lacme-accountd` aborts if *path* -    exists or if its parent directory is writable by other users. +:   Use *path* as the UNIX-domain socket to bind to for signature +    requests from the [ACME] client.  The value is subject to +    [%-specifier expansion](#percent-specifiers).  `lacme-accountd` +    aborts if *path* exists or if its parent directory is writable by +    other users. +    Default: `%t/S.lacme` (omitting `--socket=` therefore yields an +    error when `lacme-accountd` doesn't run as and the `XDG_RUNTIME_DIR` +    environment variable is unset or empty).  `-h`, `--help` @@ -86,12 +96,6 @@ Options  Configuration file  ================== -If `--config=` is not given, `lacme-accountd` uses the first existing -configuration file among *$XDG_CONFIG_HOME/lacme/lacme-accountd.conf* -(or *~/.config/lacme/lacme-accountd.conf* if the `XDG_CONFIG_HOME` -environment variable is not set), and -*@@sysconfdir@@/lacme/lacme-accountd.conf*. -  When given on the command line, the `--privkey=`, `--socket=` and  `--quiet` options take precedence over their counterpart (without  leading `--`) in the configuration file.  Valid settings are: @@ -110,13 +114,48 @@ leading `--`) in the configuration file.  Valid settings are:  *socket*  :   See `--socket=`. -    Default: *$XDG_RUNTIME_DIR/S.lacme* if the `XDG_RUNTIME_DIR` -    environment variable is set.  *quiet*  :   Be quiet. Possible values: `Yes`/`No`. +%-specifiers  {#percent-specifiers} +============ + +The value the `--config=`, `--privkey=` and `--socket=` CLI options (and +*privkey* and *socket* configuration options) are subject to %-expansion +for the following specifiers. + +----  ------------------------------------------------------------------ +`%C`  `@@localstatedir@@/cache` for the root user, and `$XDG_CACHE_HOME` +      for other users (or `$HOME/.cache` if the `XDG_CACHE_HOME` +      environment variable is unset or empty). + +`%E`  `@@sysconfdir@@` for the root user, and `$XDG_CONFIG_HOME` for +      other users (or `$HOME/.config` if the `XDG_CONFIG_HOME` +      environment variable is unset or empty). + +`%g`  Current group name. + +`%G`  Current group ID. + +`%h`  Home directory of the current user. + +`%t`  `@@runstatedir@@` for the root user, and `$XDG_RUNTIME_DIR` for +      other users.  Non-root users may only use `%t` when the +      `XDG_RUNTIME_DIR` environment variable is set to a non-empty +      value. + +`%T`  `$TMPDIR`, or `/tmp` if the `TMPDIR` environment variable is unset +      or empty. + +`%u`  Current user name. + +`%U`  Current user ID. + +`%%`  A literal `%`. +----  ------------------------------------------------------------------ +  Examples  ======== @@ -100,16 +100,22 @@ Generic settings  `--config=`*filename* -:    Use *filename* as configuration file.  See the **[configuration -     file](#configuration-file)** section below for the configuration -     options. +:   Use *filename* as configuration file instead of +    `%E/lacme/lacme.conf`.  The value is subject to [%-specifier +    expansion](#percent-specifiers). + +    See the **[configuration file](#configuration-file)** section below +    for the configuration options.  `--socket=`*path*  :   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. +    connect to for signature requests from the [ACME] client.  The value +    is subject to [%-specifier expansion](#percent-specifiers). +    `lacme` aborts if *path* exists or if its parent directory is +    writable by other users. +    Default: `%t/S.lacme`. +      This command-line option overrides the *socket* setting of the      [`[client]` section](#client-section) of the configuration file; it      also causes the [`[accountd]` section](#accountd-section) to be @@ -130,10 +136,6 @@ Generic settings  Configuration file  ================== -If `--config=` is not given, `lacme` uses the first existing -configuration file among *$XDG_CONFIG_HOME/lacme/lacme.conf* (or -*~/.config/lacme/lacme.conf* if the `XDG_CONFIG_HOME` environment -variable is not set), and *@@sysconfdir@@/lacme/lacme.conf*.  Valid settings are:  Default section @@ -145,13 +147,15 @@ Default section      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). +    configuration options).  Each item in that list is independently +    subject to [%-specifier expansion](#percent-specifiers). -    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`. +    Paths not starting with `/` (after %-expansion) are relative to the +    parent directory of the **[configuration filename](#configuration-file)**. +    The list of files and directories is processed in the specified +    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.conf.d/`. @@ -164,8 +168,6 @@ of [ACME] commands and dialogues with the remote [ACME] server).  *socket*  :   See `--socket=`. -    Default: *$XDG_RUNTIME_DIR/S.lacme* if the `XDG_RUNTIME_DIR` -    environment variable is set.  *user* @@ -247,7 +249,9 @@ served during certificate issuance.      lacme client user (by default `@@lacme_client_user@@`) needs to be      able to create files under it. -    This setting is required when *listen* is empty. +    This setting is required when *listen* is empty.  Moreover its value +    is subject to [%-specifier expansion](#percent-specifiers) _before_ +    privilege drop.  *user* @@ -308,13 +312,18 @@ UNIX-domain socket.      the first item being the command to execute, the second its first      argument etc.  (Note that `lacme` appends more arguments when      executing the command internally.) +    Each item in that list is independently subject to [%-specifier +    expansion](#percent-specifiers) _after_ privilege drop. +    Default: `@@bindir@@/lacme-accountd`. +      Use for instance `ssh -T lacme@account.example.net lacme-accountd` -    in order to spawn a remote [`lacme-accountd`(1)] server.  Default: -    `@@bindir@@/lacme-accountd`. +    in order to spawn a remote [`lacme-accountd`(1)] server.  *config* -:   Path to the [`lacme-accountd`(1)] configuration file. +:   Path to the [`lacme-accountd`(1)] configuration file.  The value is +    subject to [%-specifier expansion](#percent-specifiers) _after_ +    privilege drop.  *quiet* @@ -428,6 +437,43 @@ Valid settings are:      after successful installation of the *certificate* and/or      *certificate-chain*. +%-specifiers  {#percent-specifiers} +============ + +Some CLI options and configuration settings are subject to %-expansion +for the following specifiers.  Check the documentation of each setting +to see which ones are affected. + +----  ------------------------------------------------------------------ +`%C`  `@@localstatedir@@/cache` for the root user, and `$XDG_CACHE_HOME` +      for other users (or `$HOME/.cache` if the `XDG_CACHE_HOME` +      environment variable is unset or empty). + +`%E`  `@@sysconfdir@@` for the root user, and `$XDG_CONFIG_HOME` for +      other users (or `$HOME/.config` if the `XDG_CONFIG_HOME` +      environment variable is unset or empty). + +`%g`  Current group name. + +`%G`  Current group ID. + +`%h`  Home directory of the current user. + +`%t`  `@@runstatedir@@` for the root user, and `$XDG_RUNTIME_DIR` for +      other users.  Non-root users may only use `%t` when the +      `XDG_RUNTIME_DIR` environment variable is set to a non-empty +      value. + +`%T`  `$TMPDIR`, or `/tmp` if the `TMPDIR` environment variable is unset +      or empty. + +`%u`  Current user name. + +`%U`  Current user ID. + +`%%`  A literal `%`. +----  ------------------------------------------------------------------ +  Examples  ======== diff --git a/tests/accountd b/tests/accountd index 2f3985f..4626c78 100644 --- a/tests/accountd +++ b/tests/accountd @@ -20,12 +20,17 @@ grepstderr -Fxq "Can't stat $SOCKET: No such file or directory (Is lacme-account  ####################################################################### +# missing configuration at default location +! runuser -u lacme-account -- lacme-accountd --debug 2>"$STDERR" || fail +grepstderr -Fxq "Ignoring missing configuration file at default location /home/lacme-account/.config/lacme/lacme-accountd.conf" +grepstderr -Fxq "Error: 'privkey' is not specified" +  install -olacme-account -glacme-account -Ddm0700 ~lacme-account/.config/lacme  mv -t ~lacme-account/.config/lacme /etc/lacme/account.key  chown lacme-account: ~lacme-account/.config/lacme/account.key  cat >~lacme-account/.config/lacme/lacme-accountd.conf <<-EOF -	privkey = file:/home/lacme-account/.config/lacme/account.key +	privkey = file:%E/lacme/account.key  EOF  # non-existent parent directory @@ -33,9 +38,13 @@ EOF  grepstderr -Fxq "stat(/nonexistent): No such file or directory"  # word-writable parent directory -! runuser -u lacme-account -- lacme-accountd --socket="/tmp/S.lacme" account 2>"$STDERR" || fail +! runuser -u lacme-account -- lacme-accountd --socket="%T/S.lacme" account 2>"$STDERR" || fail  grepstderr -Fxq "Error: insecure permissions on /tmp" +# unset XDG_RUNTIME_DIR +! runuser -u lacme-account -- lacme-accountd 2>"$STDERR" || fail +grepstderr "Error: undefined expansion %t in \"%t/S.lacme\"" +  # non-existent $XDG_RUNTIME_DIR  ! runuser -u lacme-account -- env XDG_RUNTIME_DIR="/nonexistent" lacme-accountd 2>"$STDERR" || fail  grepstderr -Fxq "stat(/nonexistent): No such file or directory" diff --git a/tests/spec-expansion b/tests/spec-expansion new file mode 100644 index 0000000..722bdfc --- /dev/null +++ b/tests/spec-expansion @@ -0,0 +1,130 @@ +# %-specifiers expansion + +# lacme --config=, all specifiers, root privileges +! lacme --config="%C %E %t %h %T %g %G %u %U %%.conf" account 2>"$STDERR" || fail +grepstderr -Fxq "Can't open /var/cache /etc /run /root /tmp root 0 root 0 %.conf: No such file or directory" + +# lacme --config=, all specifiers, root privileges, defined XDG_* +! env XDG_CACHE_HOME=/foo/cache XDG_CONFIG_HOME=/foo/config XDG_RUNTIME_DIR=/foo/run HOME=/foo/home USER=myuser TMPDIR=/foo/tmp \ +    lacme --config="%C %E %t %h %T %g %G %u %U %%.conf" account 2>"$STDERR" || fail +grepstderr -Fxq "Can't open /var/cache /etc /run /root /foo/tmp root 0 root 0 %.conf: No such file or directory" + +# lacme --config=, all specifiers, non-root, unset XDG_RUNTIME_DIR +! runuser -u nobody -- lacme --config="%C %E %t %h %T %g %G %u %U %%.conf" account 2>"$STDERR" || fail +grepstderr -Fxq "Error: undefined expansion %t in \"%C %E %t %h %T %g %G %u %U %%.conf\"" + +# lacme --config=, all specifiers, non-root, defined XDG_RUNTIME_DIR, no other XDG_* +! runuser -u nobody -g www-data -- env XDG_RUNTIME_DIR=/foo/run \ +    lacme --config="%C %E %t %h %T %g %G %u %U %%.conf" account 2>"$STDERR" || fail +grepstderr -Fxq "Can't open /nonexistent/.cache /nonexistent/.config /foo/run /nonexistent /tmp www-data 33 nobody 65534 %.conf: No such file or directory" + +# lacme --config=, all specifiers, non-root, defined XDG_* +! runuser -u nobody -- env XDG_CACHE_HOME=/foo/cache XDG_CONFIG_HOME=/foo/config XDG_RUNTIME_DIR=/foo/run HOME=/foo/home USER=myuser TMPDIR=/foo/tmp \ +    lacme --config="%C %E %t %h %T %g %G %u %U %%.conf" account 2>"$STDERR" || fail +grepstderr -Fxq "Can't open /foo/cache /foo/config /foo/run /nonexistent /foo/tmp nogroup 65534 nobody 65534 %.conf: No such file or directory" + +# lacme --socket= +! lacme --config="%E/lacme/lacme.conf" --socket="%t/S.lacme2" account --debug 2>"$STDERR" || fail +grepstderr -Fxq "Using configuration file: /etc/lacme/lacme.conf" +grepstderr -Fxq "Can't stat /run/S.lacme2: No such file or directory (Is lacme-accountd running?)" + +# 'challenge-directory' setting (expands before privilege drop) +sed -ri 's|^#?challenge-directory\s*=.*|challenge-directory = /nonexistent/%u:%g|' /etc/lacme/lacme.conf +! lacme newOrder --debug 2>"$STDERR" || fail +grepstderr -Fq "Using existing webserver on /nonexistent/root:root" + +# lacme --config-certs= and 'config-certs' settings (expands before privilege drop) +! lacme newOrder --debug nonexistent 2>"$STDERR" || fail +grepstderr -Fxq "Reading /etc/lacme/lacme-certs.conf" + +sed -ri 's|^#?config-certs\s*=.*|config-certs = /nonexistent/%u:%g.conf|' /etc/lacme/lacme.conf +! lacme newOrder --debug nonexistent 2>"$STDERR" || fail +grepstderr -Fxq "Reading /nonexistent/root:root.conf" + +! lacme newOrder --config-certs="%E/lacme/certs.conf.d" --debug nonexistent 2>"$STDERR" || fail +grepstderr -vFxq "Reading /etc/lacme/lacme-certs.conf" +grepstderr -Fxq "Reading /etc/lacme/certs.conf.d" + +# 'config' setting in [accountd] section (expands after privilege drop) +sed -ri 's|^#?config\s*=\s*$|config = /nonexistent/%u:%g.conf|' /etc/lacme/lacme.conf +! lacme account 2>"$STDERR" || fail +grepstderr -Fxq "Failed to open file '/nonexistent/root:root.conf' for reading: No such file or directory" + +sed -ri 's|^#?user\s*=\s*$|user = nobody|' /etc/lacme/lacme.conf +! lacme account 2>"$STDERR" || fail +grepstderr -Fxq "Failed to open file '/nonexistent/nobody:root.conf' for reading: No such file or directory" + +# 'command' setting in [accountd] section (expands after privilege drop) +sed -ri 's|^#?command\s*=.*/lacme-accountd$|command = /usr/bin/lacme-accountd --%u|' /etc/lacme/lacme.conf +! lacme account 2>"$STDERR" || fail +grepstderr -Fxq "Unknown option: nobody" + +sed -ri 's|^#?command\s*=.*/lacme-accountd .*|command = /nonexistent/%u/%g %u %g|' /etc/lacme/lacme.conf +! lacme account 2>"$STDERR" || fail +grepstderr -Eq "^Can't exec \"/nonexistent/nobody/root\": No such file or directory" + + +####################################################################### + +# lacme-accountd --config=, all specifiers, root privileges +! lacme-accountd --config="%C %E %t %h %T %g %G %u %U %%.conf" 2>"$STDERR" || fail +grepstderr -Fxq "Failed to open file '/var/cache /etc /run /root /tmp root 0 root 0 %.conf' for reading: No such file or directory" + +# lacme-accountd --config=, all specifiers, root privileges, defined XDG_* +! env XDG_CACHE_HOME=/foo/cache XDG_CONFIG_HOME=/foo/config XDG_RUNTIME_DIR=/foo/run HOME=/foo/home USER=myuser TMPDIR=/foo/tmp \ +    lacme-accountd --config="%C %E %t %h %T %g %G %u %U %%.conf" 2>"$STDERR" || fail +grepstderr -Fxq "Failed to open file '/var/cache /etc /run /root /foo/tmp root 0 root 0 %.conf' for reading: No such file or directory" + +# lacme-accountd --config=, all specifiers, non-root, unset XDG_RUNTIME_DIR +! runuser -u nobody -- lacme-accountd --config="%C %E %t %h %T %g %G %u %U %%.conf" account 2>"$STDERR" || fail +grepstderr -Fxq "Error: undefined expansion %t in \"%C %E %t %h %T %g %G %u %U %%.conf\"" + +# lacme-accountd --config=, all specifiers, non-root, defined XDG_RUNTIME_DIR, no other XDG_* +! runuser -u nobody -g www-data -- env XDG_RUNTIME_DIR=/foo/run \ +    lacme-accountd --config="%C %E %t %h %T %g %G %u %U %%.conf" 2>"$STDERR" || fail +grepstderr -Fxq "Failed to open file '/nonexistent/.cache /nonexistent/.config /foo/run /nonexistent /tmp www-data 33 nobody 65534 %.conf' for reading: No such file or directory" + +# lacme-accountd --config=, all specifiers, non-root, defined XDG_* +! runuser -u nobody -- env XDG_CACHE_HOME=/foo/cache XDG_CONFIG_HOME=/foo/config XDG_RUNTIME_DIR=/foo/run HOME=/foo/home USER=myuser TMPDIR=/foo/tmp \ +    lacme-accountd --config="%C %E %t %h %T %g %G %u %U %%.conf" 2>"$STDERR" || fail +grepstderr -Fxq "Failed to open file '/foo/cache /foo/config /foo/run /nonexistent /foo/tmp nogroup 65534 nobody 65534 %.conf' for reading: No such file or directory" + +# lacme-accountd --privkey= +! lacme-accountd --privkey="file:%h/lacme-accountd.key" --debug 2>"$STDERR" || fail +grepstderr -Fxq "Error: Can't open /root/lacme-accountd.key: No such file or directory" + +# lacme-accountd, default socket location +lacme-accountd --debug 2>"$STDERR" & PID=$! +sleep 1 +kill $PID || fail +wait || fail +grepstderr -Fxq "Using configuration file: /etc/lacme/lacme-accountd.conf" +grepstderr -Fxq "Starting lacme Account Key Manager at /run/S.lacme" +grepstderr -Fxq "Unlinking /run/S.lacme" + +# lacme-accountd --config= --socket= --privkey= +ln -s lacme-accountd.conf /etc/lacme/accountd.conf +lacme-accountd --config="%E/lacme/accountd.conf" --socket="%t/S.lacme2" --privkey="file:%E/lacme/account.key" --debug 2>"$STDERR" & PID=$! +sleep 1 +kill $PID || fail +wait || fail +grepstderr -Fxq "Using configuration file: /etc/lacme/accountd.conf" +grepstderr -Fxq "Starting lacme Account Key Manager at /run/S.lacme2" +grepstderr -Fxq "Unlinking /run/S.lacme2" + +# lacme-accountd, custom 'socket' setting +sed -ri 's|^#?socket\s*=.*|socket = %t/S.lacme3|' /etc/lacme/lacme-accountd.conf +lacme-accountd --debug 2>"$STDERR" & PID=$! +sleep 1 +kill $PID || fail +wait || fail +grepstderr -Fxq "Using configuration file: /etc/lacme/lacme-accountd.conf" +grepstderr -Fxq "Starting lacme Account Key Manager at /run/S.lacme3" +grepstderr -Fxq "Unlinking /run/S.lacme3" + +# lacme-accountd, custom 'privkey' setting +sed -ri 's|^privkey\s*=.*|privkey = file:%h/lacme-accountd.key|' /etc/lacme/lacme-accountd.conf +! lacme-accountd --debug 2>"$STDERR" || fail +grepstderr -Fxq "Error: Can't open /root/lacme-accountd.key: No such file or directory" + +# vim: set filetype=sh :  | 
