Skip to content

Commit

Permalink
More robust reading of sshd configuration (#2330)
Browse files Browse the repository at this point in the history
Use sshd -T instead of directly reading the configuration files
  • Loading branch information
kiekerjan committed Mar 23, 2024
1 parent 9b45046 commit 1a239c5
Show file tree
Hide file tree
Showing 3 changed files with 44 additions and 43 deletions.
15 changes: 6 additions & 9 deletions management/dns_update.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
import rtyaml
import dns.resolver

from utils import shell, load_env_vars_from_file, safe_domain_name, sort_domains
from utils import shell, load_env_vars_from_file, safe_domain_name, sort_domains, get_ssh_port
from ssl_certificates import get_ssl_certificates, check_certificate
import contextlib

Expand Down Expand Up @@ -448,14 +448,11 @@ def build_sshfp_records():
# if SSH has been configured to listen on a nonstandard port, we must
# specify that port to sshkeyscan.

port = 22
with open('/etc/ssh/sshd_config', encoding="utf-8") as f:
for line in f:
s = line.rstrip().split()
if len(s) == 2 and s[0] == 'Port':
with contextlib.suppress(ValueError):
port = int(s[1])
break
port = get_ssh_port()

# If nothing returned, SSH is probably not installed.
if not port:
return

keys = shell("check_output", ["ssh-keyscan", "-4", "-t", "rsa,dsa,ecdsa,ed25519", "-p", str(port), "localhost"])
keys = sorted(keys.split("\n"))
Expand Down
44 changes: 10 additions & 34 deletions management/status_checks.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
from ssl_certificates import get_ssl_certificates, get_domain_ssl_files, check_certificate
from mailconfig import get_mail_domains, get_mail_aliases

from utils import shell, sort_domains, load_env_vars_from_file, load_settings
from utils import shell, sort_domains, load_env_vars_from_file, load_settings, get_ssh_port, get_ssh_config_value

def get_services():
return [
Expand Down Expand Up @@ -65,24 +65,6 @@ def run_checks(rounded_values, env, output, pool, domains_to_check=None):
run_network_checks(env, output)
run_domain_checks(rounded_values, env, output, pool, domains_to_check=domains_to_check)

def get_ssh_port():
# Returns ssh port
try:
output = shell('check_output', ['sshd', '-T'])
except FileNotFoundError:
# sshd is not installed. That's ok.
return None

returnNext = False
for e in output.split():
if returnNext:
return int(e)
if e == "port":
returnNext = True

# Did not find port!
return None

def run_services_checks(env, output, pool):
# Check that system services are running.
all_running = True
Expand Down Expand Up @@ -206,21 +188,15 @@ def is_port_allowed(ufw, port):
return any(re.match(str(port) +"[/ \t].*", item) for item in ufw)

def check_ssh_password(env, output):
# Check that SSH login with password is disabled. The openssh-server
# package may not be installed so check that before trying to access
# the configuration file.
if not os.path.exists("/etc/ssh/sshd_config"):
return
with open("/etc/ssh/sshd_config", encoding="utf-8") as f:
sshd = f.read()
if re.search("\nPasswordAuthentication\\s+yes", sshd) \
or not re.search("\nPasswordAuthentication\\s+no", sshd):
output.print_error("""The SSH server on this machine permits password-based login. A more secure
way to log in is using a public key. Add your SSH public key to $HOME/.ssh/authorized_keys, check
that you can log in without a password, set the option 'PasswordAuthentication no' in
/etc/ssh/sshd_config, and then restart the openssh via 'sudo service ssh restart'.""")
else:
output.print_ok("SSH disallows password-based login.")
config_value = get_ssh_config_value("passwordauthentication")
if config_value:
if config_value == "no":
output.print_ok("SSH disallows password-based login.")
else:
output.print_error("""The SSH server on this machine permits password-based login. A more secure
way to log in is using a public key. Add your SSH public key to $HOME/.ssh/authorized_keys, check
that you can log in without a password, set the option 'PasswordAuthentication no' in
/etc/ssh/sshd_config, and then restart the openssh via 'sudo service ssh restart'.""")

def is_reboot_needed_due_to_package_installation():
return os.path.exists("/var/run/reboot-required")
Expand Down
28 changes: 28 additions & 0 deletions management/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -179,6 +179,34 @@ def wait_for_service(port, public, env, timeout):
return False
time.sleep(min(timeout/4, 1))

def get_ssh_port():
port_value = get_ssh_config_value("port")

if port_value:
return int(port_value)

return None

def get_ssh_config_value(parameter_name):
# Returns ssh configuration value for the provided parameter
try:
output = shell('check_output', ['sshd', '-T'])
except FileNotFoundError:
# sshd is not installed. That's ok.
return None
except subprocess.CalledProcessError:
# error while calling shell command
return None

for line in output.split("\n"):
if " " not in line: continue # there's a blank line at the end
key, values = line.split(" ", 1)
if key == parameter_name:
return values # space-delimited if there are multiple values

# Did not find the parameter!
return None

if __name__ == "__main__":
from web_update import get_web_domains
env = load_environment()
Expand Down

0 comments on commit 1a239c5

Please sign in to comment.