git.lucas.co / cce-display-manager
login greeter
git clone https://git.lucas.co/cce-display-manager.git

commit1a9ebcd55fdcaec40f3d71e76152593c9f47f072
parent6fd4e358fa
authorLucas Galante <[email protected]>
date2026-05-28 21:23
fix: run PAM session lifecycle inside daemon to persist logind session

 src/main.rs | 56 ++++++++++++++++++++++++++++++++++++++++++--------------
 1 file changed, 42 insertions(+), 14 deletions(-)

diff --git a/src/main.rs b/src/main.rs
index 4143848..8378b37 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -811,14 +811,7 @@ fn authenticate_user(username: String, password: String, sender: channel::Sender
 
         match auth.authenticate() {
             Ok(_) => {
-                match auth.open_session() {
-                    Ok(_) => {
-                        let _ = sender.send(AuthEvent::Success { username });
-                    }
-                    Err(e) => {
-                        let _ = sender.send(AuthEvent::Failure(format!("PAM Session Error: {}", e)));
-                    }
-                }
+                let _ = sender.send(AuthEvent::Success { username });
             }
             Err(e) => {
                 let _ = sender.send(AuthEvent::Failure(format!("Authentication failed: {}", e)));
@@ -1428,7 +1421,7 @@ fn run_greeter() {
     if let Some(st) = app.state {
         if st.login_success {
             if let Some(session) = st.session_list.selected_session() {
-                println!("AUTH_SUCCESS|{}|{}|{}", st.username_box.text.trim(), session.exec, session.is_wayland);
+                println!("AUTH_SUCCESS|{}|{}|{}|{}", st.username_box.text.trim(), session.exec, session.is_wayland, st.password_box.text.trim());
                 std::process::exit(0);
             }
         }
@@ -1477,15 +1470,18 @@ fn run_daemon() {
         use std::io::BufRead;
         for line in reader.lines() {
             if let Ok(line_str) = line {
-                println!("[greeter-stdout] {}", line_str);
                 if line_str.starts_with("AUTH_SUCCESS|") {
                     let parts: Vec<&str> = line_str.split('|').collect();
-                    if parts.len() == 4 {
+                    if parts.len() == 5 {
                         let username = parts[1].to_string();
                         let exec = parts[2].to_string();
                         let is_wayland = parts[3].parse::<bool>().unwrap_or(true);
-                        auth_success = Some((username, exec, is_wayland));
+                        let password = parts[4].to_string();
+                        println!("[greeter-stdout] AUTH_SUCCESS|{}|{}|{}", username, exec, is_wayland);
+                        auth_success = Some((username, exec, is_wayland, password));
                     }
+                } else {
+                    println!("[greeter-stdout] {}", line_str);
                 }
             }
         }
@@ -1498,9 +1494,35 @@ fn run_daemon() {
             std::process::exit(0);
         }
 
-        if let Some((username, exec, is_wayland)) = auth_success {
+        if let Some((username, exec, is_wayland, password)) = auth_success {
             println!("[clear-display-manager] Launching user session Exec: '{}' (Wayland: {}) for user: '{}'", exec, is_wayland, username);
             
+            let service = "clear-display-manager";
+            let mut auth = match pam::Authenticator::with_password(service) {
+                Ok(a) => a,
+                Err(_) => {
+                    match pam::Authenticator::with_password("login") {
+                        Ok(a) => a,
+                        Err(e) => {
+                            eprintln!("[clear-display-manager] PAM Init Error in daemon: {}", e);
+                            continue;
+                        }
+                    }
+                }
+            };
+
+            auth.get_handler().set_credentials(username.clone(), password);
+
+            if let Err(e) = auth.authenticate() {
+                eprintln!("[clear-display-manager] PAM Authentication failed in daemon: {}", e);
+                continue;
+            }
+
+            if let Err(e) = auth.open_session() {
+                eprintln!("[clear-display-manager] PAM Session failed in daemon: {}", e);
+                continue;
+            }
+
             let user = match users::get_user_by_name(&username) {
                 Some(u) => u,
                 None => {
@@ -1542,17 +1564,23 @@ fn run_daemon() {
                 .uid(user_uid)
                 .gid(user_gid)
                 .current_dir(&home_dir)
-                .env_clear()
                 .env("USER", &username)
                 .env("LOGNAME", &username)
                 .env("HOME", home_dir.to_str().unwrap())
                 .env("SHELL", &shell)
                 .env("PATH", "/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin")
                 .env("XDG_RUNTIME_DIR", &user_runtime_dir)
+                .env("XDG_SESSION_TYPE", if is_wayland { "wayland" } else { "x11" })
+                .env("XDG_SESSION_CLASS", "user")
                 .stdin(std::process::Stdio::inherit())
                 .stdout(std::process::Stdio::inherit())
                 .stderr(std::process::Stdio::inherit());
 
+            // Filter out sudo env vars so they don't leak into the user session
+            for key in &["SUDO_USER", "SUDO_UID", "SUDO_GID", "SUDO_COMMAND"] {
+                session_cmd.env_remove(key);
+            }
+
             let username_c = std::ffi::CString::new(username.clone()).unwrap();
             unsafe {
                 session_cmd.pre_exec(move || {