From 460d625f601d34aefd85498bc75e81e6128cbf17 Mon Sep 17 00:00:00 2001 From: Chris Wanstrath Date: Sat, 28 Feb 2026 22:38:39 -0800 Subject: [PATCH] Simplify SSH access via dedicated cli user --- scripts/nss/libnss_toes.c | 87 ----------------------------- scripts/setup-ssh.sh | 114 +++++++++++++------------------------- src/cli/index.ts | 4 +- 3 files changed, 42 insertions(+), 163 deletions(-) delete mode 100644 scripts/nss/libnss_toes.c diff --git a/scripts/nss/libnss_toes.c b/scripts/nss/libnss_toes.c deleted file mode 100644 index 1370214..0000000 --- a/scripts/nss/libnss_toes.c +++ /dev/null @@ -1,87 +0,0 @@ -/* - * libnss_toes - NSS module that resolves unknown usernames to a shared account. - * - * Any username not found in /etc/passwd gets mapped to a toes-cli entry - * with home=/home/toes-cli and shell=/usr/local/bin/toes. - * - * Build: - * gcc -shared -o libnss_toes.so.2 libnss_toes.c -fPIC - * - * Install: - * cp libnss_toes.so.2 /lib/ - * # Add "toes" to passwd line in /etc/nsswitch.conf - */ - -#include -#include -#include -#include - -#define GUEST_UID 3001 -#define GUEST_GID 3001 -#define GUEST_HOME "/home/toes-cli" -#define GUEST_SHELL "/usr/local/bin/toes" -#define GUEST_GECOS "Toes CLI" - -static const char *skip_users[] = { - "root", "toes", "toes-cli", "nobody", "daemon", "bin", "sys", "sync", - "games", "man", "lp", "mail", "news", "uucp", "proxy", - "www-data", "backup", "list", "irc", "gnats", "systemd-network", - "systemd-resolve", "messagebus", "sshd", "_apt", - NULL -}; - -static int should_skip(const char *name) { - for (const char **p = skip_users; *p; p++) { - if (strcmp(name, *p) == 0) return 1; - } - return 0; -} - -static enum nss_status fill_passwd(const char *name, struct passwd *pw, - char *buf, size_t buflen, int *errnop) { - size_t namelen = strlen(name) + 1; - size_t gecoslen = strlen(GUEST_GECOS) + 1; - size_t homelen = strlen(GUEST_HOME) + 1; - size_t shelllen = strlen(GUEST_SHELL) + 1; - size_t needed = namelen + gecoslen + homelen + shelllen + 1; /* +1 for pw_passwd "" */ - - if (buflen < needed) { - *errnop = ERANGE; - return NSS_STATUS_TRYAGAIN; - } - - char *ptr = buf; - - pw->pw_name = ptr; - memcpy(ptr, name, namelen); - ptr += namelen; - - pw->pw_passwd = ptr; - *ptr++ = '\0'; - - pw->pw_uid = GUEST_UID; - pw->pw_gid = GUEST_GID; - - pw->pw_gecos = ptr; - memcpy(ptr, GUEST_GECOS, gecoslen); - ptr += gecoslen; - - pw->pw_dir = ptr; - memcpy(ptr, GUEST_HOME, homelen); - ptr += homelen; - - pw->pw_shell = ptr; - memcpy(ptr, GUEST_SHELL, shelllen); - - return NSS_STATUS_SUCCESS; -} - -enum nss_status _nss_toes_getpwnam_r(const char *name, struct passwd *pw, - char *buf, size_t buflen, int *errnop) { - if (!name || !*name || should_skip(name)) { - return NSS_STATUS_NOTFOUND; - } - - return fill_passwd(name, pw, buf, buflen, errnop); -} diff --git a/scripts/setup-ssh.sh b/scripts/setup-ssh.sh index 89c2481..b22b85b 100755 --- a/scripts/setup-ssh.sh +++ b/scripts/setup-ssh.sh @@ -1,67 +1,50 @@ #!/bin/bash # -# setup-ssh.sh - Configure SSH so any user gets the toes CLI +# setup-ssh.sh - Configure SSH for the toes CLI user # # This script: -# 1. Compiles and installs the NSS module -# 2. Adds "toes" to nsswitch.conf passwd line -# 3. Configures PAM to accept any password (home network appliance) -# 4. Ensures PasswordAuthentication is enabled in sshd -# 5. Adds /usr/local/bin/toes to /etc/shells -# 6. Restarts sshd +# 1. Creates a `cli` system user with /usr/local/bin/toes as shell +# 2. Sets an empty password on `cli` for passwordless SSH +# 3. Adds a Match block in sshd_config to allow empty passwords for `cli` +# 4. Adds /usr/local/bin/toes to /etc/shells +# 5. Restarts sshd # # Run as root on the toes machine. +# Usage: ssh cli@toes.local set -euo pipefail -SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" - -echo "==> Setting up SSH auto-CLI for toes" - -# 1. Compile and install NSS module -echo " Compiling NSS module..." -gcc -shared -o /tmp/libnss_toes.so.2 "$SCRIPT_DIR/nss/libnss_toes.c" -fPIC -cp /tmp/libnss_toes.so.2 /lib/ -ldconfig -echo " Installed libnss_toes.so.2" - -# 2. Add toes to nsswitch.conf -if ! grep -q 'passwd:.*toes' /etc/nsswitch.conf; then - sed -i 's/^passwd:.*/& toes/' /etc/nsswitch.conf - echo " Added toes to nsswitch.conf" -else - echo " nsswitch.conf already configured" -fi - -# 3. Configure PAM - accept any password for SSH -if ! grep -q 'pam_permit.so.*# toes' /etc/pam.d/sshd; then - # Comment out existing auth and replace with pam_permit - sed -i '/^@include common-auth/s/^/# /' /etc/pam.d/sshd - sed -i '/^auth/s/^/# /' /etc/pam.d/sshd - # Add pam_permit after the commented lines - echo 'auth sufficient pam_permit.so # toes' >> /etc/pam.d/sshd - echo " Configured PAM for passwordless SSH" -else - echo " PAM already configured" -fi - -# 4. Ensure PasswordAuthentication yes in sshd_config -SSHD_CONFIG="/etc/ssh/sshd_config" -if grep -q '^PasswordAuthentication no' "$SSHD_CONFIG"; then - sed -i 's/^PasswordAuthentication no/PasswordAuthentication yes/' "$SSHD_CONFIG" - echo " Enabled PasswordAuthentication" -elif grep -q '^#PasswordAuthentication' "$SSHD_CONFIG"; then - sed -i 's/^#PasswordAuthentication.*/PasswordAuthentication yes/' "$SSHD_CONFIG" - echo " Enabled PasswordAuthentication" -elif ! grep -q '^PasswordAuthentication yes' "$SSHD_CONFIG"; then - echo 'PasswordAuthentication yes' >> "$SSHD_CONFIG" - echo " Added PasswordAuthentication yes" -else - echo " PasswordAuthentication already enabled" -fi - -# 5. Ensure /usr/local/bin/toes is in /etc/shells TOES_SHELL="/usr/local/bin/toes" +SSHD_CONFIG="/etc/ssh/sshd_config" + +echo "==> Setting up SSH CLI user for toes" + +# 1. Create cli system user +if ! id cli &>/dev/null; then + useradd --system --home-dir /home/cli --shell "$TOES_SHELL" --create-home cli + echo " Created cli user" +else + echo " cli user already exists" +fi + +# 2. Set empty password +passwd -d cli +echo " Set empty password on cli" + +# 3. Add Match block for cli user in sshd_config +if ! grep -q 'Match User cli' "$SSHD_CONFIG"; then + cat >> "$SSHD_CONFIG" <> /etc/shells echo " Added $TOES_SHELL to /etc/shells" @@ -69,31 +52,14 @@ else echo " $TOES_SHELL already in /etc/shells" fi -# Ensure the toes binary exists (symlink to bun entry point) +# Warn if toes binary doesn't exist yet if [ ! -f "$TOES_SHELL" ]; then echo " WARNING: $TOES_SHELL does not exist yet" echo " Create it with: ln -sf /path/to/toes/cli $TOES_SHELL" fi -# Create toes-cli system user for guest SSH sessions -if ! id toes-cli &>/dev/null; then - useradd --system --uid 3001 --home-dir /home/toes-cli --shell /usr/local/bin/toes --create-home toes-cli - echo " Created toes-cli user" -else - echo " toes-cli user already exists" -fi - -# Ensure /home/toes-cli exists for guest sessions -if [ ! -d /home/toes-cli ]; then - mkdir -p /home/toes-cli - chmod 755 /home/toes-cli - echo " Created /home/toes-cli" -fi - -# 6. Restart sshd +# 5. Restart sshd echo " Restarting sshd..." systemctl restart sshd || service ssh restart || true -echo "==> Done. Any SSH user will now get the toes CLI." -echo " SSH users are mapped to the toes-cli account (UID 3001)." -echo " toes@toes.local still gets a regular shell." +echo "==> Done. Connect with: ssh cli@toes.local" diff --git a/src/cli/index.ts b/src/cli/index.ts index c871de3..1a16599 100755 --- a/src/cli/index.ts +++ b/src/cli/index.ts @@ -1,11 +1,11 @@ #!/usr/bin/env bun import { program } from './setup' -const isSSH = !!process.env.SSH_CONNECTION +const isCliUser = process.env.USER === 'cli' const noArgs = process.argv.length <= 2 const isTTY = !!process.stdin.isTTY -if (isSSH && noArgs && isTTY) { +if (isCliUser && noArgs && isTTY) { const { shell } = await import('./shell') await shell() } else {