diff --git a/scripts/setup/machine-setup/lib/ssh.sh b/scripts/setup/machine-setup/lib/ssh.sh index 6b72706a..b38f1728 100644 --- a/scripts/setup/machine-setup/lib/ssh.sh +++ b/scripts/setup/machine-setup/lib/ssh.sh @@ -59,12 +59,35 @@ authorized_key_count() { has_authorized_key() { (($(authorized_key_count) > 0)); } -# Everything about ~/.ssh that has to be true for sshd to use it at all. sshd -# ignores an authorized_keys file that is group- or world-writable, and does so -# silently from the client's point of view — the login just fails. +# Everything that has to be true for sshd to use ~/.ssh at all. sshd's StrictModes +# (on by default, and nothing here turns it off) checks the HOME DIRECTORY too, not +# just .ssh — this used to check only .ssh, which is the shape of bug that is hardest +# to notice: an account whose home came from somewhere other than THIS script's own +# adduser call (cloud-init, a prior useradd, LDAP, or simply an account that already +# existed) can have a group- or world-writable home directory, and sshd refuses +# authorized_keys under it silently. The .ssh directory and the key both look +# completely correct — because they are — and nothing here used to say why the +# login still failed. fix_ssh_permissions() { - local dir + local dir home mode dir="$(user_ssh_dir)" + home="$USER_HOME" + + if [[ -d "$home" ]]; then + # GNU stat's -c, tried first since this step only ever runs on Linux (MACOS_SKIP) + # — with a BSD fallback anyway rather than a call that silently returns nothing on + # whatever this is next tested against, the same trap officer-setup's layout.sh + # file_owner() hit for the same reason. + mode="$(stat -c %a "$home" 2>/dev/null || stat -f %Lp "$home" 2>/dev/null)" + # 0022 is the group-write and other-write bits together. Cleared rather than + # forced to a fixed mode — 0755 vs 0750 is a real choice some setups make on + # purpose, and this only removes the bits sshd actually refuses to see. + if [[ -n "$mode" ]] && ((8#$mode & 0022)); then + chmod go-w "$home" + warn "${home} was group/world-writable (${mode}) — sshd's StrictModes refuses authorized_keys under a writable home regardless of .ssh's own permissions; cleared" + fi + fi + [[ -d "$dir" ]] || install -d -m 0700 -o "$USERNAME" -g "$(user_group)" "$dir" chmod 700 "$dir" [[ -f "$dir/authorized_keys" ]] && chmod 600 "$dir/authorized_keys"