diff --git a/src/auth/pam.go b/src/auth/pam.go index f817263..d759d3e 100644 --- a/src/auth/pam.go +++ b/src/auth/pam.go @@ -37,9 +37,11 @@ static struct pam_conv makePAMConv(void *data) { import "C" import ( "fmt" + "os" ouser "os/user" "runtime" "runtime/cgo" + "strings" "unsafe" ) @@ -169,7 +171,7 @@ func Validate(user, pass, service string) (*Credentials, error) { PrimaryGID: gid, AllGIDs: gids, HomeDir: u.HomeDir, - Shell: "/bin/sh", + Shell: shellFromPasswd(uid), pamHandle: pamh, pamData: cData, pamCB: h, @@ -211,3 +213,21 @@ func atou32(s string) uint32 { } 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" +} diff --git a/src/main.go b/src/main.go index 038697c..5b04fc8 100644 --- a/src/main.go +++ b/src/main.go @@ -165,12 +165,16 @@ func spawnSession(res *login.Result) error { session.SetSeatVars(res.Config.TTY) session.SetSessionVars(creds.UID) 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) if err != nil { return fmt.Errorf("spawn: %w", err) } + utmpx := auth.AddUtmpx(creds.Username, res.Config.TTY, uint32(sess.PID())) + defer utmpx.Close() + err = sess.Wait() if err != nil { log.Printf("session exited: %v", err) diff --git a/src/session/env.go b/src/session/env.go index b3a7a0b..3a085b5 100644 --- a/src/session/env.go +++ b/src/session/env.go @@ -57,6 +57,15 @@ func SetXDGCommonPaths(home string) { 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) { if _, ok := os.LookupEnv(k); !ok { os.Setenv(k, v) diff --git a/src/session/exec.go b/src/session/exec.go index 204b2ba..830ffb7 100644 --- a/src/session/exec.go +++ b/src/session/exec.go @@ -16,10 +16,12 @@ import ( ) type PostLoginEnv struct { - Kind string // "x11", "wayland", "tty" - Title string - XinitrcPath string - ScriptPath string + Kind string // "x11", "wayland", "tty" + Title string + XinitrcPath string + ScriptPath string + DesktopNames string // for XDG_CURRENT_DESKTOP (colon-separated) + SessionDesktop string // for XDG_SESSION_DESKTOP } type SpawnedEnv struct { diff --git a/src/session/scan.go b/src/session/scan.go index 7c207e2..4066dcb 100644 --- a/src/session/scan.go +++ b/src/session/scan.go @@ -13,10 +13,11 @@ import ( ) type DesktopEntry struct { - Name string - Exec string - Hidden bool - NoDisplay bool + Name string + Exec string + DesktopNames string + Hidden bool + NoDisplay bool } func parseDesktopEntry(path string) (*DesktopEntry, error) { @@ -51,6 +52,8 @@ func parseDesktopEntry(path string) (*DesktopEntry, error) { e.Name = v case "Exec": e.Exec = v + case "DesktopNames": + e.DesktopNames = v case "Hidden": e.Hidden = strings.EqualFold(v, "true") case "NoDisplay": @@ -97,15 +100,28 @@ func scanDesktopDir(dir, kind string, envs *[]PostLoginEnv) { if err != nil || de.Hidden || de.NoDisplay { continue } + desktopNames, sessionDesktop := splitDesktopNames(de.DesktopNames, e.Name()) *envs = append(*envs, PostLoginEnv{ - Kind: kind, - Title: de.Name, - XinitrcPath: de.Exec, - ScriptPath: de.Exec, + Kind: kind, + Title: de.Name, + XinitrcPath: 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) { entries, err := os.ReadDir(dir) if err != nil {