4.2 KiB
to-do: rewrite & convert to html for docs pages
SSH
MontaukOS ships an SSH-2 server, sshd, that gives a remote client a shell on
the machine. It speaks enough of the protocol to interoperate with stock
OpenSSH clients:
ssh dan@montauk-box interactive shell
ssh dan@montauk-box 'ls 0:/' run one command
Remote access is off by default. Turn it on from Settings > SSH Server,
which flips services.ssh.enabled in 0:/config/init.toml; init starts the
daemon on the next boot.
Two gates stand in front of a login: the account must exist in the MontaukOS
user database with a valid password, and it must be listed in the [allow]
table of 0:/config/ssh.toml. A user absent from that table is refused even
with the right password. The Settings applet maintains the table; sshd never
writes it.
Layout
programs/src/sshd/
main.cpp transport framing, key exchange, auth, session/channel loop
crypto.hpp host key storage, DH group 14 arithmetic, cipher/MAC wrappers
programs/src/sshserver/
main.cpp Settings applet: enable the service, edit the allow table
programs/include/montauk/ssh.h
shared policy helpers used by both
The crypto primitives (SHA-256, HMAC, AES-CTR, RSA signing, the DRBG) come from
BearSSL. The modular exponentiation for Diffie-Hellman is in crypto.hpp
because BearSSL exposes no public bignum API.
What it implements
| Key exchange | diffie-hellman-group14-sha256 |
| Host key | rsa-sha2-256, 2048-bit, generated on first start |
| Cipher | aes128-ctr |
| MAC | hmac-sha2-256 |
| Compression | none |
| Auth | password only |
Client-initiated rekeying works, so long sessions survive OpenSSH's 1 GiB / one-hour rekey threshold. Channel windows are tracked in both directions, so sessions that move more than a window's worth of data keep flowing.
What it does not
No public key authentication, no port or X11 forwarding, no SFTP or SCP. One
session channel per connection, and connections are served one at a time --
there is no fork, so a second client waits for the first to finish. A
pre-authentication timeout keeps an idle peer from holding the daemon shut.
exec requests are run by typing the command into an interactive shell rather
than executing it directly, so the prompt and the echoed command come back
mixed into the output. This is why scp and friends will not work as-is.
The host key
Generated on first start and written to 0:/config/ssh_hostkey.toml, separate
from the policy file so the unprivileged Settings applet -- which rewrites
ssh.toml whenever the allow table changes -- never round-trips private key
material.
That separation is hygiene, not protection: the filesystem has no permission
model, so any local process can read the host key. Closing that hole needs
FS-level access control, at which point the key file should be restricted to
the account sshd runs as. A key found in an older ssh.toml is migrated to
the new file on first start so the host key does not change under existing
clients.
Debugging
sshd calls montauk::print, which reaches the boot console only. It has no
usable diagnostics once the desktop is up, pending the unified syslog.
Worth understanding, because it catches out anything written as a daemon:
montauk::print is SYS_PRINT, which writes the kernel terminal, not the
kernel log. Only in-kernel KernelLogStream writes raise g_kernelLogDepth,
and only those append to the ring buffer SYS_LOG reads -- so daemon output
never shows up in klog. On top of that, Sys_Print returns early once
g_suppressKernelLog is set, which the desktop does at startup, so the output is
discarded outright from then on. init spawns services with spawn rather than
spawn_redir, so there is no stream to capture either.
Until there is somewhere for it to go, debugging a handshake means watching the boot console, or temporarily pointing the print calls at a file.
Failures print a numeric code -- key exchange failed (N), authentication failed (N) -- where N identifies the step; see the kex_error assignments in
main.cpp. Running the client with ssh -vvv and lining its trace up against
those codes is usually the fastest way to find where a handshake diverged.