Files
ssh-access-tui/internal/audit/sessions.go
T
2026-07-22 14:14:53 +03:00

49 lines
1.3 KiB
Go

package audit
import (
"fmt"
"os/exec"
"strconv"
"strings"
)
// OnlineSession is one currently-connected sshd process for a managed user.
type OnlineSession struct {
User string
PID int
Elapsed string // e.g. "01:23:45" as reported by ps etime
}
// ListOnline reports users currently connected. Port-forwarding-only
// sessions never allocate a pty, so they are invisible to `who`/`loginctl`;
// what *is* always true is that an authenticated connection keeps a
// "sshd: <user> [priv]"-style privilege-separated process alive for as long
// as the session lasts, so we read that from `ps` instead.
func ListOnline(managedUsers map[string]bool) ([]OnlineSession, error) {
out, err := exec.Command("ps", "-eo", "user:32,pid,etime,args", "--no-headers").Output()
if err != nil {
return nil, fmt.Errorf("ps: %w", err)
}
var sessions []OnlineSession
for _, line := range strings.Split(string(out), "\n") {
fields := strings.Fields(line)
if len(fields) < 4 {
continue
}
user, pidStr, etime := fields[0], fields[1], fields[2]
args := strings.Join(fields[3:], " ")
if !strings.Contains(args, "sshd:") {
continue
}
if !managedUsers[user] {
continue
}
pid, err := strconv.Atoi(pidStr)
if err != nil {
continue
}
sessions = append(sessions, OnlineSession{User: user, PID: pid, Elapsed: etime})
}
return sessions, nil
}