dehydrated-io / dehydrated

letsencrypt/acme client implemented as a shell-script – just add water
https://dehydrated.io
MIT License
5.96k stars 716 forks source link

`dehydrated -c` silently fails to renew certificates using zsh #896

Closed Jehops closed 1 year ago

Jehops commented 1 year ago

Environment:

% uname -a
FreeBSD ser.ftfl.ca 14.0-CURRENT FreeBSD 14.0-CURRENT #1 installed-n259738-195f1b124da4: Sun Dec 18 16:35:20 AST 2022     root@ser.ftfl.ca:/usr/obj/usr/src/amd64.amd64/sys/GENERIC-NODEBUG amd64

Sample output:

% sudo zsh /usr/local/bin/dehydrated -c
# INFO: Using main config file /usr/local/etc/dehydrated/config

Strangely, if I change this snippet

    # Force zsh to expand $A into multiple words
    local is_wordsplit_disabled
    is_wordsplit_disabled="$(unsetopt 2>/dev/null | grep -c '^shwordsplit$')"

to

    # Force zsh to expand $A into multiple words
    local is_wordsplit_disabled="$(unsetopt 2>/dev/null | grep -c '^shwordsplit$')"

then things seem to work and the output looks like this

% sudo /usr/local/bin/dehydrated -c
# INFO: Using main config file /usr/local/etc/dehydrated/config
Processing xxx with alternative names: xxx
 + Checking domain name(s) of existing cert... unchanged.
 + Checking expire date of existing cert...
 + Valid till Mar 30 18:32:18 2023 GMT (Longer than 30 days). Skipping renew!
Processing yyy with alternative names: yyy
 + Checking domain name(s) of existing cert... unchanged.
 + Checking expire date of existing cert...
 + Valid till Mar 30 22:20:34 2023 GMT (Longer than 30 days). Skipping renew!
update_ocsp=no
Jehops commented 1 year ago

The problem doesn't happen on FreeBSD 13.1, so it seems this is likely a FreeBSD/ZSH bug.

hillmich commented 1 year ago

Thank you very much for pointing out the problem and providing a solution!

I observe the same problem on 13.1-RELEASE-p5 with dehydrated 0.7.1 and zsh zsh 5.9 (amd64-portbld-freebsd13.1). You're workaround fixed it here as well.

Jehops commented 1 year ago

I just now ran a very simple test in a 13.1-RELEASE-p2 jail, and that system does indeed seem to be affected. My original 13.1 test must have been flawed.

Recipe:

  1. Run poudriere testport -i -j 13amd64 security/dehydrated to give a shell prompt in a pristine 13.1-RELEASE-p2 jail plus dehydrated and its dependencies installed.
  2. Run /usr/local/bin/dehydrated -c and the output is only # INFO: Using main config file /usr/local/etc/dehydrated/config.
  3. Make the one-line change to dehydrated so that it contains local is_wordsplit_disabled="$(unsetopt....
  4. Re-run the test in 2. and the output is now
    
    # INFO: Using main config file /usr/local/etc/dehydrated/config

To use dehydrated with this certificate authority you have to agree to their terms of service which you can find here: https://letsencrypt.org/documents/LE-SA-v1.3-September-21-2022.pdf

To accept these terms of service run "/usr/local/bin/dehydrated --register --accept-terms".

areilly commented 1 year ago

This happens on my FreeBSD 13.1-STABLE system with dehydrated 0.7.1 from ports too. The last previous successful run was November 4th, so something must have changed in the installed zsh in that time, I suppose? I'm also running zsh 5.9 (amd64-portbld-freebsd13.1) which is current in ports.

Hmm. The dehydrated-io-dehydrated-v0.7.1_GH0.tar.gz file in ports/distfiles is dated 5 November, so that is the likely source of change.

I can't figure out why the suggested fix works, which worries me a bit. It should not be necessary assign a local variable on the same line as it is declared.

The line-split in question was introduced in this change, apparently: https://github.com/dehydrated-io/dehydrated/commit/e963438c5a5d58ce3f997eef1e8e25f3cb4238d8 That change appears to have introduced quite a bit of unnecessary quoting, too.

The whole shwordsplit dance appears to be unnecessary in dehydrated, as it is turned on globally on line 11: [[ -n "${ZSH_VERSION:-}" ]] && set -o SH_WORD_SPLIT && set +o FUNCTION_ARGZERO && set -o NULL_GLOB && set -o noglob

I've found that just commenting out the lines involving is_wordsplit_disabled works fine too...