session: parse DesktopNames for XDG_CURRENT_DESKTOP, wire utmpx, fix shell

- .desktop files now parse DesktopNames: first ;-entry → XDG_SESSION_DESKTOP,
  full list with : separators → XDG_CURRENT_DESKTOP
- AddUtmpx/Close wired into spawnSession (logins appear in who/w/last)
- Credentials.Shell reads from /etc/passwd instead of hardcoded /bin/sh
- Added SetDesktopVars to env.go
This commit is contained in:
2026-07-19 01:54:22 +05:30
parent 5eae08c7ba
commit a911adf284
5 changed files with 64 additions and 13 deletions

View File

@@ -37,9 +37,11 @@ static struct pam_conv makePAMConv(void *data) {
import "C" import "C"
import ( import (
"fmt" "fmt"
"os"
ouser "os/user" ouser "os/user"
"runtime" "runtime"
"runtime/cgo" "runtime/cgo"
"strings"
"unsafe" "unsafe"
) )
@@ -169,7 +171,7 @@ func Validate(user, pass, service string) (*Credentials, error) {
PrimaryGID: gid, PrimaryGID: gid,
AllGIDs: gids, AllGIDs: gids,
HomeDir: u.HomeDir, HomeDir: u.HomeDir,
Shell: "/bin/sh", Shell: shellFromPasswd(uid),
pamHandle: pamh, pamHandle: pamh,
pamData: cData, pamData: cData,
pamCB: h, pamCB: h,
@@ -211,3 +213,21 @@ func atou32(s string) uint32 {
} }
return n return n
} }
func shellFromPasswd(uid uint32) string {
data, err := os.ReadFile("/etc/passwd")
if err != nil {
return "/bin/sh"
}
uidStr := fmt.Sprint(uid)
for _, line := range strings.Split(string(data), "\n") {
parts := strings.Split(line, ":")
if len(parts) >= 7 && parts[2] == uidStr && parts[6] != "" {
sh := parts[6]
if sh != "/sbin/nologin" && sh != "/usr/sbin/nologin" && sh != "/bin/false" {
return sh
}
}
}
return "/bin/sh"
}

View File

@@ -165,12 +165,16 @@ func spawnSession(res *login.Result) error {
session.SetSeatVars(res.Config.TTY) session.SetSeatVars(res.Config.TTY)
session.SetSessionVars(creds.UID) session.SetSessionVars(creds.UID)
session.SetXDGCommonPaths(creds.HomeDir) session.SetXDGCommonPaths(creds.HomeDir)
session.SetDesktopVars(res.Env.DesktopNames, res.Env.SessionDesktop)
sess, err := session.Spawn(&res.Env, creds.UID, creds.PrimaryGID, creds.AllGIDs, &res.Config) sess, err := session.Spawn(&res.Env, creds.UID, creds.PrimaryGID, creds.AllGIDs, &res.Config)
if err != nil { if err != nil {
return fmt.Errorf("spawn: %w", err) return fmt.Errorf("spawn: %w", err)
} }
utmpx := auth.AddUtmpx(creds.Username, res.Config.TTY, uint32(sess.PID()))
defer utmpx.Close()
err = sess.Wait() err = sess.Wait()
if err != nil { if err != nil {
log.Printf("session exited: %v", err) log.Printf("session exited: %v", err)

View File

@@ -57,6 +57,15 @@ func SetXDGCommonPaths(home string) {
setOrOwn("XDG_CONFIG_DIRS", "/etc/xdg") setOrOwn("XDG_CONFIG_DIRS", "/etc/xdg")
} }
func SetDesktopVars(currentDesktop, sessionDesktop string) {
if currentDesktop != "" {
setOrOwn("XDG_CURRENT_DESKTOP", currentDesktop)
}
if sessionDesktop != "" {
setOrOwn("XDG_SESSION_DESKTOP", sessionDesktop)
}
}
func setOrOwn(k, v string) { func setOrOwn(k, v string) {
if _, ok := os.LookupEnv(k); !ok { if _, ok := os.LookupEnv(k); !ok {
os.Setenv(k, v) os.Setenv(k, v)

View File

@@ -20,6 +20,8 @@ type PostLoginEnv struct {
Title string Title string
XinitrcPath string XinitrcPath string
ScriptPath string ScriptPath string
DesktopNames string // for XDG_CURRENT_DESKTOP (colon-separated)
SessionDesktop string // for XDG_SESSION_DESKTOP
} }
type SpawnedEnv struct { type SpawnedEnv struct {

View File

@@ -15,6 +15,7 @@ import (
type DesktopEntry struct { type DesktopEntry struct {
Name string Name string
Exec string Exec string
DesktopNames string
Hidden bool Hidden bool
NoDisplay bool NoDisplay bool
} }
@@ -51,6 +52,8 @@ func parseDesktopEntry(path string) (*DesktopEntry, error) {
e.Name = v e.Name = v
case "Exec": case "Exec":
e.Exec = v e.Exec = v
case "DesktopNames":
e.DesktopNames = v
case "Hidden": case "Hidden":
e.Hidden = strings.EqualFold(v, "true") e.Hidden = strings.EqualFold(v, "true")
case "NoDisplay": case "NoDisplay":
@@ -97,15 +100,28 @@ func scanDesktopDir(dir, kind string, envs *[]PostLoginEnv) {
if err != nil || de.Hidden || de.NoDisplay { if err != nil || de.Hidden || de.NoDisplay {
continue continue
} }
desktopNames, sessionDesktop := splitDesktopNames(de.DesktopNames, e.Name())
*envs = append(*envs, PostLoginEnv{ *envs = append(*envs, PostLoginEnv{
Kind: kind, Kind: kind,
Title: de.Name, Title: de.Name,
XinitrcPath: de.Exec, XinitrcPath: de.Exec,
ScriptPath: de.Exec, ScriptPath: de.Exec,
DesktopNames: desktopNames,
SessionDesktop: sessionDesktop,
}) })
} }
} }
func splitDesktopNames(raw, fallback string) (currentDesktop, sessionDesktop string) {
if raw == "" {
return fallback, fallback
}
parts := strings.SplitN(raw, ";", 2)
sessionDesktop = strings.TrimSpace(parts[0])
currentDesktop = strings.ReplaceAll(raw, ";", ":")
return
}
func scanScriptDir(dir, kind string, envs *[]PostLoginEnv) { func scanScriptDir(dir, kind string, envs *[]PostLoginEnv) {
entries, err := os.ReadDir(dir) entries, err := os.ReadDir(dir)
if err != nil { if err != nil {