From ed5169b94c9b2596a3c4fef3c9fe6fad3ccbc09d Mon Sep 17 00:00:00 2001 From: Xiaofeng Meng Date: Tue, 24 Jun 2025 09:26:15 +0200 Subject: [PATCH] sshmngr: Fix session detection for OpenSSH backend The `sshmngr` service failed to list active sessions with the `sshd` (OpenSSH) backend because the session detection logic could not handle the process structure of modern OpenSSH, which uses an intermediate process for new connections. This commit resolves the issue by: - Improving process lookup to check for grandparent PIDs, correctly identifying the session process. - Querying the correct intermediate process for network connection details. parse netstat output. The new logic is encapsulated in a `get_network_info` function within the `openssh` backend script to maintain compatibility with the `dropbear` backend, which uses a simpler implementation of the same function. --- sshmngr/files/common/usr/libexec/rpcd/sshmngr | 27 +++++++------- .../dropbear_backend/lib/sshmngr/backend.sh | 23 +++++++++++- .../openssh_backend/lib/sshmngr/backend.sh | 36 +++++++++++++++++++ 3 files changed, 70 insertions(+), 16 deletions(-) diff --git a/sshmngr/files/common/usr/libexec/rpcd/sshmngr b/sshmngr/files/common/usr/libexec/rpcd/sshmngr index 0f0e89014..b84845bf6 100755 --- a/sshmngr/files/common/usr/libexec/rpcd/sshmngr +++ b/sshmngr/files/common/usr/libexec/rpcd/sshmngr @@ -82,22 +82,15 @@ case "$1" in # if pid equals server pid then skip [ "$session_pid" -eq "$server_pid" ] && continue - # get this session's ppid - session_ppid="$(grep PPid /proc/$session_pid/status | awk '{print $2}')" - - # if session's parent is this server - if [ "$session_ppid" -eq "$server_pid" ]; then - session="$(netstat -ntp | grep $session_pid/ | awk '{print $5,$7}' | cut -d'/' -f 1)" - - # return session IP, Port, PID - ip=$(echo "$session" | cut -d ':' -f 1) - port=$(echo "$session" | cut -d ':' -f 2 | cut -d ' ' -f 1) - pid=$(echo "$session" | cut -d ':' -f 2 | cut -d ' ' -f 2) + network_info="$(get_network_info "$session_pid" "$server_pid")" + if [ $? -eq 0 ]; then + ip=$(echo "$network_info" | cut -d' ' -f1) + port=$(echo "$network_info" | cut -d' ' -f2) json_add_object json_add_string "ip" "$ip" json_add_string "port" "$port" - json_add_string "pid" "$pid" + json_add_string "pid" "$session_pid" json_close_object fi done @@ -142,10 +135,14 @@ case "$1" in [ "$session_pid" -eq "$server_pid" ] && continue # get this session's ppid - session_ppid="$(grep PPid /proc/$session_pid/status | awk '{print $2}')" + session_ppid="$(grep PPid /proc/$session_pid/status 2>/dev/null | awk '{print $2}')" + [ -z "$session_ppid" ] && continue - # if session's parent is this server - if [ "$session_ppid" -eq "$server_pid" ]; then + # get the parent of the parent (the grandparent) + grandparent_pid="$(grep PPid /proc/$session_ppid/status 2>/dev/null | awk '{print $2}')" + + # if session's parent or grandparent is this server + if [ "$session_ppid" -eq "$server_pid" ] || { [ -n "$grandparent_pid" ] && [ "$grandparent_pid" -eq "$server_pid" ]; }; then kill -15 "$session_pid" fi done diff --git a/sshmngr/files/dropbear_backend/lib/sshmngr/backend.sh b/sshmngr/files/dropbear_backend/lib/sshmngr/backend.sh index dd97998df..8083f5cfb 100755 --- a/sshmngr/files/dropbear_backend/lib/sshmngr/backend.sh +++ b/sshmngr/files/dropbear_backend/lib/sshmngr/backend.sh @@ -17,5 +17,26 @@ get_session_pids() { local PidFile="$1" - echo "$(ps -w | grep $PidFile | grep -v grep | awk '{print $1}')" + echo "$(ps -w | grep "$PidFile" | grep -v grep | awk '{print $1}')" +} + +get_network_info() +{ + local session_pid="$1" + local server_pid="$2" + + # get this session's ppid + session_ppid="$(grep PPid /proc/$session_pid/status | awk '{print $2}')" + + # if session's parent is this server + if [ "$session_ppid" -eq "$server_pid" ]; then + session="$(netstat -ntp | grep "$session_pid/" | awk '{print $5,$7}' | cut -d'/' -f 1)" + if [ -n "$session" ]; then + ip=$(echo "$session" | cut -d ':' -f 1) + port=$(echo "$session" | cut -d ':' -f 2 | cut -d ' ' -f 1) + echo "$ip $port" + return 0 + fi + fi + return 1 } diff --git a/sshmngr/files/openssh_backend/lib/sshmngr/backend.sh b/sshmngr/files/openssh_backend/lib/sshmngr/backend.sh index 6158d3aa6..abfad6400 100755 --- a/sshmngr/files/openssh_backend/lib/sshmngr/backend.sh +++ b/sshmngr/files/openssh_backend/lib/sshmngr/backend.sh @@ -17,3 +17,39 @@ get_session_pids() { echo "$(ps -w | grep sshd | grep pts | awk '{print $1}')" } + +get_network_info() +{ + local session_pid="$1" + local server_pid="$2" + local session_info="" + local ip="" + local port="" + + # get this session's ppid + session_ppid="$(grep PPid /proc/$session_pid/status 2>/dev/null | awk '{print $2}')" + [ -z "$session_ppid" ] && return 1 + + # get the parent of the parent (the grandparent) + grandparent_pid="$(grep PPid /proc/$session_ppid/status 2>/dev/null | awk '{print $2}')" + + # if session's parent, or grandparent, is this server + if [ "$session_ppid" -eq "$server_pid" ] || { [ -n "$grandparent_pid" ] && [ "$grandparent_pid" -eq "$server_pid" ]; }; then + # The connection is usually handled by the parent process for openssh + session_info="$(netstat -ntp 2>/dev/null | awk -v pid="$session_ppid" '$7 ~ "^"pid"/" {print $5}')" + + # If not found on parent, check the child process itself (less common for openssh) + if [ -z "$session_info" ]; then + session_info="$(netstat -ntp 2>/dev/null | awk -v pid="$session_pid" '$7 ~ "^"pid"/" {print $5}')" + fi + + if [ -n "$session_info" ]; then + ip=$(echo "$session_info" | cut -d ':' -f 1) + port=$(echo "$session_info" | cut -d ':' -f 2) + echo "$ip $port" + return 0 + fi + fi + + return 1 +}