diff --git a/Cargo.lock b/Cargo.lock index a9092e0..f5d190d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -575,7 +575,7 @@ dependencies = [ [[package]] name = "moongreet" -version = "0.10.1" +version = "0.10.2" dependencies = [ "gdk-pixbuf", "gdk4", diff --git a/Cargo.toml b/Cargo.toml index c1db339..1f96a2a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "moongreet" -version = "0.10.1" +version = "0.10.2" edition = "2024" description = "A greetd greeter for Wayland with GTK4 and Layer Shell" license = "MIT" diff --git a/src/users.rs b/src/users.rs index 56f4c93..3736d13 100644 --- a/src/users.rs +++ b/src/users.rs @@ -11,13 +11,12 @@ const DEFAULT_PASSWD: &str = "/etc/passwd"; const DEFAULT_ACCOUNTSSERVICE_DIR: &str = "/var/lib/AccountsService/icons"; const GRESOURCE_PREFIX: &str = "/dev/moonarch/moongreet"; -/// Shells that indicate a user cannot log in. -const NOLOGIN_SHELLS: &[&str] = &[ - "/usr/sbin/nologin", - "/sbin/nologin", - "/bin/false", - "/usr/bin/nologin", -]; +/// Shell file names that indicate a user cannot log in. +/// +/// Matched on the file name rather than the full path: distributions place +/// these binaries in different locations, and on NixOS the path is +/// /run/current-system/sw/bin/nologin. +const NOLOGIN_SHELLS: &[&str] = &["nologin", "false"]; /// Represents a system user suitable for login. #[derive(Debug, Clone)] @@ -73,7 +72,11 @@ pub fn get_users(passwd_path: Option<&Path>) -> Vec { if !(MIN_UID..=MAX_UID).contains(&uid) { continue; } - if NOLOGIN_SHELLS.contains(&shell) { + let shell_name = Path::new(shell) + .file_name() + .and_then(|n| n.to_str()) + .unwrap_or(shell); + if NOLOGIN_SHELLS.contains(&shell_name) { continue; } // Path traversal prevention @@ -194,6 +197,31 @@ mod tests { assert!(users.is_empty()); } + #[test] + fn skip_nologin_users_at_any_path() { + let dir = tempfile::tempdir().unwrap(); + let path = make_passwd( + dir.path(), + "nixbld1:x:30001:30000:Nix build user 1:/var/empty:/run/current-system/sw/bin/nologin\n\ + svc:x:1001:1001::/var/empty:/nix/store/abc123-shadow-4.17.4/bin/nologin\n\ + disabled:x:1002:1002::/home/disabled:/run/current-system/sw/bin/false\n", + ); + let users = get_users(Some(&path)); + assert!(users.is_empty()); + } + + #[test] + fn keep_login_shell_with_similar_name() { + let dir = tempfile::tempdir().unwrap(); + let path = make_passwd( + dir.path(), + "alice:x:1000:1000:Alice:/home/alice:/run/current-system/sw/bin/zsh\n", + ); + let users = get_users(Some(&path)); + assert_eq!(users.len(), 1); + assert_eq!(users[0].username, "alice"); + } + #[test] fn skip_users_with_slash_in_name() { let dir = tempfile::tempdir().unwrap();