SSH Behind the Scene

What happens when you ssh to a remote machine? This blog will not analyze from a cryptographic way but from an engineering way. We will touch on different components of Linux and how they interact. This blog is a brief introduction. We sacrifice precision for the sake of clarity without compromising the core message. A Quick Tour systemd < root ├─sshd: /usr/sbin/sshd -D [listener] 0 of 10-100 startups < root │ └─sshd: username [priv] < root │ └─sshd: username@pts/0 < user │ └─-fish < user │ └─ other commands └─systemd --user < user ├─(sd-pam) └─other services A root process sshd listens on the configured port (usually 22). Upon connection, it forks a child. This child becomes a privileged monitor process, sshd: <username> [priv], to handle cleanup and audit logs. The monitor forks a net-child that handles network traffic, key exchange, and package parsing as a sandbox user (usually sshd). The net-child receives the key or password and passes it to the privileged root process via a pipe. The monitor runs the PAM stack (/etc/pam.d/sshd) as root, which handles auth, session setup and call pam_systemd.so. pam_systemd.so notifies systemd-logind via D-Bus that a new session is opening. systemd-logind maintains its own database in /run/systemd/sessions and checks if user@<uid>.service is running, If not, it asks PID 1 (system-level systemd) to start it. PID 1 forks a new process to run the service. Because user@.service has PAMName=systemd-user, this new service process initializes the PAM stack (/etc/pam.d/systemd-user), which gathers environment variables and limits. To keep the PAM session alive independent of the service payload, the service process creates a (sd-pam) helper. (sd-pam)’s only job is to wait for the service to die and then call pam_close_session using the parent death signal prctl(PR_SET_PDEATHSIG, SIGTERM). The service process sets its UID to the user and execs the systemd --user binary, passing the PAM-generated environment variables directly. (This explains why we need (sd-pam): after execing the binary, the process that knew how to run pam_close_session() is gone.) Back at step 4, after finishing pam_authenticate, net-child terminates. The sshd monitor calls pam_open_session to gather the environment like step 8 and forks a new child, sshd: <username>@pts/233. The child then sets its UID to the user and forks a new child that sets itself as a session leader using setsid and execs the user’s shell. The shell attaches its IO to the respective pts. This explains why we need the login shell to be a session leader because only a session leader can attach to pts When the user logs out, the ssh monitor detects via SIGCHLD. The monitor performs the final cleanup (recording logout time in wtmp, removing utmp entry, and tearing down the PTY). Note: There is a terminology overload on the word session. The POSIX session (kernel session) is used to manage all the processes belonging to a specific terminal. It can be set using setsid by the process itself. On the other hand, the PAM session in pam_open_session mainly concerns environment and policy management for the convenience of the admin. (Read the following section if you don’t understand.) ...

December 31, 2025 · 7 min